Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; 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 "mozilla/layers/ContentClient.h"
7 : #include "BasicLayers.h" // for BasicLayerManager
8 : #include "gfxContext.h" // for gfxContext, etc
9 : #include "gfxPlatform.h" // for gfxPlatform
10 : #include "gfxEnv.h" // for gfxEnv
11 : #include "gfxPrefs.h" // for gfxPrefs
12 : #include "gfxPoint.h" // for IntSize, gfxPoint
13 : #include "gfxUtils.h" // for gfxUtils
14 : #include "ipc/ShadowLayers.h" // for ShadowLayerForwarder
15 : #include "mozilla/ArrayUtils.h" // for ArrayLength
16 : #include "mozilla/Maybe.h"
17 : #include "mozilla/gfx/2D.h" // for DrawTarget, Factory
18 : #include "mozilla/gfx/BasePoint.h" // for BasePoint
19 : #include "mozilla/gfx/BaseSize.h" // for BaseSize
20 : #include "mozilla/gfx/Rect.h" // for Rect
21 : #include "mozilla/gfx/Types.h"
22 : #include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
23 : #include "mozilla/layers/LayerManagerComposite.h"
24 : #include "mozilla/layers/LayersMessages.h" // for ThebesBufferData
25 : #include "mozilla/layers/LayersTypes.h"
26 : #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
27 : #include "nsISupportsImpl.h" // for gfxContext::Release, etc
28 : #include "nsIWidget.h" // for nsIWidget
29 : #include "nsLayoutUtils.h"
30 : #ifdef XP_WIN
31 : #include "gfxWindowsPlatform.h"
32 : #endif
33 : #ifdef MOZ_WIDGET_GTK
34 : #include "gfxPlatformGtk.h"
35 : #endif
36 : #include "ReadbackLayer.h"
37 :
38 : #include <vector>
39 :
40 : using namespace std;
41 :
42 : namespace mozilla {
43 :
44 : using namespace gfx;
45 :
46 : namespace layers {
47 :
48 5 : static TextureFlags TextureFlagsForRotatedContentBufferFlags(uint32_t aBufferFlags)
49 : {
50 5 : TextureFlags result = TextureFlags::NO_FLAGS;
51 :
52 5 : if (aBufferFlags & RotatedContentBuffer::BUFFER_COMPONENT_ALPHA) {
53 0 : result |= TextureFlags::COMPONENT_ALPHA;
54 : }
55 :
56 5 : return result;
57 : }
58 :
59 : /* static */ already_AddRefed<ContentClient>
60 22 : ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
61 : {
62 22 : LayersBackend backend = aForwarder->GetCompositorBackendType();
63 22 : if (backend != LayersBackend::LAYERS_OPENGL &&
64 22 : backend != LayersBackend::LAYERS_D3D11 &&
65 22 : backend != LayersBackend::LAYERS_WR &&
66 : backend != LayersBackend::LAYERS_BASIC) {
67 0 : return nullptr;
68 : }
69 :
70 22 : bool useDoubleBuffering = false;
71 :
72 : #ifdef XP_WIN
73 : if (backend == LayersBackend::LAYERS_D3D11) {
74 : useDoubleBuffering = gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend();
75 : } else
76 : #endif
77 : #ifdef MOZ_WIDGET_GTK
78 : // We can't use double buffering when using image content with
79 : // Xrender support on Linux, as ContentHostDoubleBuffered is not
80 : // suited for direct uploads to the server.
81 44 : if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() ||
82 22 : !gfxVars::UseXRender())
83 : #endif
84 : {
85 22 : useDoubleBuffering = backend == LayersBackend::LAYERS_BASIC;
86 : }
87 :
88 22 : if (useDoubleBuffering || gfxEnv::ForceDoubleBuffering()) {
89 22 : return MakeAndAddRef<ContentClientDoubleBuffered>(aForwarder);
90 : }
91 0 : return MakeAndAddRef<ContentClientSingleBuffered>(aForwarder);
92 : }
93 :
94 : void
95 77 : ContentClient::EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
96 : {
97 77 : }
98 :
99 : void
100 0 : ContentClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
101 : {
102 0 : aStream << aPrefix;
103 0 : aStream << nsPrintfCString("ContentClient (0x%p)", this).get();
104 :
105 0 : if (profiler_feature_active(ProfilerFeature::DisplayListDump)) {
106 0 : nsAutoCString pfx(aPrefix);
107 0 : pfx += " ";
108 :
109 0 : Dump(aStream, pfx.get(), false);
110 : }
111 0 : }
112 :
113 : // We pass a null pointer for the ContentClient Forwarder argument, which means
114 : // this client will not have a ContentHost on the other side.
115 57 : ContentClientBasic::ContentClientBasic(gfx::BackendType aBackend)
116 : : ContentClient(nullptr)
117 : , RotatedContentBuffer(ContainsVisibleBounds)
118 57 : , mBackend(aBackend)
119 57 : {}
120 :
121 : void
122 0 : ContentClientBasic::CreateBuffer(ContentType aType,
123 : const IntRect& aRect,
124 : uint32_t aFlags,
125 : RefPtr<gfx::DrawTarget>* aBlackDT,
126 : RefPtr<gfx::DrawTarget>* aWhiteDT)
127 : {
128 0 : MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
129 0 : if (aFlags & BUFFER_COMPONENT_ALPHA) {
130 0 : gfxDevCrash(LogReason::AlphaWithBasicClient) << "Asking basic content client for component alpha";
131 : }
132 :
133 0 : IntSize size(aRect.width, aRect.height);
134 : #ifdef XP_WIN
135 : if (mBackend == BackendType::CAIRO &&
136 : (aType == gfxContentType::COLOR || aType == gfxContentType::COLOR_ALPHA)) {
137 : RefPtr<gfxASurface> surf =
138 : new gfxWindowsSurface(size, aType == gfxContentType::COLOR ? gfxImageFormat::X8R8G8B8_UINT32 :
139 : gfxImageFormat::A8R8G8B8_UINT32);
140 : *aBlackDT = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
141 :
142 : if (*aBlackDT) {
143 : return;
144 : }
145 : }
146 : #endif
147 :
148 0 : *aBlackDT = gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(
149 : mBackend, size,
150 0 : gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType));
151 0 : }
152 :
153 : void
154 5 : ContentClientRemoteBuffer::DestroyBuffers()
155 : {
156 5 : if (!mTextureClient) {
157 4 : return;
158 : }
159 :
160 1 : mOldTextures.AppendElement(mTextureClient);
161 1 : mTextureClient = nullptr;
162 1 : if (mTextureClientOnWhite) {
163 0 : mOldTextures.AppendElement(mTextureClientOnWhite);
164 0 : mTextureClientOnWhite = nullptr;
165 : }
166 :
167 1 : DestroyFrontBuffer();
168 : }
169 :
170 0 : class RemoteBufferReadbackProcessor : public TextureReadbackSink
171 : {
172 : public:
173 0 : RemoteBufferReadbackProcessor(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates,
174 : const IntRect& aBufferRect, const nsIntPoint& aBufferRotation)
175 0 : : mReadbackUpdates(*aReadbackUpdates)
176 : , mBufferRect(aBufferRect)
177 0 : , mBufferRotation(aBufferRotation)
178 : {
179 0 : for (uint32_t i = 0; i < mReadbackUpdates.Length(); ++i) {
180 0 : mLayerRefs.push_back(mReadbackUpdates[i].mLayer);
181 : }
182 0 : }
183 :
184 0 : virtual void ProcessReadback(gfx::DataSourceSurface *aSourceSurface)
185 : {
186 0 : SourceRotatedBuffer rotBuffer(aSourceSurface, nullptr, mBufferRect, mBufferRotation);
187 :
188 0 : for (uint32_t i = 0; i < mReadbackUpdates.Length(); ++i) {
189 0 : ReadbackProcessor::Update& update = mReadbackUpdates[i];
190 0 : nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset();
191 :
192 0 : ReadbackSink* sink = update.mLayer->GetSink();
193 :
194 0 : if (!sink) {
195 0 : continue;
196 : }
197 :
198 0 : if (!aSourceSurface) {
199 0 : sink->SetUnknown(update.mSequenceCounter);
200 0 : continue;
201 : }
202 :
203 : RefPtr<DrawTarget> dt =
204 0 : sink->BeginUpdate(update.mUpdateRect + offset, update.mSequenceCounter);
205 0 : if (!dt) {
206 0 : continue;
207 : }
208 :
209 0 : dt->SetTransform(Matrix::Translation(offset.x, offset.y));
210 :
211 0 : rotBuffer.DrawBufferWithRotation(dt, RotatedBuffer::BUFFER_BLACK);
212 :
213 0 : update.mLayer->GetSink()->EndUpdate(update.mUpdateRect + offset);
214 : }
215 0 : }
216 :
217 : private:
218 : nsTArray<ReadbackProcessor::Update> mReadbackUpdates;
219 : // This array is used to keep the layers alive until the callback.
220 : vector<RefPtr<Layer>> mLayerRefs;
221 :
222 : IntRect mBufferRect;
223 : nsIntPoint mBufferRotation;
224 : };
225 :
226 : void
227 77 : ContentClientRemoteBuffer::BeginPaint()
228 : {
229 77 : EnsureBackBufferIfFrontBuffer();
230 :
231 : // XXX: So we might not have a TextureClient yet.. because it will
232 : // only be created by CreateBuffer.. which will deliver a locked surface!.
233 77 : if (mTextureClient) {
234 52 : SetBufferProvider(mTextureClient);
235 : }
236 77 : if (mTextureClientOnWhite) {
237 0 : SetBufferProviderOnWhite(mTextureClientOnWhite);
238 : }
239 77 : }
240 :
241 : void
242 77 : ContentClientRemoteBuffer::EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
243 : {
244 77 : MOZ_ASSERT(!mTextureClientOnWhite || !aReadbackUpdates || aReadbackUpdates->Length() == 0);
245 :
246 : // XXX: We might still not have a texture client if PaintThebes
247 : // decided we didn't need one yet because the region to draw was empty.
248 77 : SetBufferProvider(nullptr);
249 77 : SetBufferProviderOnWhite(nullptr);
250 79 : for (unsigned i = 0; i< mOldTextures.Length(); ++i) {
251 2 : if (mOldTextures[i]->IsLocked()) {
252 1 : mOldTextures[i]->Unlock();
253 : }
254 : }
255 77 : mOldTextures.Clear();
256 :
257 77 : if (mTextureClient && mTextureClient->IsLocked()) {
258 33 : if (aReadbackUpdates && aReadbackUpdates->Length() > 0) {
259 0 : RefPtr<TextureReadbackSink> readbackSink = new RemoteBufferReadbackProcessor(aReadbackUpdates, mBufferRect, mBufferRotation);
260 :
261 0 : mTextureClient->SetReadbackSink(readbackSink);
262 : }
263 :
264 33 : mTextureClient->Unlock();
265 33 : mTextureClient->SyncWithObject(mForwarder->GetSyncObject());
266 : }
267 77 : if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) {
268 0 : mTextureClientOnWhite->Unlock();
269 0 : mTextureClientOnWhite->SyncWithObject(mForwarder->GetSyncObject());
270 : }
271 :
272 77 : ContentClientRemote::EndPaint(aReadbackUpdates);
273 77 : }
274 :
275 : void
276 5 : ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
277 : const IntRect& aRect,
278 : uint32_t aFlags)
279 : {
280 : // If we hit this assertion, then it might be due to an empty transaction
281 : // followed by a real transaction. Our buffers should be created (but not
282 : // painted in the empty transaction) and then painted (but not created) in the
283 : // real transaction. That is kind of fragile, and this assert will catch
284 : // circumstances where we screw that up, e.g., by unnecessarily recreating our
285 : // buffers.
286 5 : MOZ_ASSERT(!mIsNewBuffer,
287 : "Bad! Did we create a buffer twice without painting?");
288 :
289 5 : mIsNewBuffer = true;
290 :
291 5 : DestroyBuffers();
292 :
293 5 : mSurfaceFormat = aFormat;
294 5 : mSize = IntSize(aRect.width, aRect.height);
295 5 : mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
296 :
297 5 : if (aFlags & BUFFER_COMPONENT_ALPHA) {
298 0 : mTextureFlags |= TextureFlags::COMPONENT_ALPHA;
299 : }
300 :
301 5 : CreateBackBuffer(mBufferRect);
302 5 : }
303 :
304 : void
305 9 : ContentClientRemoteBuffer::CreateBackBuffer(const IntRect& aBufferRect)
306 : {
307 : // gfx::BackendType::NONE means fallback to the content backend
308 : TextureAllocationFlags textureAllocFlags
309 27 : = (mTextureFlags & TextureFlags::COMPONENT_ALPHA) ?
310 : TextureAllocationFlags::ALLOC_CLEAR_BUFFER_BLACK :
311 18 : TextureAllocationFlags::ALLOC_CLEAR_BUFFER;
312 :
313 18 : mTextureClient = CreateTextureClientForDrawing(
314 : mSurfaceFormat, mSize, BackendSelector::Content,
315 18 : mTextureFlags | ExtraTextureFlags(),
316 : textureAllocFlags
317 9 : );
318 9 : if (!mTextureClient || !AddTextureClient(mTextureClient)) {
319 0 : AbortTextureClientCreation();
320 0 : return;
321 : }
322 9 : mTextureClient->EnableBlockingReadLock();
323 :
324 9 : if (mTextureFlags & TextureFlags::COMPONENT_ALPHA) {
325 0 : mTextureClientOnWhite = mTextureClient->CreateSimilar(
326 0 : mForwarder->GetCompositorBackendType(),
327 0 : mTextureFlags | ExtraTextureFlags(),
328 : TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE
329 0 : );
330 0 : if (!mTextureClientOnWhite || !AddTextureClient(mTextureClientOnWhite)) {
331 0 : AbortTextureClientCreation();
332 0 : return;
333 : }
334 : // We don't enable the readlock for the white buffer since we always
335 : // use them together and waiting on the lock for the black
336 : // should be sufficient.
337 : }
338 : }
339 :
340 : void
341 5 : ContentClientRemoteBuffer::CreateBuffer(ContentType aType,
342 : const IntRect& aRect,
343 : uint32_t aFlags,
344 : RefPtr<gfx::DrawTarget>* aBlackDT,
345 : RefPtr<gfx::DrawTarget>* aWhiteDT)
346 : {
347 5 : BuildTextureClients(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType), aRect, aFlags);
348 5 : if (!mTextureClient) {
349 0 : return;
350 : }
351 :
352 : // We just created the textures and we are about to get their draw targets
353 : // so we have to lock them here.
354 10 : DebugOnly<bool> locked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE);
355 5 : MOZ_ASSERT(locked, "Could not lock the TextureClient");
356 :
357 5 : *aBlackDT = mTextureClient->BorrowDrawTarget();
358 5 : if (aFlags & BUFFER_COMPONENT_ALPHA) {
359 0 : locked = mTextureClientOnWhite->Lock(OpenMode::OPEN_READ_WRITE);
360 0 : MOZ_ASSERT(locked, "Could not lock the second TextureClient for component alpha");
361 :
362 0 : *aWhiteDT = mTextureClientOnWhite->BorrowDrawTarget();
363 : }
364 : }
365 :
366 : nsIntRegion
367 33 : ContentClientRemoteBuffer::GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
368 : const nsIntRegion& aVisibleRegion,
369 : bool aDidSelfCopy)
370 : {
371 33 : nsIntRegion updatedRegion;
372 33 : if (mIsNewBuffer || aDidSelfCopy) {
373 : // A buffer reallocation clears both buffers. The front buffer has all the
374 : // content by now, but the back buffer is still clear. Here, in effect, we
375 : // are saying to copy all of the pixels of the front buffer to the back.
376 : // Also when we self-copied in the buffer, the buffer space
377 : // changes and some changed buffer content isn't reflected in the
378 : // draw or invalidate region (on purpose!). When this happens, we
379 : // need to read back the entire buffer too.
380 5 : updatedRegion = aVisibleRegion.GetBounds();
381 5 : mIsNewBuffer = false;
382 : } else {
383 28 : updatedRegion = aRegionToDraw;
384 : }
385 :
386 33 : NS_ASSERTION(BufferRect().Contains(aRegionToDraw.GetBounds()),
387 : "Update outside of buffer rect!");
388 33 : MOZ_ASSERT(mTextureClient, "should have a back buffer by now");
389 :
390 33 : return updatedRegion;
391 : }
392 :
393 : void
394 33 : ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw,
395 : const nsIntRegion& aVisibleRegion,
396 : bool aDidSelfCopy)
397 : {
398 : nsIntRegion updatedRegion = GetUpdatedRegion(aRegionToDraw,
399 : aVisibleRegion,
400 66 : aDidSelfCopy);
401 :
402 33 : MOZ_ASSERT(mTextureClient);
403 33 : if (mTextureClientOnWhite) {
404 0 : mForwarder->UseComponentAlphaTextures(this, mTextureClient,
405 0 : mTextureClientOnWhite);
406 : } else {
407 66 : AutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
408 33 : CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
409 33 : t->mTextureClient = mTextureClient;
410 33 : IntSize size = mTextureClient->GetSize();
411 33 : t->mPictureRect = nsIntRect(0, 0, size.width, size.height);
412 33 : GetForwarder()->UseTextures(this, textures);
413 : }
414 : // This forces a synchronous transaction, so we can swap buffers now
415 : // and know that we'll have sole ownership of the old front buffer
416 : // by the time we paint next.
417 66 : mForwarder->UpdateTextureRegion(this,
418 66 : ThebesBufferData(BufferRect(),
419 33 : BufferRotation()),
420 66 : updatedRegion);
421 33 : SwapBuffers(updatedRegion);
422 33 : }
423 :
424 : void
425 33 : ContentClientRemoteBuffer::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
426 : {
427 33 : mFrontAndBackBufferDiffer = true;
428 33 : }
429 :
430 : bool
431 29 : ContentClientRemoteBuffer::LockBuffers()
432 : {
433 29 : if (mTextureClient) {
434 29 : bool locked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE);
435 29 : if (!locked) {
436 0 : return false;
437 : }
438 : }
439 29 : if (mTextureClientOnWhite) {
440 0 : bool locked = mTextureClientOnWhite->Lock(OpenMode::OPEN_READ_WRITE);
441 0 : if (!locked) {
442 0 : UnlockBuffers();
443 0 : return false;
444 : }
445 : }
446 29 : return true;
447 : }
448 :
449 : void
450 0 : ContentClientRemoteBuffer::UnlockBuffers()
451 : {
452 0 : if (mTextureClient && mTextureClient->IsLocked()) {
453 0 : mTextureClient->Unlock();
454 : }
455 0 : if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) {
456 0 : mTextureClientOnWhite->Unlock();
457 : }
458 0 : }
459 :
460 : void
461 0 : ContentClientRemoteBuffer::Dump(std::stringstream& aStream,
462 : const char* aPrefix,
463 : bool aDumpHtml, TextureDumpMode aCompress)
464 : {
465 : // TODO We should combine the OnWhite/OnBlack here an just output a single image.
466 0 : if (!aDumpHtml) {
467 0 : aStream << "\n" << aPrefix << "Surface: ";
468 : }
469 0 : CompositableClient::DumpTextureClient(aStream, mTextureClient, aCompress);
470 0 : }
471 :
472 : void
473 0 : ContentClientDoubleBuffered::Dump(std::stringstream& aStream,
474 : const char* aPrefix,
475 : bool aDumpHtml, TextureDumpMode aCompress)
476 : {
477 : // TODO We should combine the OnWhite/OnBlack here an just output a single image.
478 0 : if (!aDumpHtml) {
479 0 : aStream << "\n" << aPrefix << "Surface: ";
480 : }
481 0 : CompositableClient::DumpTextureClient(aStream, mFrontClient, aCompress);
482 0 : }
483 :
484 : void
485 1 : ContentClientDoubleBuffered::DestroyFrontBuffer()
486 : {
487 1 : if (mFrontClient) {
488 1 : mOldTextures.AppendElement(mFrontClient);
489 1 : mFrontClient = nullptr;
490 : }
491 :
492 1 : if (mFrontClientOnWhite) {
493 0 : mOldTextures.AppendElement(mFrontClientOnWhite);
494 0 : mFrontClientOnWhite = nullptr;
495 : }
496 1 : }
497 :
498 : void
499 33 : ContentClientDoubleBuffered::Updated(const nsIntRegion& aRegionToDraw,
500 : const nsIntRegion& aVisibleRegion,
501 : bool aDidSelfCopy)
502 : {
503 33 : ContentClientRemoteBuffer::Updated(aRegionToDraw, aVisibleRegion, aDidSelfCopy);
504 33 : }
505 :
506 : void
507 33 : ContentClientDoubleBuffered::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
508 : {
509 33 : mFrontUpdatedRegion = aFrontUpdatedRegion;
510 :
511 66 : RefPtr<TextureClient> oldBack = mTextureClient;
512 33 : mTextureClient = mFrontClient;
513 33 : mFrontClient = oldBack;
514 :
515 33 : oldBack = mTextureClientOnWhite;
516 33 : mTextureClientOnWhite = mFrontClientOnWhite;
517 33 : mFrontClientOnWhite = oldBack;
518 :
519 33 : IntRect oldBufferRect = mBufferRect;
520 33 : mBufferRect = mFrontBufferRect;
521 33 : mFrontBufferRect = oldBufferRect;
522 :
523 33 : nsIntPoint oldBufferRotation = mBufferRotation;
524 33 : mBufferRotation = mFrontBufferRotation;
525 33 : mFrontBufferRotation = oldBufferRotation;
526 :
527 33 : MOZ_ASSERT(mFrontClient);
528 :
529 33 : ContentClientRemoteBuffer::SwapBuffers(aFrontUpdatedRegion);
530 33 : }
531 :
532 : void
533 77 : ContentClientDoubleBuffered::BeginPaint()
534 : {
535 77 : ContentClientRemoteBuffer::BeginPaint();
536 :
537 77 : mIsNewBuffer = false;
538 :
539 77 : if (!mFrontAndBackBufferDiffer) {
540 25 : return;
541 : }
542 :
543 52 : if (mDidSelfCopy) {
544 : // We can't easily draw our front buffer into us, since we're going to be
545 : // copying stuff around anyway it's easiest if we just move our situation
546 : // to non-rotated while we're at it. If this situation occurs we'll have
547 : // hit a self-copy path in PaintThebes before as well anyway.
548 0 : mBufferRect.MoveTo(mFrontBufferRect.TopLeft());
549 0 : mBufferRotation = nsIntPoint();
550 0 : return;
551 : }
552 52 : mBufferRect = mFrontBufferRect;
553 52 : mBufferRotation = mFrontBufferRotation;
554 : }
555 :
556 : // Sync front/back buffers content
557 : // After executing, the new back buffer has the same (interesting) pixels as
558 : // the new front buffer, and mValidRegion et al. are correct wrt the new
559 : // back buffer (i.e. as they were for the old back buffer)
560 : void
561 29 : ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
562 : {
563 29 : if (!mFrontAndBackBufferDiffer) {
564 0 : MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?");
565 16 : return;
566 : }
567 29 : MOZ_ASSERT(mFrontClient);
568 29 : if (!mFrontClient) {
569 0 : return;
570 : }
571 :
572 29 : MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
573 : this,
574 : mFrontUpdatedRegion.GetBounds().x,
575 : mFrontUpdatedRegion.GetBounds().y,
576 : mFrontUpdatedRegion.GetBounds().width,
577 : mFrontUpdatedRegion.GetBounds().height));
578 :
579 29 : mFrontAndBackBufferDiffer = false;
580 :
581 42 : nsIntRegion updateRegion = mFrontUpdatedRegion;
582 29 : if (mDidSelfCopy) {
583 0 : mDidSelfCopy = false;
584 0 : updateRegion = mBufferRect;
585 : }
586 :
587 : // No point in sync'ing what we are going to draw over anyway. And if there is
588 : // nothing to sync at all, there is nothing to do and we can go home early.
589 29 : updateRegion.Sub(updateRegion, aRegionToDraw);
590 29 : if (updateRegion.IsEmpty()) {
591 16 : return;
592 : }
593 :
594 : // We need to ensure that we lock these two buffers in the same
595 : // order as the compositor to prevent deadlocks.
596 26 : TextureClientAutoLock frontLock(mFrontClient, OpenMode::OPEN_READ_ONLY);
597 13 : if (!frontLock.Succeeded()) {
598 0 : return;
599 : }
600 26 : Maybe<TextureClientAutoLock> frontOnWhiteLock;
601 13 : if (mFrontClientOnWhite) {
602 0 : frontOnWhiteLock.emplace(mFrontClientOnWhite, OpenMode::OPEN_READ_ONLY);
603 0 : if (!frontOnWhiteLock->Succeeded()) {
604 0 : return;
605 : }
606 : }
607 :
608 : // Restrict the DrawTargets and frontBuffer to a scope to make
609 : // sure there is no more external references to the DrawTargets
610 : // when we Unlock the TextureClients.
611 13 : gfx::DrawTarget* dt = mFrontClient->BorrowDrawTarget();
612 13 : gfx::DrawTarget* dtw = mFrontClientOnWhite ? mFrontClientOnWhite->BorrowDrawTarget() : nullptr;
613 13 : if (dt && dt->IsValid()) {
614 26 : RefPtr<SourceSurface> surf = dt->Snapshot();
615 26 : RefPtr<SourceSurface> surfOnWhite = dtw ? dtw->Snapshot() : nullptr;
616 : SourceRotatedBuffer frontBuffer(surf,
617 : surfOnWhite,
618 : mFrontBufferRect,
619 26 : mFrontBufferRotation);
620 13 : UpdateDestinationFrom(frontBuffer, updateRegion);
621 : } else {
622 : // We know this can happen, but we want to track it somewhat, in case it leads
623 : // to other problems.
624 0 : gfxCriticalNote << "Invalid draw target(s) " << hexa(dt) << " and " << hexa(dtw);
625 : }
626 : }
627 :
628 : void
629 77 : ContentClientDoubleBuffered::EnsureBackBufferIfFrontBuffer()
630 : {
631 77 : if (!mTextureClient && mFrontClient) {
632 4 : CreateBackBuffer(mFrontBufferRect);
633 :
634 4 : mBufferRect = mFrontBufferRect;
635 4 : mBufferRotation = mFrontBufferRotation;
636 : }
637 77 : }
638 :
639 : void
640 13 : ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
641 : const nsIntRegion& aUpdateRegion)
642 : {
643 26 : DrawIterator iter;
644 : while (DrawTarget* destDT =
645 26 : BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
646 13 : bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
647 13 : if (isClippingCheap) {
648 13 : gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
649 : }
650 :
651 13 : aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
652 13 : if (isClippingCheap) {
653 13 : destDT->PopClip();
654 : }
655 : // Flush the destination before the sources become inaccessible (Unlock).
656 13 : destDT->Flush();
657 13 : ReturnDrawTargetToBuffer(destDT);
658 13 : }
659 :
660 13 : if (aSource.HaveBufferOnWhite()) {
661 0 : MOZ_ASSERT(HaveBufferOnWhite());
662 0 : DrawIterator whiteIter;
663 : while (DrawTarget* destDT =
664 0 : BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
665 0 : bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
666 0 : if (isClippingCheap) {
667 0 : gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
668 : }
669 :
670 0 : aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
671 0 : if (isClippingCheap) {
672 0 : destDT->PopClip();
673 : }
674 : // Flush the destination before the sources become inaccessible (Unlock).
675 0 : destDT->Flush();
676 0 : ReturnDrawTargetToBuffer(destDT);
677 0 : }
678 : }
679 13 : }
680 :
681 : } // namespace layers
682 : } // namespace mozilla
|