LCOV - code coverage report
Current view: top level - gfx/layers/mlgpu - FrameBuilder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 183 0.5 %
Date: 2017-07-14 16:53:18 Functions: 2 20 10.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 "FrameBuilder.h"
       7             : #include "ContainerLayerMLGPU.h"
       8             : #include "GeckoProfiler.h"              // for profiler_*
       9             : #include "LayerMLGPU.h"
      10             : #include "LayerManagerMLGPU.h"
      11             : #include "MaskOperation.h"
      12             : #include "RenderPassMLGPU.h"
      13             : #include "RenderViewMLGPU.h"
      14             : #include "mozilla/gfx/Polygon.h"
      15             : #include "mozilla/layers/BSPTree.h"
      16             : #include "mozilla/layers/LayersHelpers.h"
      17             : 
      18             : namespace mozilla {
      19             : namespace layers {
      20             : 
      21             : using namespace mlg;
      22             : 
      23           0 : FrameBuilder::FrameBuilder(LayerManagerMLGPU* aManager, MLGSwapChain* aSwapChain)
      24             :  : mManager(aManager),
      25             :    mDevice(aManager->GetDevice()),
      26           0 :    mSwapChain(aSwapChain)
      27             : {
      28             :   // test_bug1124898.html has a root ColorLayer, so we don't assume the root is
      29             :   // a container.
      30           0 :   mRoot = mManager->GetRoot()->AsHostLayer()->AsLayerMLGPU();
      31           0 : }
      32             : 
      33           0 : FrameBuilder::~FrameBuilder()
      34             : {
      35           0 : }
      36             : 
      37             : bool
      38           0 : FrameBuilder::Build()
      39             : {
      40           0 :   AUTO_PROFILER_LABEL("FrameBuilder::Build", GRAPHICS);
      41             : 
      42             :   // AcquireBackBuffer can fail, so we check the result here.
      43           0 :   RefPtr<MLGRenderTarget> target = mSwapChain->AcquireBackBuffer();
      44           0 :   if (!target) {
      45           0 :     return false;
      46             :   }
      47             : 
      48             :   // This updates the frame sequence number, so layers can quickly check if
      49             :   // they've already been prepared.
      50           0 :   LayerMLGPU::BeginFrame();
      51             : 
      52             :   // Note: we don't clip draw calls to the invalid region per se, but instead
      53             :   // the region bounds. Clipping all draw calls would incur a significant
      54             :   // CPU cost on large layer trees, and would greatly complicate how draw
      55             :   // rects are added in RenderPassMLGPU, since we would need to break
      56             :   // each call into additional items based on the intersection with the
      57             :   // invalid region.
      58             :   //
      59             :   // Instead we scissor to the invalid region bounds. As a result, all items
      60             :   // affecting the invalid bounds are redrawn, even if not all are in the
      61             :   // precise region.
      62           0 :   const nsIntRegion& region = mSwapChain->GetBackBufferInvalidRegion();
      63             : 
      64           0 :   mWidgetRenderView = new RenderViewMLGPU(this, target, region);
      65             : 
      66             :   // Traverse the layer tree and assign each layer to tiles.
      67             :   {
      68           0 :     Maybe<gfx::Polygon> geometry;
      69           0 :     RenderTargetIntRect clip(0, 0, target->GetSize().width, target->GetSize().height);
      70             : 
      71           0 :     AssignLayer(mRoot->GetLayer(), mWidgetRenderView, clip, Move(geometry));
      72             :   }
      73             : 
      74             :   // Build the default mask buffer.
      75             :   {
      76           0 :     MaskInformation defaultMaskInfo(1.0f, false);
      77           0 :     if (!mDevice->GetSharedPSBuffer()->Allocate(&mDefaultMaskInfo, defaultMaskInfo)) {
      78           0 :       return false;
      79             :     }
      80             :   }
      81             : 
      82             :   // Build render passes and buffer information for each pass.
      83           0 :   mWidgetRenderView->FinishBuilding();
      84           0 :   mWidgetRenderView->Prepare();
      85             : 
      86             :   // Prepare masks that need to be combined.
      87           0 :   for (const auto& pair : mCombinedTextureMasks) {
      88           0 :     pair.second->PrepareForRendering();
      89             :   }
      90             : 
      91           0 :   FinishCurrentLayerBuffer();
      92           0 :   FinishCurrentMaskRectBuffer();
      93           0 :   return true;
      94             : }
      95             : 
      96             : void
      97           0 : FrameBuilder::Render()
      98             : {
      99           0 :   AUTO_PROFILER_LABEL("FrameBuilder::Render", GRAPHICS);
     100             : 
     101             :   // Render combined masks into single mask textures.
     102           0 :   for (const auto& pair : mCombinedTextureMasks) {
     103           0 :     pair.second->Render();
     104             :   }
     105             : 
     106             :   // Render to all targets, front-to-back.
     107           0 :   mWidgetRenderView->Render();
     108           0 : }
     109             : 
     110             : void
     111           0 : FrameBuilder::AssignLayer(Layer* aLayer,
     112             :                           RenderViewMLGPU* aView,
     113             :                           const RenderTargetIntRect& aClipRect,
     114             :                           Maybe<gfx::Polygon>&& aGeometry)
     115             : {
     116           0 :   LayerMLGPU* layer = aLayer->AsHostLayer()->AsLayerMLGPU();
     117             : 
     118           0 :   if (ContainerLayer* container = aLayer->AsContainerLayer()) {
     119             :     // This returns false if we don't need to (or can't) process the layer any
     120             :     // further. This always returns false for non-leaf ContainerLayers.
     121           0 :     if (!ProcessContainerLayer(container, aView, aClipRect, aGeometry)) {
     122           0 :       return;
     123             :     }
     124             :   } else {
     125             :     // Set the precomputed clip and any textures/resources that are needed.
     126           0 :     if (!layer->PrepareToRender(this, aClipRect)) {
     127           0 :       return;
     128             :     }
     129             :   }
     130             : 
     131             :   // If we are dealing with a nested 3D context, we might need to transform
     132             :   // the geometry back to the coordinate space of the current layer.
     133           0 :   if (aGeometry) {
     134           0 :     TransformLayerGeometry(aLayer, aGeometry);
     135             :   }
     136             : 
     137             :   // Finally, assign the layer to a rendering batch in the current render
     138             :   // target.
     139           0 :   layer->AssignToView(this, aView, Move(aGeometry));
     140             : }
     141             : 
     142             : bool
     143           0 : FrameBuilder::ProcessContainerLayer(ContainerLayer* aContainer,
     144             :                                     RenderViewMLGPU* aView,
     145             :                                     const RenderTargetIntRect& aClipRect,
     146             :                                     Maybe<gfx::Polygon>& aGeometry)
     147             : {
     148           0 :   LayerMLGPU* layer = aContainer->AsHostLayer()->AsLayerMLGPU();
     149             : 
     150             :   // We don't want to traverse containers twice, so we only traverse them if
     151             :   // they haven't been prepared yet.
     152           0 :   bool isFirstVisit = !layer->IsPrepared();
     153           0 :   if (isFirstVisit && !layer->PrepareToRender(this, aClipRect)) {
     154           0 :     return false;
     155             :   }
     156             : 
     157             :   // If the container is not part of the invalid region, we don't draw it
     158             :   // or traverse it. Note that we do not pass the geometry here. Otherwise
     159             :   // we could decide the particular split is not visible, and because of the
     160             :   // check above, never bother traversing the container again.
     161           0 :   gfx::IntRect boundingBox = layer->GetClippedBoundingBox(aView, Nothing());
     162           0 :   const gfx::IntRect& invalidRect = aView->GetInvalidRect();
     163           0 :   if (boundingBox.IsEmpty() || !invalidRect.Intersects(boundingBox)) {
     164           0 :     return false;
     165             :   }
     166             : 
     167           0 :   if (!aContainer->UseIntermediateSurface()) {
     168             :     // In case the layer previously required an intermediate surface, we
     169             :     // clear any intermediate render targets here.
     170           0 :     layer->ClearCachedResources();
     171             : 
     172             :     // This is a pass-through container, so we just process children and
     173             :     // instruct AssignLayer to early-return.
     174           0 :     ProcessChildList(aContainer, aView, aClipRect, aGeometry);
     175           0 :     return false;
     176             :   }
     177             : 
     178             :   // If this is the first visit of the container this frame, and the
     179             :   // container has an unpainted area, we traverse the container. Note that
     180             :   // RefLayers do not have intermediate surfaces so this is guaranteed
     181             :   // to be a full-fledged ContainerLayerMLGPU.
     182           0 :   ContainerLayerMLGPU* viewContainer = layer->AsContainerLayerMLGPU();
     183           0 :   if (isFirstVisit && !viewContainer->GetInvalidRect().IsEmpty()) {
     184             :     // The RenderView constructor automatically attaches itself to the parent.
     185           0 :     RefPtr<RenderViewMLGPU> view = new RenderViewMLGPU(this, viewContainer, aView);
     186           0 :     ProcessChildList(aContainer, view, aClipRect, Nothing());
     187           0 :     view->FinishBuilding();
     188             :   }
     189           0 :   return true;
     190             : }
     191             : 
     192             : void
     193           0 : FrameBuilder::ProcessChildList(ContainerLayer* aContainer,
     194             :                                RenderViewMLGPU* aView,
     195             :                                const RenderTargetIntRect& aParentClipRect,
     196             :                                const Maybe<gfx::Polygon>& aParentGeometry)
     197             : {
     198             :   nsTArray<LayerPolygon> polygons =
     199           0 :     aContainer->SortChildrenBy3DZOrder(ContainerLayer::SortMode::WITH_GEOMETRY);
     200             : 
     201             :   // Visit layers in front-to-back order.
     202           0 :   for (auto iter = polygons.rbegin(); iter != polygons.rend(); iter++) {
     203           0 :     LayerPolygon& entry = *iter;
     204           0 :     Layer* child = entry.layer;
     205           0 :     if (child->IsBackfaceHidden() || !child->IsVisible()) {
     206           0 :       continue;
     207             :     }
     208             : 
     209           0 :     RenderTargetIntRect clip = child->CalculateScissorRect(aParentClipRect);
     210           0 :     if (clip.IsEmpty()) {
     211           0 :       continue;
     212             :     }
     213             : 
     214           0 :     Maybe<gfx::Polygon> geometry;
     215           0 :     if (aParentGeometry && entry.geometry) {
     216             :       // Both parent and child are split.
     217           0 :       geometry = Some(aParentGeometry->ClipPolygon(*entry.geometry));
     218           0 :     } else if (aParentGeometry) {
     219           0 :       geometry = aParentGeometry;
     220           0 :     } else if (entry.geometry) {
     221           0 :       geometry = Move(entry.geometry);
     222             :     }
     223             : 
     224           0 :     AssignLayer(child, aView, clip, Move(geometry));
     225             :   }
     226           0 : }
     227             : 
     228             : bool
     229           0 : FrameBuilder::AddLayerToConstantBuffer(ItemInfo& aItem)
     230             : {
     231           0 :   LayerMLGPU* layer = aItem.layer;
     232             : 
     233             :   // If this layer could appear multiple times, cache it.
     234           0 :   if (aItem.geometry) {
     235           0 :     if (mLayerBufferMap.Get(layer, &aItem.layerIndex)) {
     236           0 :       return true;
     237             :     }
     238             :   }
     239             : 
     240           0 :   LayerConstants* info = AllocateLayerInfo(aItem);
     241           0 :   if (!info) {
     242           0 :     return false;
     243             :   }
     244             : 
     245             :   // Note we do not use GetEffectiveTransformForBuffer, since we calculate
     246             :   // the correct scaling when we build texture coordinates.
     247           0 :   Layer* baseLayer = layer->GetLayer();
     248           0 :   const gfx::Matrix4x4& transform = baseLayer->GetEffectiveTransform();
     249             : 
     250           0 :   memcpy(&info->transform, &transform._11, 64);
     251           0 :   info->clipRect = gfx::Rect(layer->GetComputedClipRect().ToUnknownRect());
     252           0 :   info->maskIndex = 0;
     253           0 :   if (MaskOperation* op = layer->GetMask()) {
     254             :     // Note: we use 0 as an invalid index, and so indices are offset by 1.
     255           0 :     gfx::Rect rect = op->ComputeMaskRect(baseLayer);
     256           0 :     AddMaskRect(rect, &info->maskIndex);
     257             :   }
     258             : 
     259           0 :   if (aItem.geometry) {
     260           0 :     mLayerBufferMap.Put(layer, aItem.layerIndex);
     261             :   }
     262           0 :   return true;
     263             : }
     264             : 
     265             : MaskOperation*
     266           0 : FrameBuilder::AddMaskOperation(LayerMLGPU* aLayer)
     267             : {
     268           0 :   Layer* layer = aLayer->GetLayer();
     269           0 :   MOZ_ASSERT(layer->HasMaskLayers());
     270             : 
     271             :   // Multiple masks are combined into a single mask.
     272           0 :   if ((layer->GetMaskLayer() && layer->GetAncestorMaskLayerCount()) ||
     273           0 :       layer->GetAncestorMaskLayerCount() > 1)
     274             :   {
     275             :     // Since each mask can be moved independently of the other, we must create
     276             :     // a separate combined mask for every new positioning we encounter.
     277           0 :     MaskTextureList textures;
     278           0 :     if (Layer* maskLayer = layer->GetMaskLayer()) {
     279           0 :       AppendToMaskTextureList(textures, maskLayer);
     280             :     }
     281           0 :     for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
     282           0 :       AppendToMaskTextureList(textures, layer->GetAncestorMaskLayerAt(i));
     283             :     }
     284             : 
     285           0 :     auto iter = mCombinedTextureMasks.find(textures);
     286           0 :     if (iter != mCombinedTextureMasks.end()) {
     287           0 :       return iter->second;
     288             :     }
     289             : 
     290           0 :     RefPtr<MaskCombineOperation> op = new MaskCombineOperation(this);
     291           0 :     op->Init(textures);
     292             : 
     293           0 :     mCombinedTextureMasks[textures] = op;
     294           0 :     return op;
     295             :   }
     296             : 
     297           0 :   Layer* maskLayer = layer->GetMaskLayer()
     298           0 :                      ? layer->GetMaskLayer()
     299           0 :                      : layer->GetAncestorMaskLayerAt(0);
     300           0 :   RefPtr<TextureSource> texture = GetMaskLayerTexture(maskLayer);
     301           0 :   if (!texture) {
     302           0 :     return nullptr;
     303             :   }
     304             : 
     305           0 :   RefPtr<MaskOperation> op;
     306           0 :   mSingleTextureMasks.Get(texture, getter_AddRefs(op));
     307           0 :   if (op) {
     308           0 :     return op;
     309             :   }
     310             : 
     311           0 :   RefPtr<MLGTexture> wrapped = mDevice->CreateTexture(texture);
     312             : 
     313           0 :   op = new MaskOperation(this, wrapped);
     314           0 :   mSingleTextureMasks.Put(texture, op);
     315           0 :   return op;
     316             : }
     317             : 
     318             : void
     319           0 : FrameBuilder::RetainTemporaryLayer(LayerMLGPU* aLayer)
     320             : {
     321             :   // This should only be used with temporary layers. Temporary layers do not
     322             :   // have parents.
     323           0 :   MOZ_ASSERT(!aLayer->GetLayer()->GetParent());
     324           0 :   mTemporaryLayers.push_back(aLayer->GetLayer());
     325           0 : }
     326             : 
     327             : LayerConstants*
     328           0 : FrameBuilder::AllocateLayerInfo(ItemInfo& aItem)
     329             : {
     330           0 :   if (((mCurrentLayerBuffer.Length() + 1) * sizeof(LayerConstants)) >
     331           0 :       mDevice->GetMaxConstantBufferBindSize())
     332             :   {
     333           0 :     FinishCurrentLayerBuffer();
     334           0 :     mLayerBufferMap.Clear();
     335           0 :     mCurrentLayerBuffer.ClearAndRetainStorage();
     336             :   }
     337             : 
     338           0 :   LayerConstants* info = mCurrentLayerBuffer.AppendElement(mozilla::fallible);
     339           0 :   if (!info) {
     340           0 :     return nullptr;
     341             :   }
     342             : 
     343           0 :   aItem.layerIndex = mCurrentLayerBuffer.Length() - 1;
     344           0 :   return info;
     345             : }
     346             : 
     347             : void
     348           0 : FrameBuilder::FinishCurrentLayerBuffer()
     349             : {
     350           0 :   if (mCurrentLayerBuffer.IsEmpty()) {
     351           0 :     return;
     352             :   }
     353             : 
     354             :   // Note: we append the buffer even if we couldn't allocate one, since
     355             :   // that keeps the indices sane.
     356           0 :   ConstantBufferSection section;
     357           0 :   mDevice->GetSharedVSBuffer()->Allocate(
     358             :     &section,
     359           0 :     mCurrentLayerBuffer.Elements(),
     360           0 :     mCurrentLayerBuffer.Length());
     361           0 :   mLayerBuffers.AppendElement(section);
     362             : }
     363             : 
     364             : size_t
     365           0 : FrameBuilder::CurrentLayerBufferIndex() const
     366             : {
     367             :   // The mask rect buffer list doesn't contain the buffer currently being
     368             :   // built, so we don't subtract 1 here.
     369           0 :   return mLayerBuffers.Length();
     370             : }
     371             : 
     372             : ConstantBufferSection
     373           0 : FrameBuilder::GetLayerBufferByIndex(size_t aIndex) const
     374             : {
     375           0 :   if (aIndex >= mLayerBuffers.Length()) {
     376           0 :     return ConstantBufferSection();
     377             :   }
     378           0 :   return mLayerBuffers[aIndex];
     379             : }
     380             : 
     381             : bool
     382           0 : FrameBuilder::AddMaskRect(const gfx::Rect& aRect, uint32_t* aOutIndex)
     383             : {
     384           0 :   if (((mCurrentMaskRectList.Length() + 1) * sizeof(gfx::Rect)) >
     385           0 :       mDevice->GetMaxConstantBufferBindSize())
     386             :   {
     387           0 :     FinishCurrentMaskRectBuffer();
     388           0 :     mCurrentMaskRectList.ClearAndRetainStorage();
     389             :   }
     390             : 
     391           0 :   mCurrentMaskRectList.AppendElement(aRect);
     392             : 
     393             :   // Mask indices start at 1 so the shader can use 0 as a no-mask indicator.
     394           0 :   *aOutIndex = mCurrentMaskRectList.Length();
     395           0 :   return true;
     396             : }
     397             : 
     398             : void
     399           0 : FrameBuilder::FinishCurrentMaskRectBuffer()
     400             : {
     401           0 :   if (mCurrentMaskRectList.IsEmpty()) {
     402           0 :     return;
     403             :   }
     404             : 
     405             :   // Note: we append the buffer even if we couldn't allocate one, since
     406             :   // that keeps the indices sane.
     407           0 :   ConstantBufferSection section;
     408           0 :   mDevice->GetSharedVSBuffer()->Allocate(
     409             :     &section,
     410           0 :     mCurrentMaskRectList.Elements(),
     411           0 :     mCurrentMaskRectList.Length());
     412           0 :   mMaskRectBuffers.AppendElement(section);
     413             : }
     414             : 
     415             : size_t
     416           0 : FrameBuilder::CurrentMaskRectBufferIndex() const
     417             : {
     418             :   // The mask rect buffer list doesn't contain the buffer currently being
     419             :   // built, so we don't subtract 1 here.
     420           0 :   return mMaskRectBuffers.Length();
     421             : }
     422             : 
     423             : ConstantBufferSection
     424           0 : FrameBuilder::GetMaskRectBufferByIndex(size_t aIndex) const
     425             : {
     426           0 :   if (aIndex >= mMaskRectBuffers.Length()) {
     427           0 :     return ConstantBufferSection();
     428             :   }
     429           0 :   return mMaskRectBuffers[aIndex];
     430             : }
     431             : 
     432             : } // namespace layers
     433           9 : } // namespace mozilla

Generated by: LCOV version 1.13