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