forked from mirrors/gecko-dev
		
	 b2e21ec958
			
		
	
	
		b2e21ec958
		
	
	
	
	
		
			
			These method names and ordering have gotten out of sync because of the recent churn. Differential Revision: https://phabricator.services.mozilla.com/D3288 --HG-- extra : rebase_source : 42bceaeb66a0df4808981b8c9cb0ed70b23f5a30 extra : histedit_source : 228024efe8de4e149f7e7ca66a2bb078bba820ce
		
			
				
	
	
		
			291 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			291 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* 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/. */
 | |
| 
 | |
| #include "PaintThread.h"
 | |
| 
 | |
| #include <algorithm>
 | |
| 
 | |
| #include "base/task.h"
 | |
| #include "gfxPlatform.h"
 | |
| #include "gfxPrefs.h"
 | |
| #include "GeckoProfiler.h"
 | |
| #include "mozilla/layers/CompositorBridgeChild.h"
 | |
| #include "mozilla/layers/ShadowLayers.h"
 | |
| #include "mozilla/layers/SyncObject.h"
 | |
| #include "mozilla/gfx/2D.h"
 | |
| #include "mozilla/Preferences.h"
 | |
| #include "mozilla/SharedThreadPool.h"
 | |
| #include "mozilla/SyncRunnable.h"
 | |
| #include "nsIPropertyBag2.h"
 | |
| #include "nsServiceManagerUtils.h"
 | |
| #include "prsystem.h"
 | |
| 
 | |
| // Uncomment the following line to dispatch sync runnables when
 | |
| // painting so that rasterization happens synchronously from
 | |
| // the perspective of the main thread
 | |
| // #define OMTP_FORCE_SYNC
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace layers {
 | |
| 
 | |
| using namespace gfx;
 | |
| 
 | |
| void
 | |
| PaintTask::DropTextureClients()
 | |
| {
 | |
|   mClients.Clear();
 | |
| }
 | |
| 
 | |
| StaticAutoPtr<PaintThread> PaintThread::sSingleton;
 | |
| StaticRefPtr<nsIThread> PaintThread::sThread;
 | |
| PlatformThreadId PaintThread::sThreadId;
 | |
| 
 | |
| PaintThread::PaintThread()
 | |
| {
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::Release()
 | |
| {
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::AddRef()
 | |
| {
 | |
| }
 | |
| 
 | |
| /* static */ int32_t
 | |
| PaintThread::CalculatePaintWorkerCount()
 | |
| {
 | |
|   int32_t cpuCores = PR_GetNumberOfProcessors();
 | |
|   int32_t workerCount = gfxPrefs::LayersOMTPPaintWorkers();
 | |
| 
 | |
|   // If not manually specified, default to (cpuCores * 3) / 4, and clamp
 | |
|   // between 1 and 4. If a user wants more, they can manually specify it
 | |
|   if (workerCount < 1) {
 | |
|     workerCount = std::min(std::max((cpuCores * 3) / 4, 1), 4);
 | |
|   }
 | |
| 
 | |
|   return workerCount;
 | |
| }
 | |
| 
 | |
| /* static */ void
 | |
| PaintThread::Start()
 | |
| {
 | |
|   PaintThread::sSingleton = new PaintThread();
 | |
| 
 | |
|   if (!PaintThread::sSingleton->Init()) {
 | |
|     gfxCriticalNote << "Unable to start paint thread";
 | |
|     PaintThread::sSingleton = nullptr;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool
 | |
| PaintThread::Init()
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   RefPtr<nsIThread> thread;
 | |
|   nsresult rv = NS_NewNamedThread("PaintThread", getter_AddRefs(thread));
 | |
|   if (NS_FAILED(rv)) {
 | |
|     return false;
 | |
|   }
 | |
|   sThread = thread;
 | |
| 
 | |
|   // Only create paint workers for tiling if we are using tiling or could
 | |
|   // expect to dynamically switch to tiling in the future
 | |
|   if (gfxPlatform::GetPlatform()->UsesTiling()) {
 | |
|     InitPaintWorkers();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIRunnable> paintInitTask =
 | |
|     NewRunnableMethod("PaintThread::InitOnPaintThread",
 | |
|                       this, &PaintThread::InitOnPaintThread);
 | |
|   SyncRunnable::DispatchToThread(sThread, paintInitTask);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::InitOnPaintThread()
 | |
| {
 | |
|   MOZ_ASSERT(!NS_IsMainThread());
 | |
|   sThreadId = PlatformThread::CurrentId();
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::InitPaintWorkers()
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
|   int32_t count = PaintThread::CalculatePaintWorkerCount();
 | |
|   if (count != 1) {
 | |
|     mPaintWorkers = SharedThreadPool::Get(NS_LITERAL_CSTRING("PaintWorker"), count);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| DestroyPaintThread(UniquePtr<PaintThread>&& pt)
 | |
| {
 | |
|   MOZ_ASSERT(PaintThread::IsOnPaintThread());
 | |
|   pt->ShutdownOnPaintThread();
 | |
| }
 | |
| 
 | |
| /* static */ void
 | |
| PaintThread::Shutdown()
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   UniquePtr<PaintThread> pt(sSingleton.forget());
 | |
|   if (!pt) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   sThread->Dispatch(NewRunnableFunction("DestroyPaintThreadRunnable",
 | |
|                                         DestroyPaintThread,
 | |
|                                         std::move(pt)));
 | |
|   sThread->Shutdown();
 | |
|   sThread = nullptr;
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::ShutdownOnPaintThread()
 | |
| {
 | |
|   MOZ_ASSERT(IsOnPaintThread());
 | |
| }
 | |
| 
 | |
| /* static */ PaintThread*
 | |
| PaintThread::Get()
 | |
| {
 | |
|   return PaintThread::sSingleton.get();
 | |
| }
 | |
| 
 | |
| /* static */ bool
 | |
| PaintThread::IsOnPaintThread()
 | |
| {
 | |
|   return sThreadId == PlatformThread::CurrentId();
 | |
| }
 | |
| 
 | |
| bool
 | |
| PaintThread::IsOnPaintWorkerThread()
 | |
| {
 | |
|   return (mPaintWorkers && mPaintWorkers->IsOnCurrentThread()) ||
 | |
|     (sThreadId == PlatformThread::CurrentId());
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::Dispatch(RefPtr<Runnable>& aRunnable)
 | |
| {
 | |
| #ifndef OMTP_FORCE_SYNC
 | |
|   sThread->Dispatch(aRunnable.forget());
 | |
| #else
 | |
|   SyncRunnable::DispatchToThread(sThread, aRunnable);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::UpdateRenderMode()
 | |
| {
 | |
|   if (!!mPaintWorkers != gfxPlatform::GetPlatform()->UsesTiling()) {
 | |
|     if (mPaintWorkers) {
 | |
|       mPaintWorkers = nullptr;
 | |
|     } else {
 | |
|       InitPaintWorkers();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::QueuePaintTask(PaintTask* aTask)
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
|   MOZ_ASSERT(aTask);
 | |
| 
 | |
|   if (gfxPrefs::LayersOMTPDumpCapture() && aTask->mCapture) {
 | |
|     aTask->mCapture->Dump();
 | |
|   }
 | |
| 
 | |
|   RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
 | |
|   RefPtr<PaintTask> state(aTask);
 | |
| 
 | |
|   cbc->NotifyBeginAsyncPaint(state);
 | |
| 
 | |
|   RefPtr<PaintThread> self = this;
 | |
|   RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncPaintTask",
 | |
|     [self, cbc, state]() -> void
 | |
|   {
 | |
|     self->AsyncPaintTask(cbc, state);
 | |
|   });
 | |
| 
 | |
|   nsIEventTarget* paintThread = mPaintWorkers ?
 | |
|     static_cast<nsIEventTarget*>(mPaintWorkers.get()) :
 | |
|     static_cast<nsIEventTarget*>(sThread.get());
 | |
| 
 | |
| #ifndef OMTP_FORCE_SYNC
 | |
|   paintThread->Dispatch(task.forget());
 | |
| #else
 | |
|   SyncRunnable::DispatchToThread(paintThread, task);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::AsyncPaintTask(CompositorBridgeChild* aBridge,
 | |
|                             PaintTask* aTask)
 | |
| {
 | |
|   AUTO_PROFILER_LABEL("PaintThread::AsyncPaintTask", GRAPHICS);
 | |
|   
 | |
|   MOZ_ASSERT(IsOnPaintWorkerThread());
 | |
|   MOZ_ASSERT(aTask);
 | |
| 
 | |
|   gfx::DrawTargetCapture* capture = aTask->mCapture;
 | |
|   gfx::DrawTarget* target = aTask->mTarget;
 | |
| 
 | |
|   target->DrawCapturedDT(capture, Matrix());
 | |
|   target->Flush();
 | |
| 
 | |
|   if (gfxPrefs::LayersOMTPReleaseCaptureOnMainThread()) {
 | |
|     // This should ensure the capture drawtarget, which may hold on to UnscaledFont objects,
 | |
|     // gets destroyed on the main thread (See bug 1404742). This assumes (unflushed) target
 | |
|     // DrawTargets do not themselves hold on to UnscaledFonts.
 | |
|     NS_ReleaseOnMainThreadSystemGroup("PaintTask::DrawTargetCapture", aTask->mCapture.forget());
 | |
|   }
 | |
| 
 | |
|   if (aBridge->NotifyFinishedAsyncWorkerPaint(aTask)) {
 | |
|     AsyncEndLayerTransaction(aBridge);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::QueueEndLayerTransaction(SyncObjectClient* aSyncObject)
 | |
| {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
 | |
| 
 | |
|   if (cbc->NotifyBeginAsyncEndLayerTransaction(aSyncObject)) {
 | |
|     RefPtr<PaintThread> self = this;
 | |
|     RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncEndLayerTransaction",
 | |
|       [self, cbc]() -> void
 | |
|     {
 | |
|       self->AsyncEndLayerTransaction(cbc);
 | |
|     });
 | |
| 
 | |
|   #ifndef OMTP_FORCE_SYNC
 | |
|     sThread->Dispatch(task.forget());
 | |
|   #else
 | |
|     SyncRunnable::DispatchToThread(sThread, task);
 | |
|   #endif
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| PaintThread::AsyncEndLayerTransaction(CompositorBridgeChild* aBridge)
 | |
| {
 | |
|   MOZ_ASSERT(IsOnPaintWorkerThread());
 | |
| 
 | |
|   aBridge->NotifyFinishedAsyncEndLayerTransaction();
 | |
| }
 | |
| 
 | |
| } // namespace layers
 | |
| } // namespace mozilla
 |