gfx/layers/composite/TiledContentHost.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     6 #include "TiledContentHost.h"
     7 #include "ThebesLayerComposite.h"       // for ThebesLayerComposite
     8 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
     9 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
    10 #include "mozilla/layers/Compositor.h"  // for Compositor
    11 #include "mozilla/layers/Effects.h"     // for TexturedEffect, Effect, etc
    12 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
    13 #include "nsAString.h"
    14 #include "nsDebug.h"                    // for NS_WARNING
    15 #include "nsPoint.h"                    // for nsIntPoint
    16 #include "nsPrintfCString.h"            // for nsPrintfCString
    17 #include "nsRect.h"                     // for nsIntRect
    18 #include "nsSize.h"                     // for nsIntSize
    19 #include "mozilla/layers/TiledContentClient.h"
    21 class gfxReusableSurfaceWrapper;
    23 namespace mozilla {
    24 using namespace gfx;
    25 namespace layers {
    27 class Layer;
    29 TiledLayerBufferComposite::TiledLayerBufferComposite()
    30   : mFrameResolution(1.0)
    31   , mHasDoubleBufferedTiles(false)
    32   , mUninitialized(true)
    33 {}
    35 /* static */ void
    36 TiledLayerBufferComposite::RecycleCallback(TextureHost* textureHost, void* aClosure)
    37 {
    38   textureHost->CompositorRecycle();
    39 }
    41 TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
    42                                                      const SurfaceDescriptorTiles& aDescriptor,
    43                                                      const nsIntRegion& aOldPaintedRegion)
    44 {
    45   mUninitialized = false;
    46   mHasDoubleBufferedTiles = false;
    47   mValidRegion = aDescriptor.validRegion();
    48   mPaintedRegion = aDescriptor.paintedRegion();
    49   mRetainedWidth = aDescriptor.retainedWidth();
    50   mRetainedHeight = aDescriptor.retainedHeight();
    51   mResolution = aDescriptor.resolution();
    52   mFrameResolution = CSSToParentLayerScale(aDescriptor.frameResolution());
    54   // Combine any valid content that wasn't already uploaded
    55   nsIntRegion oldPaintedRegion(aOldPaintedRegion);
    56   oldPaintedRegion.And(oldPaintedRegion, mValidRegion);
    57   mPaintedRegion.Or(mPaintedRegion, oldPaintedRegion);
    59   const InfallibleTArray<TileDescriptor>& tiles = aDescriptor.tiles();
    60   for(size_t i = 0; i < tiles.Length(); i++) {
    61     RefPtr<TextureHost> texture;
    62     const TileDescriptor& tileDesc = tiles[i];
    63     switch (tileDesc.type()) {
    64       case TileDescriptor::TTexturedTileDescriptor : {
    65         texture = TextureHost::AsTextureHost(tileDesc.get_TexturedTileDescriptor().textureParent());
    66 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
    67         if (!gfxPrefs::LayersUseSimpleTiles()) {
    68           texture->SetRecycleCallback(RecycleCallback, nullptr);
    69         }
    70 #endif
    71         const TileLock& ipcLock = tileDesc.get_TexturedTileDescriptor().sharedLock();
    72         nsRefPtr<gfxSharedReadLock> sharedLock;
    73         if (ipcLock.type() == TileLock::TShmemSection) {
    74           sharedLock = gfxShmSharedReadLock::Open(aAllocator, ipcLock.get_ShmemSection());
    75         } else {
    76           sharedLock = reinterpret_cast<gfxMemorySharedReadLock*>(ipcLock.get_uintptr_t());
    77           if (sharedLock) {
    78             // The corresponding AddRef is in TiledClient::GetTileDescriptor
    79             sharedLock->Release();
    80           }
    81         }
    83         mRetainedTiles.AppendElement(TileHost(sharedLock, texture));
    84         break;
    85       }
    86       default:
    87         NS_WARNING("Unrecognised tile descriptor type");
    88         // Fall through
    89       case TileDescriptor::TPlaceholderTileDescriptor :
    90         mRetainedTiles.AppendElement(GetPlaceholderTile());
    91         break;
    92     }
    93     if (texture && !texture->HasInternalBuffer()) {
    94       mHasDoubleBufferedTiles = true;
    95     }
    96   }
    97 }
    99 void
   100 TiledLayerBufferComposite::ReadUnlock()
   101 {
   102   if (!IsValid()) {
   103     return;
   104   }
   105   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
   106     mRetainedTiles[i].ReadUnlock();
   107   }
   108 }
   110 void
   111 TiledLayerBufferComposite::ReleaseTextureHosts()
   112 {
   113   if (!IsValid()) {
   114     return;
   115   }
   116   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
   117     mRetainedTiles[i].mTextureHost = nullptr;
   118   }
   119 }
   121 void
   122 TiledLayerBufferComposite::Upload()
   123 {
   124   if(!IsValid()) {
   125     return;
   126   }
   127   // The TextureClients were created with the TEXTURE_IMMEDIATE_UPLOAD flag,
   128   // so calling Update on all the texture hosts will perform the texture upload.
   129   Update(mValidRegion, mPaintedRegion);
   130   ClearPaintedRegion();
   131 }
   133 TileHost
   134 TiledLayerBufferComposite::ValidateTile(TileHost aTile,
   135                                         const nsIntPoint& aTileOrigin,
   136                                         const nsIntRegion& aDirtyRect)
   137 {
   138   if (aTile.IsPlaceholderTile()) {
   139     NS_WARNING("Placeholder tile encountered in painted region");
   140     return aTile;
   141   }
   143 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   144   printf_stderr("Upload tile %i, %i\n", aTileOrigin.x, aTileOrigin.y);
   145   long start = PR_IntervalNow();
   146 #endif
   148   MOZ_ASSERT(aTile.mTextureHost->GetFlags() & TEXTURE_IMMEDIATE_UPLOAD);
   149   // We possibly upload the entire texture contents here. This is a purposeful
   150   // decision, as sub-image upload can often be slow and/or unreliable, but
   151   // we may want to reevaluate this in the future.
   152   // For !HasInternalBuffer() textures, this is likely a no-op.
   153   aTile.mTextureHost->Updated(nullptr);
   155 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   156   if (PR_IntervalNow() - start > 1) {
   157     printf_stderr("Tile Time to upload %i\n", PR_IntervalNow() - start);
   158   }
   159 #endif
   160   return aTile;
   161 }
   163 void
   164 TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor)
   165 {
   166   if (!IsValid()) {
   167     return;
   168   }
   169   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
   170     if (mRetainedTiles[i].IsPlaceholderTile()) continue;
   171     mRetainedTiles[i].mTextureHost->SetCompositor(aCompositor);
   172   }
   173 }
   175 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   176 void
   177 TiledLayerBufferComposite::SetReleaseFence(const android::sp<android::Fence>& aReleaseFence)
   178 {
   179   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
   180     if (!mRetainedTiles[i].mTextureHost) {
   181       continue;
   182     }
   183     TextureHostOGL* texture = mRetainedTiles[i].mTextureHost->AsHostOGL();
   184     if (!texture) {
   185       continue;
   186     }
   187     texture->SetReleaseFence(new android::Fence(aReleaseFence->dup()));
   188   }
   189 }
   190 #endif
   192 TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
   193   : ContentHost(aTextureInfo)
   194   , mTiledBuffer(TiledLayerBufferComposite())
   195   , mLowPrecisionTiledBuffer(TiledLayerBufferComposite())
   196   , mOldTiledBuffer(TiledLayerBufferComposite())
   197   , mOldLowPrecisionTiledBuffer(TiledLayerBufferComposite())
   198   , mPendingUpload(false)
   199   , mPendingLowPrecisionUpload(false)
   200 {
   201   MOZ_COUNT_CTOR(TiledContentHost);
   202 }
   204 TiledContentHost::~TiledContentHost()
   205 {
   206   MOZ_COUNT_DTOR(TiledContentHost);
   208   // Unlock any buffers that may still be locked. If we have a pending upload,
   209   // we will need to unlock the buffer that was about to be uploaded.
   210   // If a buffer that was being composited had double-buffered tiles, we will
   211   // need to unlock that buffer too.
   212   if (mPendingUpload) {
   213     mTiledBuffer.ReadUnlock();
   214     if (mOldTiledBuffer.HasDoubleBufferedTiles()) {
   215       mOldTiledBuffer.ReadUnlock();
   216     }
   217   } else if (mTiledBuffer.HasDoubleBufferedTiles()) {
   218     mTiledBuffer.ReadUnlock();
   219   }
   221   if (mPendingLowPrecisionUpload) {
   222     mLowPrecisionTiledBuffer.ReadUnlock();
   223     if (mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
   224       mOldLowPrecisionTiledBuffer.ReadUnlock();
   225     }
   226   } else if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
   227     mLowPrecisionTiledBuffer.ReadUnlock();
   228   }
   229 }
   231 void
   232 TiledContentHost::Attach(Layer* aLayer,
   233                          Compositor* aCompositor,
   234                          AttachFlags aFlags /* = NO_FLAGS */)
   235 {
   236   CompositableHost::Attach(aLayer, aCompositor, aFlags);
   237   static_cast<ThebesLayerComposite*>(aLayer)->EnsureTiled();
   238 }
   240 void
   241 TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
   242                                       const SurfaceDescriptorTiles& aTiledDescriptor)
   243 {
   244   if (aTiledDescriptor.resolution() < 1) {
   245     if (mPendingLowPrecisionUpload) {
   246       mLowPrecisionTiledBuffer.ReadUnlock();
   247     } else {
   248       mPendingLowPrecisionUpload = true;
   249       // If the old buffer has double-buffered tiles, hang onto it so we can
   250       // unlock it after we've composited the new buffer.
   251       // We only need to hang onto the locks, but not the textures.
   252       // Releasing the textures here can help prevent a memory spike in the
   253       // situation that the client starts rendering new content before we get
   254       // to composite the new buffer.
   255       if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
   256         mOldLowPrecisionTiledBuffer = mLowPrecisionTiledBuffer;
   257         mOldLowPrecisionTiledBuffer.ReleaseTextureHosts();
   258       }
   259     }
   260     mLowPrecisionTiledBuffer =
   261       TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
   262                                 mLowPrecisionTiledBuffer.GetPaintedRegion());
   263   } else {
   264     if (mPendingUpload) {
   265       mTiledBuffer.ReadUnlock();
   266     } else {
   267       mPendingUpload = true;
   268       if (mTiledBuffer.HasDoubleBufferedTiles()) {
   269         mOldTiledBuffer = mTiledBuffer;
   270         mOldTiledBuffer.ReleaseTextureHosts();
   271       }
   272     }
   273     mTiledBuffer = TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
   274                                              mTiledBuffer.GetPaintedRegion());
   275   }
   276 }
   278 void
   279 TiledContentHost::Composite(EffectChain& aEffectChain,
   280                             float aOpacity,
   281                             const gfx::Matrix4x4& aTransform,
   282                             const gfx::Filter& aFilter,
   283                             const gfx::Rect& aClipRect,
   284                             const nsIntRegion* aVisibleRegion /* = nullptr */,
   285                             TiledLayerProperties* aLayerProperties /* = nullptr */)
   286 {
   287   MOZ_ASSERT(aLayerProperties, "aLayerProperties required for TiledContentHost");
   289   if (mPendingUpload) {
   290     mTiledBuffer.SetCompositor(mCompositor);
   291     mTiledBuffer.Upload();
   293     // For a single-buffered tiled buffer, Upload will upload the shared memory
   294     // surface to texture memory and we no longer need to read from them.
   295     if (!mTiledBuffer.HasDoubleBufferedTiles()) {
   296       mTiledBuffer.ReadUnlock();
   297     }
   298   }
   299   if (mPendingLowPrecisionUpload) {
   300     mLowPrecisionTiledBuffer.SetCompositor(mCompositor);
   301     mLowPrecisionTiledBuffer.Upload();
   303     if (!mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
   304       mLowPrecisionTiledBuffer.ReadUnlock();
   305     }
   306   }
   308   RenderLayerBuffer(mLowPrecisionTiledBuffer, aEffectChain, aOpacity, aFilter,
   309                     aClipRect, aLayerProperties->mVisibleRegion, aTransform);
   310   RenderLayerBuffer(mTiledBuffer, aEffectChain, aOpacity, aFilter,
   311                     aClipRect, aLayerProperties->mVisibleRegion, aTransform);
   313   // Now release the old buffer if it had double-buffered tiles, as we can
   314   // guarantee that they're no longer on the screen (and so any locks that may
   315   // have been held have been released).
   316   if (mPendingUpload && mOldTiledBuffer.HasDoubleBufferedTiles()) {
   317     mOldTiledBuffer.ReadUnlock();
   318     mOldTiledBuffer = TiledLayerBufferComposite();
   319   }
   320   if (mPendingLowPrecisionUpload && mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
   321     mOldLowPrecisionTiledBuffer.ReadUnlock();
   322     mOldLowPrecisionTiledBuffer = TiledLayerBufferComposite();
   323   }
   324   mPendingUpload = mPendingLowPrecisionUpload = false;
   325 }
   328 void
   329 TiledContentHost::RenderTile(const TileHost& aTile,
   330                              EffectChain& aEffectChain,
   331                              float aOpacity,
   332                              const gfx::Matrix4x4& aTransform,
   333                              const gfx::Filter& aFilter,
   334                              const gfx::Rect& aClipRect,
   335                              const nsIntRegion& aScreenRegion,
   336                              const nsIntPoint& aTextureOffset,
   337                              const nsIntSize& aTextureBounds)
   338 {
   339   if (aTile.IsPlaceholderTile()) {
   340     // This shouldn't ever happen, but let's fail semi-gracefully. No need
   341     // to warn, the texture update would have already caught this.
   342     return;
   343   }
   345   nsIntRect screenBounds = aScreenRegion.GetBounds();
   346   Rect quad(screenBounds.x, screenBounds.y, screenBounds.width, screenBounds.height);
   347   quad = aTransform.TransformBounds(quad);
   349   if (!quad.Intersects(mCompositor->ClipRectInLayersCoordinates(aClipRect))) {
   350     return;
   351   }
   353   AutoLockTextureHost autoLock(aTile.mTextureHost);
   354   if (autoLock.Failed()) {
   355     NS_WARNING("Failed to lock tile");
   356     return;
   357   }
   358   RefPtr<NewTextureSource> source = aTile.mTextureHost->GetTextureSources();
   359   if (!source) {
   360     return;
   361   }
   363   RefPtr<TexturedEffect> effect =
   364     CreateTexturedEffect(aTile.mTextureHost->GetFormat(), source, aFilter);
   365   if (!effect) {
   366     return;
   367   }
   369   aEffectChain.mPrimaryEffect = effect;
   371   nsIntRegionRectIterator it(aScreenRegion);
   372   for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
   373     Rect graphicsRect(rect->x, rect->y, rect->width, rect->height);
   374     Rect textureRect(rect->x - aTextureOffset.x, rect->y - aTextureOffset.y,
   375                      rect->width, rect->height);
   377     effect->mTextureCoords = Rect(textureRect.x / aTextureBounds.width,
   378                                   textureRect.y / aTextureBounds.height,
   379                                   textureRect.width / aTextureBounds.width,
   380                                   textureRect.height / aTextureBounds.height);
   381     mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform);
   382   }
   383   mCompositor->DrawDiagnostics(DIAGNOSTIC_CONTENT|DIAGNOSTIC_TILE,
   384                                aScreenRegion, aClipRect, aTransform, mFlashCounter);
   385 }
   387 void
   388 TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
   389                                     EffectChain& aEffectChain,
   390                                     float aOpacity,
   391                                     const gfx::Filter& aFilter,
   392                                     const gfx::Rect& aClipRect,
   393                                     nsIntRegion aVisibleRegion,
   394                                     gfx::Matrix4x4 aTransform)
   395 {
   396   if (!mCompositor) {
   397     NS_WARNING("Can't render tiled content host - no compositor");
   398     return;
   399   }
   400   float resolution = aLayerBuffer.GetResolution();
   401   gfx::Size layerScale(1, 1);
   403   // We assume that the current frame resolution is the one used in our high
   404   // precision layer buffer. Compensate for a changing frame resolution when
   405   // rendering the low precision buffer.
   406   if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
   407     const CSSToParentLayerScale& layerResolution = aLayerBuffer.GetFrameResolution();
   408     const CSSToParentLayerScale& localResolution = mTiledBuffer.GetFrameResolution();
   409     layerScale.width = layerScale.height = layerResolution.scale / localResolution.scale;
   410     aVisibleRegion.ScaleRoundOut(layerScale.width, layerScale.height);
   411   }
   413   // If we're drawing the low precision buffer, make sure the high precision
   414   // buffer is masked out to avoid overdraw and rendering artifacts with
   415   // non-opaque layers.
   416   nsIntRegion maskRegion;
   417   if (resolution != mTiledBuffer.GetResolution()) {
   418     maskRegion = mTiledBuffer.GetValidRegion();
   419     // XXX This should be ScaleRoundIn, but there is no such function on
   420     //     nsIntRegion.
   421     maskRegion.ScaleRoundOut(layerScale.width, layerScale.height);
   422   }
   424   // Make sure the resolution and difference in frame resolution are accounted
   425   // for in the layer transform.
   426   aTransform.Scale(1/(resolution * layerScale.width),
   427                    1/(resolution * layerScale.height), 1);
   429   uint32_t rowCount = 0;
   430   uint32_t tileX = 0;
   431   nsIntRect visibleRect = aVisibleRegion.GetBounds();
   432   gfx::IntSize scaledTileSize = aLayerBuffer.GetScaledTileSize();
   433   for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
   434     rowCount++;
   435     int32_t tileStartX = aLayerBuffer.GetTileStart(x, scaledTileSize.width);
   436     int32_t w = scaledTileSize.width - tileStartX;
   437     if (x + w > visibleRect.x + visibleRect.width) {
   438       w = visibleRect.x + visibleRect.width - x;
   439     }
   440     int tileY = 0;
   441     for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
   442       int32_t tileStartY = aLayerBuffer.GetTileStart(y, scaledTileSize.height);
   443       int32_t h = scaledTileSize.height - tileStartY;
   444       if (y + h > visibleRect.y + visibleRect.height) {
   445         h = visibleRect.y + visibleRect.height - y;
   446       }
   448       TileHost tileTexture = aLayerBuffer.
   449         GetTile(nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x, scaledTileSize.width),
   450                            aLayerBuffer.RoundDownToTileEdge(y, scaledTileSize.height)));
   451       if (tileTexture != aLayerBuffer.GetPlaceholderTile()) {
   452         nsIntRegion tileDrawRegion;
   453         tileDrawRegion.And(nsIntRect(x, y, w, h), aLayerBuffer.GetValidRegion());
   454         tileDrawRegion.And(tileDrawRegion, aVisibleRegion);
   455         tileDrawRegion.Sub(tileDrawRegion, maskRegion);
   457         if (!tileDrawRegion.IsEmpty()) {
   458           tileDrawRegion.ScaleRoundOut(resolution, resolution);
   459           nsIntPoint tileOffset((x - tileStartX) * resolution,
   460                                 (y - tileStartY) * resolution);
   461           gfx::IntSize tileSize = aLayerBuffer.GetTileSize();
   462           RenderTile(tileTexture, aEffectChain, aOpacity, aTransform, aFilter, aClipRect, tileDrawRegion,
   463                      tileOffset, nsIntSize(tileSize.width, tileSize.height));
   464         }
   465       }
   466       tileY++;
   467       y += h;
   468     }
   469     tileX++;
   470     x += w;
   471   }
   472   gfx::Rect rect(visibleRect.x, visibleRect.y,
   473                  visibleRect.width, visibleRect.height);
   474   GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTENT,
   475                                    rect, aClipRect, aTransform, mFlashCounter);
   476 }
   478 void
   479 TiledContentHost::PrintInfo(nsACString& aTo, const char* aPrefix)
   480 {
   481   aTo += aPrefix;
   482   aTo += nsPrintfCString("TiledContentHost (0x%p)", this);
   484 }
   486 #ifdef MOZ_DUMP_PAINTING
   487 void
   488 TiledContentHost::Dump(FILE* aFile,
   489                        const char* aPrefix,
   490                        bool aDumpHtml)
   491 {
   492   if (!aFile) {
   493     aFile = stderr;
   494   }
   496   TiledLayerBufferComposite::Iterator it = mTiledBuffer.TilesBegin();
   497   TiledLayerBufferComposite::Iterator stop = mTiledBuffer.TilesEnd();
   498   if (aDumpHtml) {
   499     fprintf_stderr(aFile, "<ul>");
   500   }
   501   for (;it != stop; ++it) {
   502     fprintf_stderr(aFile, "%s", aPrefix);
   503     fprintf_stderr(aFile, aDumpHtml ? "<li> <a href=" : "Tile ");
   504     if (it->IsPlaceholderTile()) {
   505       fprintf_stderr(aFile, "empty tile");
   506     } else {
   507       DumpTextureHost(aFile, it->mTextureHost);
   508     }
   509     fprintf_stderr(aFile, aDumpHtml ? " >Tile</a></li>" : " ");
   510   }
   511     if (aDumpHtml) {
   512     fprintf_stderr(aFile, "</ul>");
   513   }
   514 }
   515 #endif
   517 } // namespace
   518 } // namespace

mercurial