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 "ClientPaintedLayer.h"
7 : #include "ClientTiledPaintedLayer.h" // for ClientTiledPaintedLayer
8 : #include <stdint.h> // for uint32_t
9 : #include "GeckoProfiler.h" // for AUTO_PROFILER_LABEL
10 : #include "client/ClientLayerManager.h" // for ClientLayerManager, etc
11 : #include "gfxContext.h" // for gfxContext
12 : #include "gfx2DGlue.h"
13 : #include "gfxRect.h" // for gfxRect
14 : #include "gfxPrefs.h" // for gfxPrefs
15 : #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
16 : #include "mozilla/gfx/2D.h" // for DrawTarget
17 : #include "mozilla/gfx/DrawEventRecorder.h"
18 : #include "mozilla/gfx/Matrix.h" // for Matrix
19 : #include "mozilla/gfx/Rect.h" // for Rect, IntRect
20 : #include "mozilla/gfx/Types.h" // for Float, etc
21 : #include "mozilla/layers/LayersTypes.h"
22 : #include "mozilla/Preferences.h"
23 : #include "nsCOMPtr.h" // for already_AddRefed
24 : #include "nsISupportsImpl.h" // for Layer::AddRef, etc
25 : #include "nsRect.h" // for mozilla::gfx::IntRect
26 : #include "PaintThread.h"
27 : #include "ReadbackProcessor.h"
28 :
29 : namespace mozilla {
30 : namespace layers {
31 :
32 : using namespace mozilla::gfx;
33 :
34 : bool
35 77 : ClientPaintedLayer::EnsureContentClient()
36 : {
37 77 : if (!mContentClient) {
38 44 : mContentClient = ContentClient::CreateContentClient(
39 44 : ClientManager()->AsShadowForwarder());
40 :
41 22 : if (!mContentClient) {
42 0 : return false;
43 : }
44 :
45 22 : mContentClient->Connect();
46 22 : ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
47 22 : MOZ_ASSERT(mContentClient->GetForwarder());
48 : }
49 :
50 77 : return true;
51 : }
52 :
53 : bool
54 77 : ClientPaintedLayer::CanRecordLayer(ReadbackProcessor* aReadback)
55 : {
56 : // If we don't have a paint thread, this is either not the content
57 : // process or the pref is disabled.
58 77 : if (!PaintThread::Get()) {
59 77 : return false;
60 : }
61 :
62 : // Not supported yet
63 0 : if (aReadback && UsedForReadback()) {
64 0 : return false;
65 : }
66 :
67 : // If we have mask layers, we have to render those first
68 : // In this case, don't record for now.
69 0 : if (GetMaskLayer()) {
70 0 : return false;
71 : }
72 :
73 0 : return GetAncestorMaskLayerCount() == 0;
74 : }
75 :
76 : void
77 33 : ClientPaintedLayer::UpdateContentClient(PaintState& aState)
78 : {
79 33 : Mutated();
80 :
81 33 : AddToValidRegion(aState.mRegionToDraw);
82 :
83 : ContentClientRemote *contentClientRemote =
84 33 : static_cast<ContentClientRemote *>(mContentClient.get());
85 33 : MOZ_ASSERT(contentClientRemote->GetIPCHandle());
86 :
87 : // Hold(this) ensures this layer is kept alive through the current transaction
88 : // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
89 : // so deleting this Hold for whatever reason will break things.
90 33 : ClientManager()->Hold(this);
91 66 : contentClientRemote->Updated(aState.mRegionToDraw,
92 66 : mVisibleRegion.ToUnknownRegion(),
93 66 : aState.mDidSelfCopy);
94 33 : }
95 :
96 : bool
97 77 : ClientPaintedLayer::UpdatePaintRegion(PaintState& aState)
98 : {
99 77 : SubtractFromValidRegion(aState.mRegionToInvalidate);
100 :
101 77 : if (!aState.mRegionToDraw.IsEmpty() && !ClientManager()->GetPaintedLayerCallback()) {
102 0 : ClientManager()->SetTransactionIncomplete();
103 0 : mContentClient->EndPaint(nullptr);
104 0 : return false;
105 : }
106 :
107 : // The area that became invalid and is visible needs to be repainted
108 : // (this could be the whole visible area if our buffer switched
109 : // from RGB to RGBA, because we might need to repaint with
110 : // subpixel AA)
111 : aState.mRegionToInvalidate.And(aState.mRegionToInvalidate,
112 77 : GetLocalVisibleRegion().ToUnknownRegion());
113 77 : return true;
114 : }
115 :
116 : void
117 0 : ClientPaintedLayer::PaintOffMainThread(DrawTargetCapture* aCapture)
118 : {
119 0 : MOZ_ASSERT(NS_IsMainThread());
120 0 : LayerIntRegion visibleRegion = GetVisibleRegion();
121 0 : mContentClient->BeginPaint();
122 :
123 0 : uint32_t flags = GetPaintFlags();
124 :
125 : PaintState state =
126 0 : mContentClient->BeginPaintBuffer(this, flags);
127 0 : if (!UpdatePaintRegion(state)) {
128 0 : return;
129 : }
130 :
131 0 : bool didUpdate = false;
132 0 : RotatedContentBuffer::DrawIterator iter;
133 0 : while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
134 0 : if (!target || !target->IsValid()) {
135 0 : if (target) {
136 0 : mContentClient->ReturnDrawTargetToBuffer(target);
137 : }
138 0 : continue;
139 : }
140 :
141 0 : SetAntialiasingFlags(this, target);
142 :
143 : // Basic version, wait for the paint thread to finish painting.
144 0 : PaintThread::Get()->PaintContents(aCapture, target);
145 :
146 0 : mContentClient->ReturnDrawTargetToBuffer(target);
147 0 : didUpdate = true;
148 0 : }
149 :
150 : // ending paint w/o any readback updates
151 : // TODO: Fix me
152 0 : mContentClient->EndPaint(nullptr);
153 :
154 0 : if (didUpdate) {
155 0 : UpdateContentClient(state);
156 : }
157 : }
158 :
159 :
160 : uint32_t
161 77 : ClientPaintedLayer::GetPaintFlags()
162 : {
163 77 : uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
164 : #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
165 77 : if (ClientManager()->CompositorMightResample()) {
166 0 : flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
167 : }
168 77 : if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) {
169 77 : if (MayResample()) {
170 0 : flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
171 : }
172 : }
173 : #endif
174 77 : return flags;
175 : }
176 :
177 : void
178 77 : ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
179 : {
180 154 : AUTO_PROFILER_LABEL("ClientPaintedLayer::PaintThebes", GRAPHICS);
181 :
182 77 : NS_ASSERTION(ClientManager()->InDrawing(),
183 : "Can only draw in drawing phase");
184 :
185 77 : mContentClient->BeginPaint();
186 :
187 77 : uint32_t flags = GetPaintFlags();
188 :
189 154 : PaintState state = mContentClient->BeginPaintBuffer(this, flags);
190 77 : if (!UpdatePaintRegion(state)) {
191 0 : return;
192 : }
193 :
194 77 : bool didUpdate = false;
195 154 : RotatedContentBuffer::DrawIterator iter;
196 110 : while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
197 33 : if (!target || !target->IsValid()) {
198 0 : if (target) {
199 0 : mContentClient->ReturnDrawTargetToBuffer(target);
200 : }
201 0 : continue;
202 : }
203 :
204 33 : SetAntialiasingFlags(this, target);
205 :
206 66 : RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(target);
207 33 : MOZ_ASSERT(ctx); // already checked the target above
208 :
209 33 : ClientManager()->GetPaintedLayerCallback()(this,
210 : ctx,
211 : iter.mDrawRegion,
212 : iter.mDrawRegion,
213 : state.mClip,
214 : state.mRegionToInvalidate,
215 33 : ClientManager()->GetPaintedLayerCallbackData());
216 :
217 33 : ctx = nullptr;
218 33 : mContentClient->ReturnDrawTargetToBuffer(target);
219 33 : didUpdate = true;
220 33 : }
221 :
222 77 : mContentClient->EndPaint(aReadbackUpdates);
223 :
224 77 : if (didUpdate) {
225 33 : UpdateContentClient(state);
226 : }
227 : }
228 :
229 : already_AddRefed<DrawTargetCapture>
230 0 : ClientPaintedLayer::CapturePaintedContent()
231 : {
232 0 : LayerIntRegion visibleRegion = GetVisibleRegion();
233 0 : LayerIntRect bounds = visibleRegion.GetBounds();
234 0 : LayerIntSize size = bounds.Size();
235 :
236 0 : if (visibleRegion.IsEmpty()) {
237 0 : if (gfxPrefs::LayersDump()) {
238 0 : printf_stderr("PaintedLayer %p skipping\n", this);
239 : }
240 0 : return nullptr;
241 : }
242 :
243 0 : nsIntRegion regionToPaint;
244 0 : regionToPaint.Sub(mVisibleRegion.ToUnknownRegion(), GetValidRegion());
245 :
246 0 : if (regionToPaint.IsEmpty()) {
247 : // Do we ever have to do anything if the region to paint is empty
248 : // but we have a painted layer callback?
249 0 : return nullptr;
250 : }
251 :
252 0 : if (!ClientManager()->GetPaintedLayerCallback()) {
253 0 : ClientManager()->SetTransactionIncomplete();
254 0 : return nullptr;
255 : }
256 :
257 0 : IntSize imageSize(size.ToUnknownSize());
258 :
259 : // DrawTargetCapture requires a reference DT
260 : // That is used when some API requires a snapshot.
261 : // TODO: Fixup so DrawTargetCapture lazily creates a reference DT
262 : RefPtr<DrawTarget> refDT =
263 0 : Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetDefaultContentBackend(),
264 0 : imageSize, gfx::SurfaceFormat::B8G8R8A8);
265 :
266 : // We don't clear the rect here like WRPaintedBlobLayers do
267 : // because ContentClient already clears the surface for us during BeginPaint.
268 0 : RefPtr<DrawTargetCapture> captureDT = refDT->CreateCaptureDT(imageSize);
269 0 : captureDT->SetTransform(Matrix().PreTranslate(-bounds.x, -bounds.y));
270 :
271 0 : RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(captureDT);
272 0 : MOZ_ASSERT(ctx); // already checked the target above
273 :
274 0 : ClientManager()->GetPaintedLayerCallback()(this,
275 : ctx,
276 0 : visibleRegion.ToUnknownRegion(),
277 0 : visibleRegion.ToUnknownRegion(),
278 : DrawRegionClip::DRAW,
279 0 : nsIntRegion(),
280 0 : ClientManager()->GetPaintedLayerCallbackData());
281 :
282 0 : return captureDT.forget();
283 : }
284 :
285 : void
286 77 : ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
287 : {
288 77 : RenderMaskLayers(this);
289 :
290 77 : if (CanRecordLayer(aReadback)) {
291 0 : RefPtr<DrawTargetCapture> capture = CapturePaintedContent();
292 0 : if (capture) {
293 0 : if (!EnsureContentClient()) {
294 0 : return;
295 : }
296 :
297 0 : PaintOffMainThread(capture);
298 0 : return;
299 : }
300 : }
301 :
302 77 : if (!EnsureContentClient()) {
303 0 : return;
304 : }
305 :
306 154 : nsTArray<ReadbackProcessor::Update> readbackUpdates;
307 154 : nsIntRegion readbackRegion;
308 77 : if (aReadback && UsedForReadback()) {
309 0 : aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
310 : }
311 :
312 77 : PaintThebes(&readbackUpdates);
313 : }
314 :
315 : already_AddRefed<PaintedLayer>
316 0 : ClientLayerManager::CreatePaintedLayer()
317 : {
318 0 : return CreatePaintedLayerWithHint(NONE);
319 : }
320 :
321 : already_AddRefed<PaintedLayer>
322 22 : ClientLayerManager::CreatePaintedLayerWithHint(PaintedLayerCreationHint aHint)
323 : {
324 22 : NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
325 : // The non-tiling ContentClient requires CrossProcessSemaphore which
326 : // isn't implemented for OSX.
327 : #ifdef XP_MACOSX
328 : if (true) {
329 : #else
330 22 : if (gfxPrefs::LayersTilesEnabled()) {
331 : #endif
332 0 : RefPtr<ClientTiledPaintedLayer> layer = new ClientTiledPaintedLayer(this, aHint);
333 0 : CREATE_SHADOW(Painted);
334 0 : return layer.forget();
335 : } else {
336 44 : RefPtr<ClientPaintedLayer> layer = new ClientPaintedLayer(this, aHint);
337 22 : CREATE_SHADOW(Painted);
338 22 : return layer.forget();
339 : }
340 : }
341 :
342 : void
343 0 : ClientPaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
344 : {
345 0 : PaintedLayer::PrintInfo(aStream, aPrefix);
346 0 : if (mContentClient) {
347 0 : aStream << "\n";
348 0 : nsAutoCString pfx(aPrefix);
349 0 : pfx += " ";
350 0 : mContentClient->PrintInfo(aStream, pfx.get());
351 : }
352 0 : }
353 :
354 : } // namespace layers
355 : } // namespace mozilla
|