xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/AllocatorHelperRing.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2022 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 // AllocatorHelperRing:
7 //    Manages the ring buffer allocators used in the command buffers.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_VULKAN_ALLOCATORHELPERRING_H_
11 #define LIBANGLE_RENDERER_VULKAN_ALLOCATORHELPERRING_H_
12 
13 #include "common/RingBufferAllocator.h"
14 #include "common/vulkan/vk_headers.h"
15 #include "libANGLE/renderer/vulkan/vk_command_buffer_utils.h"
16 #include "libANGLE/renderer/vulkan/vk_wrapper.h"
17 
18 namespace rx
19 {
20 namespace vk
21 {
22 namespace priv
23 {
24 class SecondaryCommandBuffer;
25 }  // namespace priv
26 
27 using SharedCommandMemoryAllocator = angle::SharedRingBufferAllocator;
28 using RingBufferAllocator          = angle::RingBufferAllocator;
29 
30 // Used in CommandBufferHelperCommon
31 class SharedCommandBlockAllocator
32 {
33   public:
SharedCommandBlockAllocator()34     SharedCommandBlockAllocator() : mAllocator(nullptr), mAllocSharedCP(nullptr) {}
35     void resetAllocator();
hasAllocatorLinks()36     bool hasAllocatorLinks() const { return mAllocator || mAllocSharedCP; }
37 
init()38     void init() {}
39 
40     void attachAllocator(SharedCommandMemoryAllocator *allocator);
41     SharedCommandMemoryAllocator *detachAllocator(bool isCommandBufferEmpty);
42 
getAllocator()43     SharedCommandMemoryAllocator *getAllocator() { return mAllocator; }
44 
45   private:
46     // Using a ring buffer allocator for less memory overhead (observed with enabled async queue)
47     SharedCommandMemoryAllocator *mAllocator;
48     angle::SharedRingBufferAllocatorCheckPoint *mAllocSharedCP;
49     angle::RingBufferAllocatorCheckPoint mAllocReleaseCP;
50 };
51 
52 // Used in SecondaryCommandBuffer
53 class SharedCommandBlockPool final : angle::RingBufferAllocateListener
54 {
55   public:
SharedCommandBlockPool()56     SharedCommandBlockPool()
57         : mLastCommandBlock(nullptr), mFinishedCommandSize(0), mCommandBuffer(nullptr)
58     {}
59 
60     static constexpr size_t kCommandHeaderSize = 4;
61     using CommandHeaderIDType                  = uint16_t;
62     // Make sure the size of command header ID type is less than total command header size.
63     static_assert(sizeof(CommandHeaderIDType) < kCommandHeaderSize, "Check size of CommandHeader");
64 
setCommandBuffer(priv::SecondaryCommandBuffer * commandBuffer)65     void setCommandBuffer(priv::SecondaryCommandBuffer *commandBuffer)
66     {
67         mCommandBuffer = commandBuffer;
68     }
resetCommandBuffer()69     void resetCommandBuffer() { mCommandBuffer = nullptr; }
70 
reset(CommandBufferCommandTracker * commandBufferTracker)71     void reset(CommandBufferCommandTracker *commandBufferTracker)
72     {
73         mLastCommandBlock    = nullptr;
74         mFinishedCommandSize = 0;
75         if (mAllocator.valid())
76         {
77             mAllocator.release(mAllocator.getReleaseCheckPoint());
78             pushNewCommandBlock(mAllocator.allocate(0));
79         }
80     }
81 
initialize(SharedCommandMemoryAllocator * allocator)82     angle::Result initialize(SharedCommandMemoryAllocator *allocator)
83     {
84         return angle::Result::Continue;
85     }
86 
87     // Always valid (even if allocator is detached).
valid()88     bool valid() const { return true; }
empty()89     bool empty() const { return getCommandSize() == 0; }
90 
91     void getMemoryUsageStats(size_t *usedMemoryOut, size_t *allocatedMemoryOut) const;
92 
terminateLastCommandBlock()93     void terminateLastCommandBlock()
94     {
95         if (mLastCommandBlock)
96         {
97             ASSERT(mAllocator.valid());
98             ASSERT(mAllocator.getPointer() >= mLastCommandBlock);
99             ASSERT(mAllocator.getFragmentSize() >= kCommandHeaderSize);
100             reinterpret_cast<CommandHeaderIDType &>(*(mAllocator.getPointer())) = 0;
101         }
102     }
103 
104     // Initialize the SecondaryCommandBuffer by setting the allocator it will use
105     void attachAllocator(SharedCommandMemoryAllocator *source);
106     void detachAllocator(SharedCommandMemoryAllocator *destination);
107 
onNewVariableSizedCommand(const size_t requiredSize,const size_t allocationSize,uint8_t ** headerOut)108     void onNewVariableSizedCommand(const size_t requiredSize,
109                                    const size_t allocationSize,
110                                    uint8_t **headerOut)
111     {
112         *headerOut = allocateCommand(allocationSize);
113     }
onNewCommand(const size_t requiredSize,const size_t allocationSize,uint8_t ** headerOut)114     void onNewCommand(const size_t requiredSize, const size_t allocationSize, uint8_t **headerOut)
115     {
116         *headerOut = allocateCommand(allocationSize);
117     }
118 
119   private:
allocateCommand(size_t allocationSize)120     uint8_t *allocateCommand(size_t allocationSize)
121     {
122         ASSERT(mLastCommandBlock);
123         return mAllocator.allocate(static_cast<uint32_t>(allocationSize));
124     }
125 
126     // The following is used to give the size of the command buffer in bytes
getCommandSize()127     uint32_t getCommandSize() const
128     {
129         uint32_t result = mFinishedCommandSize;
130         if (mLastCommandBlock)
131         {
132             ASSERT(mAllocator.valid());
133             ASSERT(mAllocator.getPointer() >= mLastCommandBlock);
134             result += static_cast<uint32_t>(mAllocator.getPointer() - mLastCommandBlock);
135         }
136         return result;
137     }
138 
139     void pushNewCommandBlock(uint8_t *block);
140     void finishLastCommandBlock();
141 
142     // Functions derived from RingBufferAllocateListener
143     virtual void onRingBufferNewFragment() override;
144     virtual void onRingBufferFragmentEnd() override;
145 
146     // Using a ring buffer allocator for less memory overhead (observed with enabled async queue)
147     RingBufferAllocator mAllocator;
148     uint8_t *mLastCommandBlock;
149     uint32_t mFinishedCommandSize;
150 
151     // Points to the parent command buffer.
152     priv::SecondaryCommandBuffer *mCommandBuffer;
153 };
154 
155 }  // namespace vk
156 }  // namespace rx
157 
158 #endif  // LIBANGLE_RENDERER_VULKAN_ALLOCATORHELPERRING_H_
159