Diligent Engine API Reference: D:/GitHub/DiligentEngine/DiligentCore/Graphics/GraphicsAccessories/interface/RingBuffer.h Source File

Diligent Engine API Reference

RingBuffer.h
1 /* Copyright 2015-2018 Egor Yusov
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
12 *
13 * In no event and under no legal theory, whether in tort (including negligence),
14 * contract, or otherwise, unless required by applicable law (such as deliberate
15 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
16 * liable for any damages, including any direct, indirect, special, incidental,
17 * or consequential damages of any character arising as a result of this License or
18 * out of the use or inability to use the software (including but not limited to damages
19 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
20 * all other commercial damages or losses), even if such Contributor has been advised
21 * of the possibility of such damages.
22 */
23
24 #pragma once
25
28
29
30 #include <deque>
31 #include "MemoryAllocator.h"
32 #include "STDAllocator.h"
33 #include "DebugUtilities.h"
34
35 namespace Diligent
36 {
38 class RingBuffer
39 {
40 public:
41 typedef size_t OffsetType;
42 struct FrameTailAttribs
43 {
44 FrameTailAttribs(Uint64 fv, OffsetType off, OffsetType sz) :
45 FenceValue(fv),
46 Offset(off),
47 Size(sz)
48 {}
49
50 // Fence value associated with the command list in which
51 // the allocation could have been referenced last time
52 Uint64 FenceValue;
53 OffsetType Offset;
54 OffsetType Size;
55 };
56 static const OffsetType InvalidOffset = static_cast<OffsetType>(-1);
57
58 RingBuffer(OffsetType MaxSize, IMemoryAllocator &Allocator)noexcept :
59 m_CompletedFrameTails(0, FrameTailAttribs(0,0,0), STD_ALLOCATOR_RAW_MEM(FrameTailAttribs, Allocator, "Allocator for vector<FrameNumOffsetPair>" )),
60 m_MaxSize(MaxSize)
61 {}
62
63 RingBuffer(RingBuffer&& rhs)noexcept :
64 m_CompletedFrameTails(std::move(rhs.m_CompletedFrameTails)),
65 m_Head(rhs.m_Head),
66 m_Tail(rhs.m_Tail),
67 m_MaxSize(rhs.m_MaxSize),
68 m_UsedSize(rhs.m_UsedSize),
69 m_CurrFrameSize(rhs.m_CurrFrameSize)
70 {
71 rhs.m_Head = 0;
72 rhs.m_Tail = 0;
73 rhs.m_MaxSize = 0;
74 rhs.m_UsedSize = 0;
75 rhs.m_CurrFrameSize = 0;
76 }
77
78 RingBuffer& operator = (RingBuffer&& rhs)noexcept
79 {
80 m_CompletedFrameTails = std::move(rhs.m_CompletedFrameTails);
81 m_Head = rhs.m_Head;
82 m_Tail = rhs.m_Tail;
83 m_MaxSize = rhs.m_MaxSize;
84 m_UsedSize = rhs.m_UsedSize;
85 m_CurrFrameSize = rhs.m_CurrFrameSize;
86
87 rhs.m_MaxSize = 0;
88 rhs.m_Head = 0;
89 rhs.m_Tail = 0;
90 rhs.m_UsedSize = 0;
91 rhs.m_CurrFrameSize = 0;
92
93 return *this;
94 }
95
96 RingBuffer(const RingBuffer&) = delete;
97 RingBuffer& operator = (const RingBuffer&) = delete;
98
99 ~RingBuffer()
100 {
101 VERIFY(m_UsedSize==0, "All space in the ring buffer must be released");
102 }
103
104 OffsetType Allocate(OffsetType Size)
105 {
106 if(IsFull())
107 {
108 return InvalidOffset;
109 }
110
111 if (m_Tail >= m_Head )
112 {
113 // Head Tail MaxSize
114 // | | |
115 // [ xxxxxxxxxxxxxxxxx ]
116 //
117 //
118 if (m_Tail + Size <= m_MaxSize)
119 {
120 auto Offset = m_Tail;
121 m_Tail += Size;
122 m_UsedSize += Size;
123 m_CurrFrameSize += Size;
124 return Offset;
125 }
126 else if(Size <= m_Head)
127 {
128 // Allocate from the beginning of the buffer
129 OffsetType AddSize = (m_MaxSize - m_Tail) + Size;
130 m_UsedSize += AddSize;
131 m_CurrFrameSize += AddSize;
132 m_Tail = Size;
133 return 0;
134 }
135 }
136 else if (m_Tail + Size <= m_Head )
137 {
138 //
139 // Tail Head
140 // | |
141 // [xxxx xxxxxxxxxxxxxxxxxxxxxxxxxx]
142 //
143 auto Offset = m_Tail;
144 m_Tail += Size;
145 m_UsedSize += Size;
146 m_CurrFrameSize += Size;
147 return Offset;
148 }
149
150 return InvalidOffset;
151 }
152
153 // FenceValue is the fence value associated with the command list in which the tail
154 // could have been referenced last time
155 // See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-resource-lifetimes/
156 void FinishCurrentFrame(Uint64 FenceValue)
157 {
158 m_CompletedFrameTails.emplace_back(FenceValue, m_Tail, m_CurrFrameSize);
159 m_CurrFrameSize = 0;
160 }
161
162 // CompletedFenceValue indicates GPU progress
163 // See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-resource-lifetimes/
164 void ReleaseCompletedFrames(Uint64 CompletedFenceValue)
165 {
166 // We can release all tails whose associated fence value is less than or equal to CompletedFenceValue
167 while(!m_CompletedFrameTails.empty() && m_CompletedFrameTails.front().FenceValue <= CompletedFenceValue)
168 {
169 const auto &OldestFrameTail = m_CompletedFrameTails.front();
170 VERIFY_EXPR(OldestFrameTail.Size <= m_UsedSize);
171 m_UsedSize -= OldestFrameTail.Size;
172 m_Head = OldestFrameTail.Offset;
173 m_CompletedFrameTails.pop_front();
174 }
175 }
176
177 OffsetType GetMaxSize()const{return m_MaxSize;}
178 bool IsFull()const{ return m_UsedSize==m_MaxSize; };
179 bool IsEmpty()const{ return m_UsedSize==0; };
180 OffsetType GetUsedSize()const{return m_UsedSize;}
181
182 private:
183 // Consider the following scenario for a 1024-byte buffer:
184 // Allocate(512)
185 //
186 // h t m
187 // |xxxxx| |
188
189 // FinishCurrentFrame(0)
190 //
191 // t0
192 // h t m
193 // |xxxxx| |
194
195 // ReleaseCompletedFrames(1)
196 //
197 // h
198 // t m
199 // | | |
200
201 // FinishCurrentFrame(1)
202 //
203 // t1
204 // h
205 // t m
206 // | | |
207
208 // Allocate(512)
209 //
210 // t1 t
211 // h m
212 // | |xxxxx|
213
214 // Allocate(512)
215 //
216 // t
217 // t1
218 // h m
219 // |xxxxx|xxxxx|
220
221 // FinishCurrentFrame(2)
222 //
223 // t
224 // t1
225 // t2
226 // h m
227 // |xxxxx|xxxxx|
228
229 // At this point there will be two tails in the queue, both at 512. m_UsedSize will be 0. When
230 // ReleaseCompletedFrames(2) is called, there wil be no way to find out if the current frame is 0
231 // or the entire buffer if we don't store the frame size
232
233 std::deque< FrameTailAttribs, STDAllocatorRawMem<FrameTailAttribs> > m_CompletedFrameTails;
234 OffsetType m_Head = 0;
235 OffsetType m_Tail = 0;
236 OffsetType m_MaxSize = 0;
237 OffsetType m_UsedSize = 0;
238 OffsetType m_CurrFrameSize = 0;
239 };
240 }
Diligent
Graphics engine namespace.
Definition: AdaptiveFixedBlockAllocator.h:30
Diligent::Uint64
uint64_t Uint64
64-bit unsigned integer
Definition: BasicTypes.h:38
Diligent::IMemoryAllocator
Base interface for a raw memory allocator.
Definition: MemoryAllocator.h:35
Diligent::RingBuffer
Implementation of a ring buffer. The class is not thread-safe.
Definition: RingBuffer.h:38