LCOV - code coverage report
Current view: top level - gfx/layers/client - ContentClient.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 185 299 61.9 %
Date: 2017-07-14 16:53:18 Functions: 21 30 70.0 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13