LCOV - code coverage report
Current view: top level - gfx/layers/composite - ImageHost.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 257 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 23 0.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 "ImageHost.h"
       7             : 
       8             : #include "LayersLogging.h"              // for AppendToString
       9             : #include "composite/CompositableHost.h"  // for CompositableHost, etc
      10             : #include "ipc/IPCMessageUtils.h"        // for null_t
      11             : #include "mozilla/layers/Compositor.h"  // for Compositor
      12             : #include "mozilla/layers/Effects.h"     // for TexturedEffect, Effect, etc
      13             : #include "mozilla/layers/LayerManagerComposite.h"     // for TexturedEffect, Effect, etc
      14             : #include "nsAString.h"
      15             : #include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
      16             : #include "nsPrintfCString.h"            // for nsPrintfCString
      17             : #include "nsString.h"                   // for nsAutoCString
      18             : 
      19             : namespace mozilla {
      20             : 
      21             : using namespace gfx;
      22             : 
      23             : namespace layers {
      24             : 
      25             : class ISurfaceAllocator;
      26             : 
      27           0 : ImageHost::ImageHost(const TextureInfo& aTextureInfo)
      28             :   : CompositableHost(aTextureInfo)
      29             :   , ImageComposite()
      30           0 :   , mLocked(false)
      31           0 : {}
      32             : 
      33           0 : ImageHost::~ImageHost()
      34             : {
      35           0 : }
      36             : 
      37             : void
      38           0 : ImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
      39             : {
      40           0 :   MOZ_ASSERT(!mLocked);
      41             : 
      42           0 :   CompositableHost::UseTextureHost(aTextures);
      43           0 :   MOZ_ASSERT(aTextures.Length() >= 1);
      44             : 
      45           0 :   nsTArray<TimedImage> newImages;
      46             : 
      47           0 :   for (uint32_t i = 0; i < aTextures.Length(); ++i) {
      48           0 :     const TimedTexture& t = aTextures[i];
      49           0 :     MOZ_ASSERT(t.mTexture);
      50           0 :     if (i + 1 < aTextures.Length() &&
      51           0 :         t.mProducerID == mLastProducerID && t.mFrameID < mLastFrameID) {
      52             :       // Ignore frames before a frame that we already composited. We don't
      53             :       // ever want to display these frames. This could be important if
      54             :       // the frame producer adjusts timestamps (e.g. to track the audio clock)
      55             :       // and the new frame times are earlier.
      56           0 :       continue;
      57             :     }
      58           0 :     TimedImage& img = *newImages.AppendElement();
      59           0 :     img.mTextureHost = t.mTexture;
      60           0 :     img.mTimeStamp = t.mTimeStamp;
      61           0 :     img.mPictureRect = t.mPictureRect;
      62           0 :     img.mFrameID = t.mFrameID;
      63           0 :     img.mProducerID = t.mProducerID;
      64           0 :     img.mTextureHost->SetCropRect(img.mPictureRect);
      65           0 :     img.mTextureHost->Updated();
      66             :   }
      67             : 
      68           0 :   mImages.SwapElements(newImages);
      69           0 :   newImages.Clear();
      70             : 
      71             :   // If we only have one image we can upload it right away, otherwise we'll upload
      72             :   // on-demand during composition after we have picked the proper timestamp.
      73           0 :   if (mImages.Length() == 1) {
      74           0 :     SetCurrentTextureHost(mImages[0].mTextureHost);
      75             :   }
      76             : 
      77           0 :   HostLayerManager* lm = GetLayerManager();
      78             : 
      79             :   // Video producers generally send replacement images with the same frameID but
      80             :   // slightly different timestamps in order to sync with the audio clock. This
      81             :   // means that any CompositeUntil() call we made in Composite() may no longer
      82             :   // guarantee that we'll composite until the next frame is ready. Fix that here.
      83           0 :   if (lm && mLastFrameID >= 0) {
      84           0 :     for (size_t i = 0; i < mImages.Length(); ++i) {
      85           0 :       bool frameComesAfter = mImages[i].mFrameID > mLastFrameID ||
      86           0 :                              mImages[i].mProducerID != mLastProducerID;
      87           0 :       if (frameComesAfter && !mImages[i].mTimeStamp.IsNull()) {
      88           0 :         lm->CompositeUntil(mImages[i].mTimeStamp +
      89           0 :                            TimeDuration::FromMilliseconds(BIAS_TIME_MS));
      90           0 :         break;
      91             :       }
      92             :     }
      93             :   }
      94           0 : }
      95             : 
      96             : void
      97           0 : ImageHost::SetCurrentTextureHost(TextureHost* aTexture)
      98             : {
      99           0 :   if (aTexture == mCurrentTextureHost.get()) {
     100           0 :     return;
     101             :   }
     102             : 
     103           0 :   bool swapTextureSources = !!mCurrentTextureHost && !!mCurrentTextureSource
     104           0 :                             && mCurrentTextureHost->HasIntermediateBuffer();
     105             : 
     106           0 :   if (swapTextureSources) {
     107           0 :     auto dataSource = mCurrentTextureSource->AsDataTextureSource();
     108           0 :     if (dataSource) {
     109             :       // The current textureHost has an internal buffer in the form of the
     110             :       // DataTextureSource. Removing the ownership of the texture source
     111             :       // will enable the next texture host we bind to the texture source to
     112             :       // acquire it instead of creating a new one. This is desirable in
     113             :       // ImageHost because the current texture won't be used again with the
     114             :       // same content. It wouldn't be desirable with ContentHost for instance,
     115             :       // because the latter reuses the texture's valid regions.
     116           0 :       dataSource->SetOwner(nullptr);
     117             :     }
     118             : 
     119           0 :     RefPtr<TextureSource> tmp = mExtraTextureSource;
     120           0 :     mExtraTextureSource = mCurrentTextureSource.get();
     121           0 :     mCurrentTextureSource = tmp;
     122             :   } else {
     123           0 :     mExtraTextureSource = nullptr;
     124             :   }
     125             : 
     126           0 :   mCurrentTextureHost = aTexture;
     127           0 :   mCurrentTextureHost->PrepareTextureSource(mCurrentTextureSource);
     128             : }
     129             : 
     130             : void
     131           0 : ImageHost::CleanupResources()
     132             : {
     133           0 :   mExtraTextureSource = nullptr;
     134           0 :   mCurrentTextureSource = nullptr;
     135           0 :   mCurrentTextureHost = nullptr;
     136           0 : }
     137             : 
     138             : void
     139           0 : ImageHost::RemoveTextureHost(TextureHost* aTexture)
     140             : {
     141           0 :   MOZ_ASSERT(!mLocked);
     142             : 
     143           0 :   CompositableHost::RemoveTextureHost(aTexture);
     144             : 
     145           0 :   for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
     146           0 :     if (mImages[i].mTextureHost == aTexture) {
     147           0 :       aTexture->UnbindTextureSource();
     148           0 :       mImages.RemoveElementAt(i);
     149             :     }
     150             :   }
     151           0 : }
     152             : 
     153             : TimeStamp
     154           0 : ImageHost::GetCompositionTime() const
     155             : {
     156           0 :   TimeStamp time;
     157           0 :   if (HostLayerManager* lm = GetLayerManager()) {
     158           0 :     time = lm->GetCompositionTime();
     159             :   }
     160           0 :   return time;
     161             : }
     162             : 
     163             : TextureHost*
     164           0 : ImageHost::GetAsTextureHost(IntRect* aPictureRect)
     165             : {
     166           0 :   TimedImage* img = ChooseImage();
     167           0 :   if (img) {
     168           0 :     SetCurrentTextureHost(img->mTextureHost);
     169             :   }
     170           0 :   if (aPictureRect && img) {
     171           0 :     *aPictureRect = img->mPictureRect;
     172             :   }
     173           0 :   return img ? img->mTextureHost.get() : nullptr;
     174             : }
     175             : 
     176           0 : void ImageHost::Attach(Layer* aLayer,
     177             :                        TextureSourceProvider* aProvider,
     178             :                        AttachFlags aFlags)
     179             : {
     180           0 :   CompositableHost::Attach(aLayer, aProvider, aFlags);
     181           0 :   for (auto& img : mImages) {
     182           0 :     img.mTextureHost->SetTextureSourceProvider(aProvider);
     183           0 :     img.mTextureHost->Updated();
     184             :   }
     185           0 : }
     186             : 
     187             : void
     188           0 : ImageHost::Composite(Compositor* aCompositor,
     189             :                      LayerComposite* aLayer,
     190             :                      EffectChain& aEffectChain,
     191             :                      float aOpacity,
     192             :                      const gfx::Matrix4x4& aTransform,
     193             :                      const gfx::SamplingFilter aSamplingFilter,
     194             :                      const gfx::IntRect& aClipRect,
     195             :                      const nsIntRegion* aVisibleRegion,
     196             :                      const Maybe<gfx::Polygon>& aGeometry)
     197             : {
     198           0 :   RenderInfo info;
     199           0 :   if (!PrepareToRender(aCompositor, &info)) {
     200           0 :     return;
     201             :   }
     202             : 
     203           0 :   TimedImage* img = info.img;
     204             : 
     205             :   {
     206           0 :     AutoLockCompositableHost autoLock(this);
     207           0 :     if (autoLock.Failed()) {
     208           0 :       NS_WARNING("failed to lock front buffer");
     209           0 :       return;
     210             :     }
     211             : 
     212           0 :     if (!mCurrentTextureHost->BindTextureSource(mCurrentTextureSource)) {
     213           0 :       return;
     214             :     }
     215             : 
     216           0 :     if (!mCurrentTextureSource) {
     217             :       // BindTextureSource above should have returned false!
     218           0 :       MOZ_ASSERT(false);
     219             :       return;
     220             :     }
     221             : 
     222             :     bool isAlphaPremultiplied =
     223           0 :         !(mCurrentTextureHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED);
     224             :     RefPtr<TexturedEffect> effect =
     225           0 :         CreateTexturedEffect(mCurrentTextureHost,
     226           0 :             mCurrentTextureSource.get(), aSamplingFilter, isAlphaPremultiplied);
     227           0 :     if (!effect) {
     228           0 :       return;
     229             :     }
     230             : 
     231           0 :     if (!aCompositor->SupportsEffect(effect->mType)) {
     232           0 :       return;
     233             :     }
     234             : 
     235           0 :     DiagnosticFlags diagnosticFlags = DiagnosticFlags::IMAGE;
     236           0 :     if (effect->mType == EffectTypes::NV12) {
     237           0 :       diagnosticFlags |= DiagnosticFlags::NV12;
     238           0 :     } else if (effect->mType == EffectTypes::YCBCR) {
     239           0 :       diagnosticFlags |= DiagnosticFlags::YCBCR;
     240             :     }
     241             : 
     242           0 :     aEffectChain.mPrimaryEffect = effect;
     243           0 :     gfx::Rect pictureRect(0, 0, img->mPictureRect.width, img->mPictureRect.height);
     244           0 :     BigImageIterator* it = mCurrentTextureSource->AsBigImageIterator();
     245           0 :     if (it) {
     246             : 
     247             :       // This iteration does not work if we have multiple texture sources here
     248             :       // (e.g. 3 YCbCr textures). There's nothing preventing the different
     249             :       // planes from having different resolutions or tile sizes. For example, a
     250             :       // YCbCr frame could have Cb and Cr planes that are half the resolution of
     251             :       // the Y plane, in such a way that the Y plane overflows the maximum
     252             :       // texture size and the Cb and Cr planes do not. Then the Y plane would be
     253             :       // split into multiple tiles and the Cb and Cr planes would just be one
     254             :       // tile each.
     255             :       // To handle the general case correctly, we'd have to create a grid of
     256             :       // intersected tiles over all planes, and then draw each grid tile using
     257             :       // the corresponding source tiles from all planes, with appropriate
     258             :       // per-plane per-tile texture coords.
     259             :       // DrawQuad currently assumes that all planes use the same texture coords.
     260           0 :       MOZ_ASSERT(it->GetTileCount() == 1 || !mCurrentTextureSource->GetNextSibling(),
     261             :                  "Can't handle multi-plane BigImages");
     262             : 
     263           0 :       it->BeginBigImageIteration();
     264           0 :       do {
     265           0 :         IntRect tileRect = it->GetTileRect();
     266           0 :         gfx::Rect rect(tileRect.x, tileRect.y, tileRect.width, tileRect.height);
     267           0 :         rect = rect.Intersect(pictureRect);
     268           0 :         effect->mTextureCoords = Rect(Float(rect.x - tileRect.x) / tileRect.width,
     269           0 :                                       Float(rect.y - tileRect.y) / tileRect.height,
     270           0 :                                       Float(rect.width) / tileRect.width,
     271           0 :                                       Float(rect.height) / tileRect.height);
     272           0 :         if (img->mTextureHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
     273           0 :           effect->mTextureCoords.y = effect->mTextureCoords.YMost();
     274           0 :           effect->mTextureCoords.height = -effect->mTextureCoords.height;
     275             :         }
     276             :         aCompositor->DrawGeometry(rect, aClipRect, aEffectChain,
     277           0 :                                   aOpacity, aTransform, aGeometry);
     278           0 :         aCompositor->DrawDiagnostics(diagnosticFlags | DiagnosticFlags::BIGIMAGE,
     279           0 :                                      rect, aClipRect, aTransform, mFlashCounter);
     280           0 :       } while (it->NextTile());
     281           0 :       it->EndBigImageIteration();
     282             :       // layer border
     283           0 :       aCompositor->DrawDiagnostics(diagnosticFlags, pictureRect,
     284           0 :                                    aClipRect, aTransform, mFlashCounter);
     285             :     } else {
     286           0 :       IntSize textureSize = mCurrentTextureSource->GetSize();
     287           0 :       effect->mTextureCoords = Rect(Float(img->mPictureRect.x) / textureSize.width,
     288           0 :                                     Float(img->mPictureRect.y) / textureSize.height,
     289           0 :                                     Float(img->mPictureRect.width) / textureSize.width,
     290           0 :                                     Float(img->mPictureRect.height) / textureSize.height);
     291             : 
     292           0 :       if (img->mTextureHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
     293           0 :         effect->mTextureCoords.y = effect->mTextureCoords.YMost();
     294           0 :         effect->mTextureCoords.height = -effect->mTextureCoords.height;
     295             :       }
     296             : 
     297             :       aCompositor->DrawGeometry(pictureRect, aClipRect, aEffectChain,
     298           0 :                                 aOpacity, aTransform, aGeometry);
     299           0 :       aCompositor->DrawDiagnostics(diagnosticFlags,
     300             :                                    pictureRect, aClipRect,
     301           0 :                                    aTransform, mFlashCounter);
     302             :     }
     303             :   }
     304             : 
     305           0 :   FinishRendering(info);
     306             : }
     307             : 
     308             : bool
     309           0 : ImageHost::PrepareToRender(TextureSourceProvider* aProvider, RenderInfo* aOutInfo)
     310             : {
     311           0 :   HostLayerManager* lm = GetLayerManager();
     312           0 :   if (!lm) {
     313           0 :     return false;
     314             :   }
     315             : 
     316           0 :   int imageIndex = ChooseImageIndex();
     317           0 :   if (imageIndex < 0) {
     318           0 :     return false;
     319             :   }
     320             : 
     321           0 :   if (uint32_t(imageIndex) + 1 < mImages.Length()) {
     322           0 :     lm->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
     323             :   }
     324             : 
     325           0 :   TimedImage* img = &mImages[imageIndex];
     326           0 :   img->mTextureHost->SetTextureSourceProvider(aProvider);
     327           0 :   SetCurrentTextureHost(img->mTextureHost);
     328             : 
     329           0 :   aOutInfo->imageIndex = imageIndex;
     330           0 :   aOutInfo->img = img;
     331           0 :   aOutInfo->host = mCurrentTextureHost;
     332           0 :   return true;
     333             : }
     334             : 
     335             : RefPtr<TextureSource>
     336           0 : ImageHost::AcquireTextureSource(const RenderInfo& aInfo)
     337             : {
     338           0 :   MOZ_ASSERT(aInfo.host == mCurrentTextureHost);
     339           0 :   if (!aInfo.host->AcquireTextureSource(mCurrentTextureSource)) {
     340           0 :     return nullptr;
     341             :   }
     342           0 :   return mCurrentTextureSource.get();
     343             : }
     344             : 
     345             : void
     346           0 : ImageHost::FinishRendering(const RenderInfo& aInfo)
     347             : {
     348           0 :   HostLayerManager* lm = GetLayerManager();
     349           0 :   TimedImage* img = aInfo.img;
     350           0 :   int imageIndex = aInfo.imageIndex;
     351             : 
     352           0 :   if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
     353           0 :     if (mAsyncRef) {
     354           0 :       ImageCompositeNotificationInfo info;
     355           0 :       info.mImageBridgeProcessId = mAsyncRef.mProcessId;
     356           0 :       info.mNotification = ImageCompositeNotification(
     357             :         mAsyncRef.mHandle,
     358           0 :         img->mTimeStamp, lm->GetCompositionTime(),
     359           0 :         img->mFrameID, img->mProducerID);
     360           0 :       lm->AppendImageCompositeNotification(info);
     361             :     }
     362           0 :     mLastFrameID = img->mFrameID;
     363           0 :     mLastProducerID = img->mProducerID;
     364             :   }
     365             : 
     366             :   // Update mBias last. This can change which frame ChooseImage(Index) would
     367             :   // return, and we don't want to do that until we've finished compositing
     368             :   // since callers of ChooseImage(Index) assume the same image will be chosen
     369             :   // during a given composition. This must happen after autoLock's
     370             :   // destructor!
     371           0 :   mBias = UpdateBias(
     372           0 :       lm->GetCompositionTime(), mImages[imageIndex].mTimeStamp,
     373           0 :       uint32_t(imageIndex + 1) < mImages.Length() ?
     374           0 :           mImages[imageIndex + 1].mTimeStamp : TimeStamp(),
     375             :       mBias);
     376           0 : }
     377             : 
     378             : void
     379           0 : ImageHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
     380             : {
     381           0 :   if (mTextureSourceProvider != aProvider) {
     382           0 :     for (auto& img : mImages) {
     383           0 :       img.mTextureHost->SetTextureSourceProvider(aProvider);
     384             :     }
     385             :   }
     386           0 :   CompositableHost::SetTextureSourceProvider(aProvider);
     387           0 : }
     388             : 
     389             : void
     390           0 : ImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
     391             : {
     392           0 :   aStream << aPrefix;
     393           0 :   aStream << nsPrintfCString("ImageHost (0x%p)", this).get();
     394             : 
     395           0 :   nsAutoCString pfx(aPrefix);
     396           0 :   pfx += "  ";
     397           0 :   for (auto& img : mImages) {
     398           0 :     aStream << "\n";
     399           0 :     img.mTextureHost->PrintInfo(aStream, pfx.get());
     400           0 :     AppendToString(aStream, img.mPictureRect, " [picture-rect=", "]");
     401             :   }
     402           0 : }
     403             : 
     404             : void
     405           0 : ImageHost::Dump(std::stringstream& aStream,
     406             :                 const char* aPrefix,
     407             :                 bool aDumpHtml)
     408             : {
     409           0 :   for (auto& img : mImages) {
     410           0 :     aStream << aPrefix;
     411             :     aStream << (aDumpHtml ? "<ul><li>TextureHost: "
     412           0 :                              : "TextureHost: ");
     413           0 :     DumpTextureHost(aStream, img.mTextureHost);
     414           0 :     aStream << (aDumpHtml ? " </li></ul> " : " ");
     415             :   }
     416           0 : }
     417             : 
     418             : already_AddRefed<gfx::DataSourceSurface>
     419           0 : ImageHost::GetAsSurface()
     420             : {
     421           0 :   TimedImage* img = ChooseImage();
     422           0 :   if (img) {
     423           0 :     return img->mTextureHost->GetAsSurface();
     424             :   }
     425           0 :   return nullptr;
     426             : }
     427             : 
     428             : bool
     429           0 : ImageHost::Lock()
     430             : {
     431           0 :   MOZ_ASSERT(!mLocked);
     432           0 :   TimedImage* img = ChooseImage();
     433           0 :   if (!img) {
     434           0 :     return false;
     435             :   }
     436             : 
     437           0 :   SetCurrentTextureHost(img->mTextureHost);
     438             : 
     439           0 :   if (!mCurrentTextureHost->Lock()) {
     440           0 :     return false;
     441             :   }
     442           0 :   mLocked = true;
     443           0 :   return true;
     444             : }
     445             : 
     446             : void
     447           0 : ImageHost::Unlock()
     448             : {
     449           0 :   MOZ_ASSERT(mLocked);
     450             : 
     451           0 :   if (mCurrentTextureHost) {
     452           0 :     mCurrentTextureHost->Unlock();
     453             :   }
     454           0 :   mLocked = false;
     455           0 : }
     456             : 
     457             : IntSize
     458           0 : ImageHost::GetImageSize() const
     459             : {
     460           0 :   const TimedImage* img = ChooseImage();
     461           0 :   if (img) {
     462           0 :     return IntSize(img->mPictureRect.width, img->mPictureRect.height);
     463             :   }
     464           0 :   return IntSize();
     465             : }
     466             : 
     467             : bool
     468           0 : ImageHost::IsOpaque()
     469             : {
     470           0 :   const TimedImage* img = ChooseImage();
     471           0 :   if (!img) {
     472           0 :     return false;
     473             :   }
     474             : 
     475           0 :   if (img->mPictureRect.width == 0 ||
     476           0 :       img->mPictureRect.height == 0 ||
     477           0 :       !img->mTextureHost) {
     478           0 :     return false;
     479             :   }
     480             : 
     481           0 :   gfx::SurfaceFormat format = img->mTextureHost->GetFormat();
     482           0 :   if (gfx::IsOpaque(format)) {
     483           0 :     return true;
     484             :   }
     485           0 :   return false;
     486             : }
     487             : 
     488             : already_AddRefed<TexturedEffect>
     489           0 : ImageHost::GenEffect(const gfx::SamplingFilter aSamplingFilter)
     490             : {
     491           0 :   TimedImage* img = ChooseImage();
     492           0 :   if (!img) {
     493           0 :     return nullptr;
     494             :   }
     495           0 :   SetCurrentTextureHost(img->mTextureHost);
     496           0 :   if (!mCurrentTextureHost->BindTextureSource(mCurrentTextureSource)) {
     497           0 :     return nullptr;
     498             :   }
     499           0 :   bool isAlphaPremultiplied = true;
     500           0 :   if (mCurrentTextureHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED) {
     501           0 :     isAlphaPremultiplied = false;
     502             :   }
     503             : 
     504             :   return CreateTexturedEffect(mCurrentTextureHost,
     505             :                               mCurrentTextureSource,
     506             :                               aSamplingFilter,
     507           0 :                               isAlphaPremultiplied);
     508             : }
     509             : 
     510             : } // namespace layers
     511             : } // namespace mozilla

Generated by: LCOV version 1.13