summaryrefslogtreecommitdiffstats
path: root/gfx/layers/mlgpu/BufferCache.h
blob: 0f67597e3a9a83d963f37e7aa5d25791023dab29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_gfx_layers_mlgpu_BufferCache_h
#define mozilla_gfx_layers_mlgpu_BufferCache_h

#include "mozilla/EnumeratedArray.h"
#include "mozilla/RefPtr.h"
#include <deque>
#include <vector>

namespace mozilla {
namespace layers {

class MLGBuffer;
class MLGDevice;

// Cache MLGBuffers based on how long ago they were last used.
class BufferCache final {
 public:
  explicit BufferCache(MLGDevice* aDevice);
  ~BufferCache();

  // Get a buffer that has at least |aBytes|, or create a new one
  // if none can be re-used.
  RefPtr<MLGBuffer> GetOrCreateBuffer(size_t aBytes);

  // Age out old buffers after a frame has been completed.
  void EndFrame();

 private:
  // Not RefPtr since this would create a cycle.
  MLGDevice* mDevice;

  // The first size class is Log2(N), where 16 is the minimum size of a
  // constant buffer (currently 16 bytes).
  size_t mFirstSizeClass;

  // Each size class is a power of 2. Each pool of buffers is represented as a
  // deque, with the least-recently-used (i.e., oldest) buffers at the front,
  // and most-recently-used (i.e., newest) buffers at the back. To re-use a
  // buffer it is popped off the front and re-added to the back.
  //
  // This is not always efficient use of storage: if a single frame allocates
  // 300 buffers of the same size, we may keep recycling through all those
  // buffers for a long time, as long as at least one gets used per frame.
  // But since buffers use tiny amounts of memory, and they are only mapped
  // while drawing, it shouldn't be a big deal.
  struct CacheEntry {
    CacheEntry() : mLastUsedFrame(0) {}
    // XXX The copy constructor can be deleted once RefPtr's move constructor is
    // declared noexcept, see Bug 1612680.
    CacheEntry(const CacheEntry& aEntry) = default;
    CacheEntry(CacheEntry&& aEntry) = default;
    CacheEntry(size_t aLastUsedFrame, MLGBuffer* aBuffer)
        : mLastUsedFrame(aLastUsedFrame), mBuffer(aBuffer) {}

    uint64_t mLastUsedFrame;
    RefPtr<MLGBuffer> mBuffer;
  };
  typedef std::deque<CacheEntry> CachePool;

  // We track how many frames have occurred to determine the age of cache
  // entries.
  uint64_t mFrameNumber;

  // To avoid doing too much work in one frame, we only shrink one size class
  // per frame.
  uint64_t mNextSizeClassToShrink;

  // There is one pool of buffers for each power of 2 allocation size. The
  // maximum buffer size is at most 64KB on Direct3D 11.
  std::vector<CachePool> mCaches;
};

}  // namespace layers
}  // namespace mozilla

#endif  // mozilla_gfx_layers_mlgpu_BufferCache_h