Hash :
ee64836f
Author :
Date :
2023-02-11T17:56:06
Revert "Metal: Optimized BufferSubData per device" This reverts commit 968041b54770af8917001d8fe9b52a881cfed0b2. Includes the following patches: git revert -n 995db1f66bcf87fc9e47d908fb2a885e810d2567 \ 9a6c90c8f802b4d107a081bfccaf4be007e7af54 \ dbd47e378582ef86db52c7379cd220cf0b2c8193 \ 369b320f92f54774879e8b8faff834fc8db0793e \ 4abae6f97586448712e2dc1cced4a678b0901d7b \ 968041b54770af8917001d8fe9b52a881cfed0b2 Several conflicts with top-of-tree were resolved during this revert. The aim is to reland this with additional code which will reduce the amount of excess buffer memory allocated, and release the resources associated with temporary buffer allocations. Bug: angleproject:7544 Change-Id: Ib7a6bc2ab1c2f23cb43112cd980106e2898c3826 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4240556 Reviewed-by: Kimmo Kinnunen <kkinnunen@apple.com> Reviewed-by: Gregg Tavares <gman@chromium.org> Commit-Queue: Kenneth Russell <kbr@chromium.org>
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 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// mtl_buffer_pool.h:
// Defines class interface for BufferPool, managing a pool of mtl::Buffer
//
#ifndef LIBANGLE_RENDERER_METAL_MTL_BUFFER_POOL_H_
#define LIBANGLE_RENDERER_METAL_MTL_BUFFER_POOL_H_
#include "libANGLE/renderer/metal/mtl_resources.h"
#include <deque>
namespace rx
{
class ContextMtl;
namespace mtl
{
enum class BufferPoolMemPolicy
{
// Always allocate buffer in shared memory, useful for dynamic small buffer.
// This translates to MTLResourceStorageModeShared.
AlwaysSharedMem,
// Always allocate buffer in GPU dedicated memory. Note: a CPU side copy is also allocated so
// that buffer can still be mapped on CPU side.
// This translates to MTLResourceStorageModeManaged on macOS or MTLResourceStorageModeShared on
// iOS.
AlwaysGPUMem,
// Auto allocate buffer in shared memory if it is small. GPU otherwise.
Auto,
};
// A buffer pool is conceptually an infinitely long buffer. Each time you write to the buffer,
// you will always write to a previously unused portion. After a series of writes, you must flush
// the buffer data to the device. Buffer lifetime currently assumes that each new allocation will
// last as long or longer than each prior allocation.
//
// Buffer pool is used to implement a variety of data streaming operations in Metal, such
// as for immediate vertex array and element array data, and other dynamic data.
//
// Internally buffer pool keeps a collection of mtl::Buffer. When we write past the end of a
// currently active mtl::Buffer we keep it until it is no longer in use. We then mark it available
// for future allocations in a free list.
class BufferPool
{
public:
BufferPool();
// - alwaysAllocNewBuffer=true will always allocate new buffer or reuse free buffer on
// allocate(), regardless of whether current buffer still has unused portion or not.
// - memPolicy: indicate the allocated buffers should be in shared memory or not.
// See BufferPoolMemPolicy.
BufferPool(bool alwaysAllocNewBuffer);
BufferPool(bool alwaysAllocNewBuffer, BufferPoolMemPolicy memPolicy);
~BufferPool();
// Init is called after the buffer creation so that the alignment can be specified later.
void initialize(Context *context, size_t initialSize, size_t alignment, size_t maxBuffers);
// Calling this without initialize() will have same effect as calling initialize().
// If called after initialize(), the old pending buffers will be flushed and might be re-used if
// their size are big enough for the requested initialSize parameter.
angle::Result reset(ContextMtl *contextMtl,
size_t initialSize,
size_t alignment,
size_t maxBuffers);
// This call will allocate a new region at the end of the buffer. It internally may trigger
// a new buffer to be created (which is returned in the optional parameter
// `newBufferAllocatedOut`). The new region will be in the returned buffer at given offset. If
// a memory pointer is given, the buffer will be automatically map()ed.
angle::Result allocate(ContextMtl *contextMtl,
size_t sizeInBytes,
uint8_t **ptrOut = nullptr,
BufferRef *bufferOut = nullptr,
size_t *offsetOut = nullptr,
bool *newBufferAllocatedOut = nullptr);
// After a sequence of CPU writes, call commit to ensure the data is visible to the GPU.
// Note: the data will only be made visible to the GPU if the buffer's storage mode is not
// shared AND a non-null pointer was passed to allocate(). Otherwise, this call only advances
// the flush pointer.
angle::Result commit(ContextMtl *contextMtl, bool flushEntireBuffer = false);
// This releases all the buffers that have been allocated since this was last called.
void releaseInFlightBuffers(ContextMtl *contextMtl);
// This frees resources immediately.
void destroy(ContextMtl *contextMtl);
const BufferRef &getCurrentBuffer() { return mBuffer; }
size_t getAlignment() { return mAlignment; }
void updateAlignment(Context *context, size_t alignment);
size_t getMaxBuffers() const { return mMaxBuffers; }
// Set whether allocate() will always allocate new buffer or attempting to append to previous
// buffer or not. Default is false.
void setAlwaysAllocateNewBuffer(bool e) { mAlwaysAllocateNewBuffer = e; }
void setMemoryPolicy(BufferPoolMemPolicy policy) { mMemPolicy = policy; }
// Set all subsequent allocated buffers should always use shared memory
void setAlwaysUseSharedMem() { setMemoryPolicy(BufferPoolMemPolicy::AlwaysSharedMem); }
// Set all subsequent allocated buffers should always use GPU memory
void setAlwaysUseGPUMem() { setMemoryPolicy(BufferPoolMemPolicy::AlwaysGPUMem); }
private:
bool shouldAllocateInSharedMem(ContextMtl *contextMtl) const;
void reset();
angle::Result allocateNewBuffer(ContextMtl *contextMtl);
void destroyBufferList(ContextMtl *contextMtl, std::deque<BufferRef> *buffers);
angle::Result finalizePendingBuffer(ContextMtl *contextMtl);
size_t mInitialSize;
BufferRef mBuffer;
uint32_t mNextAllocationOffset;
uint32_t mLastFlushOffset;
size_t mSize;
size_t mAlignment;
std::deque<BufferRef> mInFlightBuffers;
std::deque<BufferRef> mBufferFreeList;
size_t mBuffersAllocated;
size_t mMaxBuffers;
BufferPoolMemPolicy mMemPolicy;
bool mAlwaysAllocateNewBuffer;
};
} // namespace mtl
} // namespace rx
#endif /* LIBANGLE_RENDERER_METAL_MTL_BUFFER_POOL_H_ */