LCOV - code coverage report
Current view: top level - gfx/layers/mlgpu - StagingBuffer.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 112 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 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             : #ifndef mozilla_gfx_layers_mlgpu_StagingBuffer_h
       7             : #define mozilla_gfx_layers_mlgpu_StagingBuffer_h
       8             : 
       9             : #include "mozilla/MathAlgorithms.h"
      10             : #include "mozilla/UniquePtr.h"
      11             : #include "UtilityMLGPU.h"
      12             : #include <algorithm>
      13             : #include <utility>
      14             : #include <limits.h>
      15             : 
      16             : namespace mozilla {
      17             : namespace layers {
      18             : 
      19             : class MLGDevice;
      20             : 
      21             : // A StagingBuffer is a writable memory buffer for arbitrary contents.
      22             : template <size_t Alignment = 0>
      23           0 : class StagingBuffer
      24             : {
      25             : public:
      26           0 :   StagingBuffer()
      27           0 :    : StagingBuffer(0)
      28           0 :   {}
      29             : 
      30             :   // By default, staging buffers operate in "forward" mode: items are added to
      31             :   // the end of the buffer. In "reverse" mode the cursor is at the end of the
      32             :   // buffer, and items are added to the beginning.
      33             :   //
      34             :   // This must be called before the buffer is written.
      35           0 :   void SetReversed() {
      36           0 :     MOZ_ASSERT(IsEmpty());
      37           0 :     mReversed = true;
      38           0 :   }
      39             : 
      40             :   // Write a series of components as a single item. When this is first used, the
      41             :   // buffer records the initial item size and requires that all future items be
      42             :   // the exact same size.
      43             :   //
      44             :   // This directs to either AppendItem or PrependItem depending on the buffer
      45             :   // state.
      46             :   template <typename T>
      47             :   bool AddItem(const T& aItem) {
      48             :     if (mReversed) {
      49             :       return PrependItem(aItem);
      50             :     }
      51             :     return AppendItem(aItem);
      52             :   }
      53             : 
      54             :   // Helper for adding a single item as two components.
      55             :   template <typename T1, typename T2>
      56           0 :   bool AddItem(const T1& aItem1, const T2& aItem2) {
      57           0 :     if (mReversed) {
      58           0 :       return PrependItem(aItem1, aItem2);
      59             :     }
      60           0 :     return AppendItem(aItem1, aItem2);
      61             :   }
      62             : 
      63             :   // This may only be called on forward buffers.
      64             :   template <typename T>
      65           0 :   bool AppendItem(const T& aItem) {
      66           0 :     MOZ_ASSERT(!mReversed);
      67             : 
      68           0 :     size_t alignedBytes = AlignUp<Alignment>::calc(sizeof(aItem));
      69           0 :     if (!mUniformSize) {
      70           0 :       mUniformSize = alignedBytes;
      71             :     }
      72             : 
      73           0 :     if (!EnsureForwardRoomFor(alignedBytes)) {
      74           0 :       return false;
      75             :     }
      76           0 :     if (mUniformSize != alignedBytes) {
      77           0 :       MOZ_ASSERT_UNREACHABLE("item of incorrect size added!");
      78             :       return false;
      79             :     }
      80             : 
      81           0 :     *reinterpret_cast<T*>(mPos) = aItem;
      82           0 :     mPos += alignedBytes;
      83           0 :     MOZ_ASSERT(mPos <= mEnd);
      84             : 
      85           0 :     mNumItems++;
      86           0 :     return true;
      87             :   }
      88             : 
      89             :   // Append an item in two stages.
      90             :   template <typename T1, typename T2>
      91           0 :   bool AppendItem(const T1& aFirst, const T2& aSecond) {
      92             :     struct Combined {
      93             :       T1 first;
      94             :       T2 second;
      95           0 :     } value = { aFirst, aSecond };
      96             : 
      97             :     // The combined value must be packed.
      98             :     static_assert(sizeof(value) == sizeof(aFirst) + sizeof(aSecond),
      99             :                   "Items must be packed within struct");
     100           0 :     return AppendItem(value);
     101             :   }
     102             : 
     103             :   // This may only be called on reversed buffers.
     104             :   template <typename T>
     105           0 :   bool PrependItem(const T& aItem) {
     106           0 :     MOZ_ASSERT(mReversed);
     107             : 
     108           0 :     size_t alignedBytes = AlignUp<Alignment>::calc(sizeof(aItem));
     109           0 :     if (!mUniformSize) {
     110           0 :       mUniformSize = alignedBytes;
     111             :     }
     112             : 
     113           0 :     if (!EnsureBackwardRoomFor(alignedBytes)) {
     114           0 :       return false;
     115             :     }
     116           0 :     if (mUniformSize != alignedBytes) {
     117           0 :       MOZ_ASSERT_UNREACHABLE("item of incorrect size added!");
     118             :       return false;
     119             :     }
     120             : 
     121           0 :     mPos -= alignedBytes;
     122           0 :     *reinterpret_cast<T*>(mPos) = aItem;
     123           0 :     MOZ_ASSERT(mPos >= mBuffer.get());
     124             : 
     125           0 :     mNumItems++;
     126           0 :     return true;
     127             :   }
     128             : 
     129             :   // Prepend an item in two stages.
     130             :   template <typename T1, typename T2>
     131           0 :   bool PrependItem(const T1& aFirst, const T2& aSecond) {
     132             :     struct Combined {
     133             :       T1 first;
     134             :       T2 second;
     135           0 :     } value = { aFirst, aSecond };
     136             : 
     137             :     // The combined value must be packed.
     138             :     static_assert(sizeof(value) == sizeof(aFirst) + sizeof(aSecond),
     139             :                   "Items must be packed within struct");
     140           0 :     return PrependItem(value);
     141             :   }
     142             : 
     143           0 :   size_t NumBytes() const {
     144           0 :     return mReversed
     145           0 :            ? mEnd - mPos
     146           0 :            : mPos - mBuffer.get();
     147             :   }
     148           0 :   uint8_t* GetBufferStart() const {
     149           0 :     return mReversed
     150             :            ? mPos
     151           0 :            : mBuffer.get();
     152             :   }
     153           0 :   size_t SizeOfItem() const {
     154           0 :     return mUniformSize;
     155             :   }
     156           0 :   size_t NumItems() const {
     157           0 :     return mNumItems;
     158             :   }
     159             : 
     160             :   void Reset() {
     161             :     mPos = mReversed ? mEnd : mBuffer.get();
     162             :     mUniformSize = 0;
     163             :     mNumItems = 0;
     164             :   }
     165             : 
     166             :   // RestorePosition must only be called with a previous call to
     167             :   // GetPosition.
     168             :   typedef std::pair<size_t,size_t> Position;
     169           0 :   Position GetPosition() const {
     170           0 :     return std::make_pair(NumBytes(), mNumItems);
     171             :   }
     172           0 :   void RestorePosition(const Position& aPosition) {
     173           0 :     mPos = mBuffer.get() + aPosition.first;
     174           0 :     mNumItems = aPosition.second;
     175           0 :     if (mNumItems == 0) {
     176           0 :       mUniformSize = 0;
     177             :     }
     178             : 
     179             :     // Make sure the buffer is still coherent.
     180           0 :     MOZ_ASSERT(mPos >= mBuffer.get() && mPos <= mEnd);
     181           0 :     MOZ_ASSERT(mNumItems * mUniformSize == NumBytes());
     182           0 :   }
     183             : 
     184           0 :   bool IsEmpty() const {
     185           0 :     return mNumItems == 0;
     186             :   }
     187             : 
     188             : protected:
     189           0 :   explicit StagingBuffer(size_t aMaxSize)
     190             :    : mPos(nullptr),
     191             :      mEnd(nullptr),
     192             :      mUniformSize(0),
     193             :      mNumItems(0),
     194             :      mMaxSize(aMaxSize),
     195           0 :      mReversed(false)
     196           0 :   {}
     197             : 
     198             :   static const size_t kDefaultSize = 8;
     199             : 
     200           0 :   bool EnsureForwardRoomFor(size_t aAlignedBytes) {
     201           0 :     if (size_t(mEnd - mPos) < aAlignedBytes) {
     202           0 :       return GrowBuffer(aAlignedBytes);
     203             :     }
     204           0 :     return true;
     205             :   }
     206             : 
     207           0 :   bool EnsureBackwardRoomFor(size_t aAlignedBytes) {
     208           0 :     if (size_t(mPos - mBuffer.get()) < aAlignedBytes) {
     209           0 :       return GrowBuffer(aAlignedBytes);
     210             :     }
     211           0 :     return true;
     212             :   }
     213             : 
     214           0 :   bool GrowBuffer(size_t aAlignedBytes) {
     215             :     // We should not be writing items that are potentially bigger than the
     216             :     // maximum constant buffer size, that's crazy. An assert should be good
     217             :     // enough since the size of writes is static - and shader compilers
     218             :     // would explode anyway.
     219           0 :     MOZ_ASSERT_IF(mMaxSize, aAlignedBytes < mMaxSize);
     220           0 :     MOZ_ASSERT_IF(mMaxSize, kDefaultSize * Alignment < mMaxSize);
     221             : 
     222           0 :     if (!mBuffer) {
     223           0 :       size_t newSize = std::max(kDefaultSize * Alignment, aAlignedBytes);
     224           0 :       MOZ_ASSERT_IF(mMaxSize, newSize < mMaxSize);
     225             : 
     226           0 :       mBuffer = MakeUnique<uint8_t[]>(newSize);
     227           0 :       mEnd = mBuffer.get() + newSize;
     228           0 :       mPos = mReversed ? mEnd : mBuffer.get();
     229           0 :       return true;
     230             :     }
     231             : 
     232             :     // Take the bigger of exact-fit or 1.5x the previous size, and make sure
     233             :     // the new size doesn't overflow size_t. If needed, clamp to the max
     234             :     // size.
     235           0 :     size_t oldSize = mEnd - mBuffer.get();
     236           0 :     size_t trySize = std::max(oldSize + aAlignedBytes, oldSize + oldSize / 2);
     237           0 :     size_t newSize = mMaxSize ? std::min(trySize, mMaxSize) : trySize;
     238           0 :     if (newSize < oldSize || newSize - oldSize < aAlignedBytes) {
     239           0 :       return false;
     240             :     }
     241             : 
     242           0 :     UniquePtr<uint8_t[]> newBuffer = MakeUnique<uint8_t[]>(newSize);
     243           0 :     if (!newBuffer) {
     244           0 :       return false;
     245             :     }
     246             : 
     247             :     // When the buffer is in reverse mode, we have to copy from the end of the
     248             :     // buffer, not the beginning.
     249           0 :     if (mReversed) {
     250           0 :       size_t usedBytes = mEnd - mPos;
     251           0 :       size_t newPos = newSize - usedBytes;
     252           0 :       MOZ_RELEASE_ASSERT(newPos + usedBytes <= newSize);
     253             : 
     254           0 :       memcpy(newBuffer.get() + newPos, mPos, usedBytes);
     255           0 :       mPos = newBuffer.get() + newPos;
     256             :     } else {
     257           0 :       size_t usedBytes = mPos - mBuffer.get();
     258           0 :       MOZ_RELEASE_ASSERT(usedBytes <= newSize);
     259             : 
     260           0 :       memcpy(newBuffer.get(), mBuffer.get(), usedBytes);
     261           0 :       mPos = newBuffer.get() + usedBytes;
     262             :     }
     263           0 :     mEnd = newBuffer.get() + newSize;
     264           0 :     mBuffer = Move(newBuffer);
     265             : 
     266           0 :     MOZ_RELEASE_ASSERT(mPos >= mBuffer.get() && mPos <= mEnd);
     267           0 :     return true;
     268             :   }
     269             : 
     270             : protected:
     271             :   UniquePtr<uint8_t[]> mBuffer;
     272             :   uint8_t* mPos;
     273             :   uint8_t* mEnd;
     274             :   size_t mUniformSize;
     275             :   size_t mNumItems;
     276             :   size_t mMaxSize;
     277             :   bool mReversed;
     278             : };
     279             : 
     280             : class ConstantStagingBuffer : public StagingBuffer<16>
     281             : {
     282             :  public:
     283             :   explicit ConstantStagingBuffer(MLGDevice* aDevice);
     284             : };
     285             : 
     286             : } // namespace layers
     287             : } // namespace mozilla
     288             : 
     289             : #endif // mozilla_gfx_layers_mlgpu_StagingBuffer_h

Generated by: LCOV version 1.13