RavEngine
Loading...
Searching...
No Matches
NvFlowReadbackBuffer.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2014-2022 NVIDIA Corporation. All rights reserved.
26
27#pragma once
28
29#include "NvFlowContext.h"
30#include "NvFlowArray.h"
31
33{
34 NvFlowBuffer* buffer = nullptr;
35 NvFlowUint64 bufferSizeInBytes = 0llu;
36 NvFlowBool32 isActive = NV_FLOW_FALSE;
37 NvFlowUint64 completedFrame = ~0llu;
38 NvFlowUint64 completedGlobalFrame = ~0llu;
39 NvFlowUint64 version = ~0llu;
40 NvFlowUint64 validNumBytes = 0llu;
41};
42
44{
45 NvFlowContextInterface* contextInterface = nullptr;
46 NvFlowUint64 versionCounter = 0llu;
47
50};
51
52NV_FLOW_INLINE void NvFlowReadbackBuffer_init(NvFlowContextInterface* contextInterface, NvFlowContext* context, NvFlowReadbackBuffer* ptr)
53{
54 ptr->contextInterface = contextInterface;
55}
56
57NV_FLOW_INLINE void NvFlowReadbackBuffer_destroy(NvFlowContext* context, NvFlowReadbackBuffer* ptr)
58{
59 for (NvFlowUint idx = 0u; idx < ptr->buffers.size; idx++)
60 {
61 if (ptr->buffers[idx].buffer)
62 {
63 ptr->contextInterface->destroyBuffer(context, ptr->buffers[idx].buffer);
64 ptr->buffers[idx].buffer = nullptr;
65 }
66 }
67 ptr->buffers.size = 0u;
68}
69
71{
72 NvFlowUint64 offset;
73 NvFlowUint64 numBytes;
74};
75
76NV_FLOW_INLINE void NvFlowReadbackBuffer_copyN(NvFlowContext* context, NvFlowReadbackBuffer* ptr, NvFlowUint64 numBytes, NvFlowBufferTransient* src, const NvFlowReadbackBufferCopyRange* copyRanges, NvFlowUint copyRangeCount, NvFlowUint64* pOutVersion)
77{
78 // find inactive buffer, create as needed
79 NvFlowUint64 bufferIdx = 0u;
80 for (; bufferIdx < ptr->buffers.size; bufferIdx++)
81 {
82 if (!ptr->buffers[bufferIdx].isActive)
83 {
84 break;
85 }
86 }
87 if (bufferIdx == ptr->buffers.size)
88 {
89 bufferIdx = ptr->buffers.allocateBack();
90 }
91 NvFlowReadbackBufferInstance* inst = &ptr->buffers[bufferIdx];
92
93 // resize buffer as needed
94 if (inst->buffer && inst->bufferSizeInBytes < numBytes)
95 {
96 ptr->contextInterface->destroyBuffer(context, inst->buffer);
97 inst->buffer = nullptr;
98 inst->bufferSizeInBytes = 0llu;
99 }
100 if (!inst->buffer)
101 {
102 NvFlowBufferDesc bufDesc = {};
103 bufDesc.usageFlags = eNvFlowBufferUsage_bufferCopyDst;
104 bufDesc.format = eNvFlowFormat_unknown;
105 bufDesc.structureStride = 0u;
106 bufDesc.sizeInBytes = 65536u;
107 while (bufDesc.sizeInBytes < numBytes)
108 {
109 bufDesc.sizeInBytes *= 2u;
110 }
111
112 inst->buffer = ptr->contextInterface->createBuffer(context, eNvFlowMemoryType_readback, &bufDesc);
113 inst->bufferSizeInBytes = bufDesc.sizeInBytes;
114 }
115
116 // set active state
117 ptr->versionCounter++;
118 inst->isActive = NV_FLOW_TRUE;
119 inst->completedFrame = ptr->contextInterface->getCurrentFrame(context);
120 inst->completedGlobalFrame = ptr->contextInterface->getCurrentGlobalFrame(context);
121 inst->version = ptr->versionCounter;
122 inst->validNumBytes = numBytes;
123 if (pOutVersion)
124 {
125 *pOutVersion = inst->version;
126 }
127
128 // copy
129 NvFlowBufferTransient* dst = ptr->contextInterface->registerBufferAsTransient(context, inst->buffer);
130 for (NvFlowUint copyRangeIdx = 0u; copyRangeIdx < copyRangeCount; copyRangeIdx++)
131 {
132 NvFlowPassCopyBufferParams copyParams = {};
133 copyParams.srcOffset = copyRanges[copyRangeIdx].offset;
134 copyParams.dstOffset = copyRanges[copyRangeIdx].offset;
135 copyParams.numBytes = copyRanges[copyRangeIdx].numBytes;
136 copyParams.src = src;
137 copyParams.dst = dst;
138
139 copyParams.debugLabel = "ReadbackBufferCopy";
140
141 ptr->contextInterface->addPassCopyBuffer(context, &copyParams);
142 }
143 if (copyRangeCount == 0u)
144 {
145 NvFlowPassCopyBufferParams copyParams = {};
146 copyParams.srcOffset = 0llu;
147 copyParams.dstOffset = 0llu;
148 copyParams.numBytes = 0llu;
149 copyParams.src = src;
150 copyParams.dst = dst;
151
152 copyParams.debugLabel = "ReadbackBufferCopy";
153
154 ptr->contextInterface->addPassCopyBuffer(context, &copyParams);
155 }
156
157 // push on active queue
158 ptr->activeBuffers.pushBack(bufferIdx);
159}
160
161NV_FLOW_INLINE void NvFlowReadbackBuffer_copy(NvFlowContext* context, NvFlowReadbackBuffer* ptr, NvFlowUint64 numBytes, NvFlowBufferTransient* src, NvFlowUint64* pOutVersion)
162{
163 NvFlowReadbackBufferCopyRange copyRange = { 0llu, numBytes };
164 NvFlowReadbackBuffer_copyN(context, ptr, numBytes, src, &copyRange, 1u, pOutVersion);
165}
166
167NV_FLOW_INLINE void NvFlowReadbackBuffer_flush(NvFlowContext* context, NvFlowReadbackBuffer* ptr)
168{
169 // flush queue
170 NvFlowUint completedCount = 0u;
171 NvFlowUint64 lastFenceCompleted = ptr->contextInterface->getLastFrameCompleted(context);
172 for (NvFlowUint activeBufferIdx = 0u; activeBufferIdx < ptr->activeBuffers.size; activeBufferIdx++)
173 {
174 if (ptr->buffers[ptr->activeBuffers[activeBufferIdx]].completedFrame > lastFenceCompleted)
175 {
176 break;
177 }
178 completedCount++;
179 }
180 NvFlowUint popCount = completedCount >= 2u ? completedCount - 1u : 0u;
181 if (popCount > 0u)
182 {
183 for (NvFlowUint activeBufferIdx = 0u; activeBufferIdx < popCount; activeBufferIdx++)
184 {
185 ptr->buffers[ptr->activeBuffers[activeBufferIdx]].isActive = NV_FLOW_FALSE;
186 }
187 // compact
188 for (NvFlowUint activeBufferIdx = popCount; activeBufferIdx < ptr->activeBuffers.size; activeBufferIdx++)
189 {
190 ptr->activeBuffers[activeBufferIdx - popCount] = ptr->activeBuffers[activeBufferIdx];
191 }
192 ptr->activeBuffers.size = ptr->activeBuffers.size - popCount;
193 }
194}
195
196NV_FLOW_INLINE NvFlowUint NvFlowReadbackBuffer_getActiveCount(NvFlowContext* context, NvFlowReadbackBuffer* ptr)
197{
198 return (NvFlowUint)ptr->activeBuffers.size;
199}
200
201NV_FLOW_INLINE NvFlowUint64 NvFlowReadbackBuffer_getCompletedGlobalFrame(NvFlowContext* context, NvFlowReadbackBuffer* ptr, NvFlowUint activeIdx)
202{
203 if (activeIdx < ptr->activeBuffers.size)
204 {
205 return ptr->buffers[ptr->activeBuffers[activeIdx]].completedGlobalFrame;
206 }
207 return ~0llu;
208}
209
210NV_FLOW_INLINE void* NvFlowReadbackBuffer_map(NvFlowContext* context, NvFlowReadbackBuffer* ptr, NvFlowUint activeIdx, NvFlowUint64* pOutVersion, NvFlowUint64* pNumBytes)
211{
212 if (activeIdx > ptr->activeBuffers.size)
213 {
214 if (pOutVersion)
215 {
216 *pOutVersion = 0llu;
217 }
218 if (pNumBytes)
219 {
220 *pNumBytes = 0llu;
221 }
222 return nullptr;
223 }
224
225 NvFlowReadbackBufferInstance* inst = &ptr->buffers[ptr->activeBuffers[activeIdx]];
226 if (pOutVersion)
227 {
228 *pOutVersion = inst->version;
229 }
230 if (pNumBytes)
231 {
232 *pNumBytes = inst->validNumBytes;
233 }
234 return ptr->contextInterface->mapBuffer(context, inst->buffer);
235}
236
237NV_FLOW_INLINE void* NvFlowReadbackBuffer_mapLatest(NvFlowContext* context, NvFlowReadbackBuffer* ptr, NvFlowUint64* pOutVersion, NvFlowUint64* pNumBytes)
238{
239 NvFlowReadbackBuffer_flush(context, ptr);
240
241 NvFlowUint64 lastFenceCompleted = ptr->contextInterface->getLastFrameCompleted(context);
242 bool shouldMap = true;
243 if (ptr->activeBuffers.size > 0u)
244 {
245 if (ptr->buffers[ptr->activeBuffers[0u]].completedFrame > lastFenceCompleted)
246 {
247 shouldMap = false;
248 }
249 }
250 else if (ptr->buffers[ptr->activeBuffers[0u]].completedFrame > lastFenceCompleted)
251 {
252 shouldMap = false;
253 }
254 if (!shouldMap)
255 {
256 if (pOutVersion)
257 {
258 *pOutVersion = 0llu;
259 }
260 if (pNumBytes)
261 {
262 *pNumBytes = 0llu;
263 }
264 return nullptr;
265 }
266
267 return NvFlowReadbackBuffer_map(context, ptr, 0u, pOutVersion, pNumBytes);
268}
269
270NV_FLOW_INLINE void NvFlowReadbackBuffer_unmap(NvFlowContext* context, NvFlowReadbackBuffer* ptr, NvFlowUint activeIdx)
271{
272 if (activeIdx < ptr->activeBuffers.size)
273 {
274 NvFlowReadbackBufferInstance* inst = &ptr->buffers[ptr->activeBuffers[activeIdx]];
275 ptr->contextInterface->unmapBuffer(context, inst->buffer);
276 }
277}
278
279NV_FLOW_INLINE void NvFlowReadbackBuffer_unmapLatest(NvFlowContext* context, NvFlowReadbackBuffer* ptr)
280{
281 NvFlowReadbackBuffer_unmap(context, ptr, 0u);
282}
Definition base.h:1940
Definition NvFlowArray.h:36
Definition NvFlowContext.h:96
Definition NvFlowContext.h:362
Definition NvFlowContext.h:300
Definition NvFlowReadbackBuffer.h:71
Definition NvFlowReadbackBuffer.h:33
Definition NvFlowReadbackBuffer.h:44