• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // mtl_buffer_pool.h:
7 //    Defines class interface for BufferPool, managing a pool of mtl::Buffer
8 //
9 
10 #ifndef LIBANGLE_RENDERER_METAL_MTL_BUFFER_POOL_H_
11 #define LIBANGLE_RENDERER_METAL_MTL_BUFFER_POOL_H_
12 
13 #include "libANGLE/renderer/metal/mtl_resources.h"
14 
15 #include <deque>
16 
17 namespace rx
18 {
19 
20 class ContextMtl;
21 
22 namespace mtl
23 {
24 
25 // A buffer pool is conceptually an infinitely long buffer. Each time you write to the buffer,
26 // you will always write to a previously unused portion. After a series of writes, you must flush
27 // the buffer data to the device. Buffer lifetime currently assumes that each new allocation will
28 // last as long or longer than each prior allocation.
29 //
30 // Buffer pool is used to implement a variety of data streaming operations in Metal, such
31 // as for immediate vertex array and element array data, and other dynamic data.
32 //
33 // Internally buffer pool keeps a collection of mtl::Buffer. When we write past the end of a
34 // currently active mtl::Buffer we keep it until it is no longer in use. We then mark it available
35 // for future allocations in a free list.
36 class BufferPool
37 {
38   public:
39     BufferPool();
40     // - alwaysAllocNewBuffer=true will always allocate new buffer or reuse free buffer on
41     // allocate(), regardless of whether current buffer still has unused portion or not.
42     BufferPool(bool alwaysAllocNewBuffer);
43     ~BufferPool();
44 
45     // Init is called after the buffer creation so that the alignment can be specified later.
46     void initialize(Context *context, size_t initialSize, size_t alignment, size_t maxBuffers);
47     // Calling this without initialize() will have same effect as calling initialize().
48     // If called after initialize(), the old pending buffers will be flushed and might be re-used if
49     // their size are big enough for the requested initialSize parameter.
50     angle::Result reset(ContextMtl *contextMtl,
51                         size_t initialSize,
52                         size_t alignment,
53                         size_t maxBuffers);
54 
55     // This call will allocate a new region at the end of the buffer. It internally may trigger
56     // a new buffer to be created (which is returned in the optional parameter
57     // `newBufferAllocatedOut`).  The new region will be in the returned buffer at given offset. If
58     // a memory pointer is given, the buffer will be automatically map()ed.
59     angle::Result allocate(ContextMtl *contextMtl,
60                            size_t sizeInBytes,
61                            uint8_t **ptrOut            = nullptr,
62                            BufferRef *bufferOut        = nullptr,
63                            size_t *offsetOut           = nullptr,
64                            bool *newBufferAllocatedOut = nullptr);
65 
66     // After a sequence of CPU writes, call commit to ensure the data is visible to the GPU.
67     // Note: the data will only be made visible to the GPU if the buffer's storage mode is not
68     // shared AND a non-null pointer was passed to allocate(). Otherwise, this call only advances
69     // the flush pointer.
70     angle::Result commit(ContextMtl *contextMtl, bool flushEntireBuffer = false);
71 
72     // This releases all the buffers that have been allocated since this was last called.
73     void releaseInFlightBuffers(ContextMtl *contextMtl);
74 
75     // This frees resources immediately.
76     void destroy(ContextMtl *contextMtl);
77 
getCurrentBuffer()78     const BufferRef &getCurrentBuffer() { return mBuffer; }
79 
getAlignment()80     size_t getAlignment() { return mAlignment; }
81     void updateAlignment(Context *context, size_t alignment);
82 
getMaxBuffers()83     size_t getMaxBuffers() const { return mMaxBuffers; }
84 
85     // Set whether allocate() will always allocate new buffer or attempting to append to previous
86     // buffer or not. Default is false.
setAlwaysAllocateNewBuffer(bool e)87     void setAlwaysAllocateNewBuffer(bool e) { mAlwaysAllocateNewBuffer = e; }
88 
89   private:
90     MTLStorageMode storageMode(ContextMtl *contextMtl) const;
91     void reset();
92     angle::Result allocateNewBuffer(ContextMtl *contextMtl);
93     void destroyBufferList(ContextMtl *contextMtl, std::deque<BufferRef> *buffers);
94     angle::Result finalizePendingBuffer(ContextMtl *contextMtl);
95     size_t mInitialSize;
96     BufferRef mBuffer;
97     uint32_t mNextAllocationOffset;
98     uint32_t mLastFlushOffset;
99     size_t mSize;
100     size_t mAlignment;
101 
102     std::deque<BufferRef> mInFlightBuffers;
103     std::deque<BufferRef> mBufferFreeList;
104 
105     size_t mBuffersAllocated;
106     size_t mMaxBuffers;
107     bool mAlwaysAllocateNewBuffer;
108 };
109 
110 }  // namespace mtl
111 }  // namespace rx
112 
113 #endif /* LIBANGLE_RENDERER_METAL_MTL_BUFFER_POOL_H_ */
114