1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "ClientPaintedLayer.h"
8 #include "ClientTiledPaintedLayer.h"    // for ClientTiledPaintedLayer
9 #include <stdint.h>                     // for uint32_t
10 #include "GeckoProfiler.h"              // for AUTO_PROFILER_LABEL
11 #include "client/ClientLayerManager.h"  // for ClientLayerManager, etc
12 #include "gfxContext.h"                 // for gfxContext
13 #include "gfx2DGlue.h"
14 #include "gfxRect.h"             // for gfxRect
15 #include "gfxPrefs.h"            // for gfxPrefs
16 #include "mozilla/Assertions.h"  // for MOZ_ASSERT, etc
17 #include "mozilla/gfx/2D.h"      // for DrawTarget
18 #include "mozilla/gfx/DrawEventRecorder.h"
19 #include "mozilla/gfx/Matrix.h"  // for Matrix
20 #include "mozilla/gfx/Rect.h"    // for Rect, IntRect
21 #include "mozilla/gfx/Types.h"   // for Float, etc
22 #include "mozilla/layers/LayersTypes.h"
23 #include "mozilla/Preferences.h"
24 #include "nsCOMPtr.h"         // for already_AddRefed
25 #include "nsISupportsImpl.h"  // for Layer::AddRef, etc
26 #include "nsRect.h"           // for mozilla::gfx::IntRect
27 #include "PaintThread.h"
28 #include "ReadbackProcessor.h"
29 #include "RotatedBuffer.h"
30 
31 namespace mozilla {
32 namespace layers {
33 
34 using namespace mozilla::gfx;
35 
EnsureContentClient()36 bool ClientPaintedLayer::EnsureContentClient() {
37   if (!mContentClient) {
38     mContentClient = ContentClient::CreateContentClient(
39         ClientManager()->AsShadowForwarder());
40 
41     if (!mContentClient) {
42       return false;
43     }
44 
45     mContentClient->Connect();
46     ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
47     MOZ_ASSERT(mContentClient->GetForwarder());
48   }
49 
50   return true;
51 }
52 
CanRecordLayer(ReadbackProcessor * aReadback)53 bool ClientPaintedLayer::CanRecordLayer(ReadbackProcessor* aReadback) {
54   // If we don't have a paint thread, this is either not the content
55   // process or the pref is disabled.
56   if (!PaintThread::Get()) {
57     return false;
58   }
59 
60   // Not supported yet
61   if (aReadback && UsedForReadback()) {
62     return false;
63   }
64 
65   return true;
66 }
67 
UpdateContentClient(PaintState & aState)68 void ClientPaintedLayer::UpdateContentClient(PaintState& aState) {
69   Mutated();
70 
71   AddToValidRegion(aState.mRegionToDraw);
72 
73   ContentClientRemoteBuffer* contentClientRemote =
74       static_cast<ContentClientRemoteBuffer*>(mContentClient.get());
75   MOZ_ASSERT(contentClientRemote->GetIPCHandle());
76 
77   // Hold(this) ensures this layer is kept alive through the current transaction
78   // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
79   // so deleting this Hold for whatever reason will break things.
80   ClientManager()->Hold(this);
81   contentClientRemote->Updated(aState.mRegionToDraw,
82                                mVisibleRegion.ToUnknownRegion());
83 }
84 
UpdatePaintRegion(PaintState & aState)85 bool ClientPaintedLayer::UpdatePaintRegion(PaintState& aState) {
86   SubtractFromValidRegion(aState.mRegionToInvalidate);
87 
88   if (!aState.mRegionToDraw.IsEmpty() &&
89       !ClientManager()->GetPaintedLayerCallback()) {
90     ClientManager()->SetTransactionIncomplete();
91     mContentClient->EndPaint(nullptr);
92     return false;
93   }
94 
95   // The area that became invalid and is visible needs to be repainted
96   // (this could be the whole visible area if our buffer switched
97   // from RGB to RGBA, because we might need to repaint with
98   // subpixel AA)
99   aState.mRegionToInvalidate.And(aState.mRegionToInvalidate,
100                                  GetLocalVisibleRegion().ToUnknownRegion());
101   return true;
102 }
103 
GetPaintFlags()104 uint32_t ClientPaintedLayer::GetPaintFlags() {
105   uint32_t flags = ContentClient::PAINT_CAN_DRAW_ROTATED;
106 #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
107   if (ClientManager()->CompositorMightResample()) {
108     flags |= ContentClient::PAINT_WILL_RESAMPLE;
109   }
110   if (!(flags & ContentClient::PAINT_WILL_RESAMPLE)) {
111     if (MayResample()) {
112       flags |= ContentClient::PAINT_WILL_RESAMPLE;
113     }
114   }
115 #endif
116   return flags;
117 }
118 
PaintThebes(nsTArray<ReadbackProcessor::Update> * aReadbackUpdates)119 void ClientPaintedLayer::PaintThebes(
120     nsTArray<ReadbackProcessor::Update>* aReadbackUpdates) {
121   AUTO_PROFILER_LABEL("ClientPaintedLayer::PaintThebes", GRAPHICS);
122 
123   NS_ASSERTION(ClientManager()->InDrawing(), "Can only draw in drawing phase");
124 
125   uint32_t flags = GetPaintFlags();
126 
127   PaintState state = mContentClient->BeginPaint(this, flags);
128   if (!UpdatePaintRegion(state)) {
129     return;
130   }
131 
132   bool didUpdate = false;
133   RotatedBuffer::DrawIterator iter;
134   while (DrawTarget* target =
135              mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
136     if (!target || !target->IsValid()) {
137       if (target) {
138         mContentClient->ReturnDrawTarget(target);
139       }
140       continue;
141     }
142 
143     SetAntialiasingFlags(this, target);
144 
145     RefPtr<gfxContext> ctx =
146         gfxContext::CreatePreservingTransformOrNull(target);
147     MOZ_ASSERT(ctx);  // already checked the target above
148 
149     ClientManager()->GetPaintedLayerCallback()(
150         this, ctx, iter.mDrawRegion, iter.mDrawRegion, state.mClip,
151         state.mRegionToInvalidate,
152         ClientManager()->GetPaintedLayerCallbackData());
153 
154     ctx = nullptr;
155     mContentClient->ReturnDrawTarget(target);
156     didUpdate = true;
157   }
158 
159   mContentClient->EndPaint(aReadbackUpdates);
160 
161   if (didUpdate) {
162     UpdateContentClient(state);
163   }
164 }
165 
166 class MOZ_RAII AutoQueuedAsyncPaint {
167  public:
AutoQueuedAsyncPaint(ClientLayerManager * aLayerManager)168   explicit AutoQueuedAsyncPaint(ClientLayerManager* aLayerManager)
169       : mLayerManager(aLayerManager), mQueuedAsyncPaints(false) {}
170 
Queue()171   void Queue() { mQueuedAsyncPaints = true; }
172 
~AutoQueuedAsyncPaint()173   ~AutoQueuedAsyncPaint() {
174     if (mQueuedAsyncPaints) {
175       mLayerManager->SetQueuedAsyncPaints();
176     }
177   }
178 
179  private:
180   ClientLayerManager* mLayerManager;
181   bool mQueuedAsyncPaints;
182 };
183 
184 /***
185  * If we can, let's paint this ClientPaintedLayer's contents off the main
186  * thread. The essential idea is that we ask the ContentClient for a DrawTarget
187  * and record the moz2d commands. On the Paint Thread, we replay those commands
188  * to the destination draw target. There are a couple of lifetime issues here
189  * though:
190  *
191  * 1) TextureClient owns the underlying buffer and DrawTarget. Because of this
192  *    we have to keep the TextureClient and DrawTarget alive but trick the
193  *    TextureClient into thinking it's already returned the DrawTarget
194  *    since we iterate through different Rects to get DrawTargets*. If
195  *    the TextureClient goes away, the DrawTarget and thus buffer can too.
196  * 2) When ContentClient::EndPaint happens, it flushes the DrawTarget. We have
197  *    to Reflush on the Paint Thread
198  * 3) DrawTarget API is NOT thread safe. We get around this by recording
199  *    on the main thread and painting on the paint thread. Logically,
200  *    ClientLayerManager will force a flushed paint and block the main thread
201  *    if we have another transaction. Thus we have a gap between when the main
202  *    thread records, the paint thread paints, and we block the main thread
203  *    from trying to paint again. The underlying API however is NOT thread safe.
204  *  4) We have both "sync" and "async" OMTP. Sync OMTP means we paint on the
205  * main thread but block the main thread while the paint thread paints. Async
206  * OMTP doesn't block the main thread. Sync OMTP is only meant to be used as
207  * a debugging tool.
208  */
PaintOffMainThread()209 void ClientPaintedLayer::PaintOffMainThread() {
210   AutoQueuedAsyncPaint asyncPaints(ClientManager());
211 
212   uint32_t flags = GetPaintFlags();
213   PaintState state =
214       mContentClient->BeginPaint(this, flags | ContentClient::PAINT_ASYNC);
215 
216   if (state.mBufferState && state.mBufferState->HasOperations()) {
217     PaintThread::Get()->PrepareBuffer(state.mBufferState);
218     asyncPaints.Queue();
219   }
220 
221   if (!UpdatePaintRegion(state)) {
222     return;
223   }
224 
225   bool didUpdate = false;
226   RotatedBuffer::DrawIterator iter;
227 
228   // Debug Protip: Change to BorrowDrawTargetForPainting if using sync OMTP.
229   while (RefPtr<CapturedPaintState> captureState =
230              mContentClient->BorrowDrawTargetForRecording(state, &iter)) {
231     DrawTarget* target = captureState->mTargetDual;
232     if (!target || !target->IsValid()) {
233       if (target) {
234         mContentClient->ReturnDrawTarget(target);
235       }
236       continue;
237     }
238 
239     RefPtr<DrawTargetCapture> captureDT = Factory::CreateCaptureDrawTarget(
240         target->GetBackendType(), target->GetSize(), target->GetFormat());
241 
242     captureDT->SetTransform(captureState->mTargetTransform);
243     SetAntialiasingFlags(this, captureDT);
244 
245     RefPtr<gfxContext> ctx =
246         gfxContext::CreatePreservingTransformOrNull(captureDT);
247     MOZ_ASSERT(ctx);  // already checked the target above
248 
249     ClientManager()->GetPaintedLayerCallback()(
250         this, ctx, iter.mDrawRegion, iter.mDrawRegion, state.mClip,
251         state.mRegionToInvalidate,
252         ClientManager()->GetPaintedLayerCallbackData());
253 
254     ctx = nullptr;
255 
256     captureState->mCapture = captureDT.forget();
257     PaintThread::Get()->PaintContents(
258         captureState, ContentClient::PrepareDrawTargetForPainting);
259 
260     mContentClient->ReturnDrawTarget(target);
261 
262     asyncPaints.Queue();
263     didUpdate = true;
264   }
265 
266   PaintThread::Get()->EndLayer();
267   mContentClient->EndPaint(nullptr);
268 
269   if (didUpdate) {
270     UpdateContentClient(state);
271   }
272 }
273 
RenderLayerWithReadback(ReadbackProcessor * aReadback)274 void ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor* aReadback) {
275   RenderMaskLayers(this);
276 
277   if (!EnsureContentClient()) {
278     return;
279   }
280 
281   if (CanRecordLayer(aReadback)) {
282     PaintOffMainThread();
283     return;
284   }
285 
286   nsTArray<ReadbackProcessor::Update> readbackUpdates;
287   nsIntRegion readbackRegion;
288   if (aReadback && UsedForReadback()) {
289     aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
290   }
291 
292   PaintThebes(&readbackUpdates);
293 }
294 
CreatePaintedLayer()295 already_AddRefed<PaintedLayer> ClientLayerManager::CreatePaintedLayer() {
296   return CreatePaintedLayerWithHint(NONE);
297 }
298 
CreatePaintedLayerWithHint(PaintedLayerCreationHint aHint)299 already_AddRefed<PaintedLayer> ClientLayerManager::CreatePaintedLayerWithHint(
300     PaintedLayerCreationHint aHint) {
301   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
302   if (gfxPlatform::GetPlatform()->UsesTiling()) {
303     RefPtr<ClientTiledPaintedLayer> layer =
304         new ClientTiledPaintedLayer(this, aHint);
305     CREATE_SHADOW(Painted);
306     return layer.forget();
307   } else {
308     RefPtr<ClientPaintedLayer> layer = new ClientPaintedLayer(this, aHint);
309     CREATE_SHADOW(Painted);
310     return layer.forget();
311   }
312 }
313 
PrintInfo(std::stringstream & aStream,const char * aPrefix)314 void ClientPaintedLayer::PrintInfo(std::stringstream& aStream,
315                                    const char* aPrefix) {
316   PaintedLayer::PrintInfo(aStream, aPrefix);
317   if (mContentClient) {
318     aStream << "\n";
319     nsAutoCString pfx(aPrefix);
320     pfx += "  ";
321     mContentClient->PrintInfo(aStream, pfx.get());
322   }
323 }
324 
325 }  // namespace layers
326 }  // namespace mozilla
327