1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
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 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "util/render_frame_util.h"
17
18 #include <limits>
19
20 #include <base/containers/fixed_string.h>
21 #include <render/datastore/intf_render_data_store_default_gpu_resource_data_copy.h>
22 #include <render/datastore/intf_render_data_store_default_staging.h>
23 #include <render/datastore/intf_render_data_store_manager.h>
24 #include <render/datastore/intf_render_data_store_pod.h>
25 #include <render/datastore/render_data_store_render_pods.h>
26 #include <render/device/intf_device.h>
27 #include <render/device/intf_gpu_resource_manager.h>
28 #include <render/intf_render_context.h>
29
30 #include "device/device.h"
31 #include "device/gpu_resource_manager.h"
32 #include "device/gpu_semaphore.h"
33 #include "util/log.h"
34
35 RENDER_BEGIN_NAMESPACE()
36 using namespace BASE_NS;
37
38 namespace {
39 const string_view RENDER_DATA_STORE_DEFAULT_STAGING { "RenderDataStoreDefaultStaging" };
40 const string_view RENDER_DATA_STORE_DEFAULT_DATA_COPY { "RenderDataStoreDefaultGpuResourceDataCopy" };
41 const string_view RENDER_DATA_STORE_POD { "RenderDataStorePod" };
42 const string_view POD_NAME { "NodeGraphBackBufferConfiguration" };
43
GetStagingBufferDesc(const uint32_t byteSize,const EngineBufferCreationFlags engineBufferCreationAdditionalFlags)44 GpuBufferDesc GetStagingBufferDesc(
45 const uint32_t byteSize, const EngineBufferCreationFlags engineBufferCreationAdditionalFlags)
46 {
47 return GpuBufferDesc {
48 CORE_BUFFER_USAGE_TRANSFER_DST_BIT,
49 CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT | CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
50 CORE_ENGINE_BUFFER_CREATION_DYNAMIC_BARRIERS | engineBufferCreationAdditionalFlags,
51 byteSize,
52 {},
53 };
54 }
55 } // namespace
56
RenderFrameUtil(const IRenderContext & renderContext)57 RenderFrameUtil::RenderFrameUtil(const IRenderContext& renderContext)
58 : renderContext_(renderContext), device_(renderContext_.GetDevice())
59 {
60 bufferedPostFrame_.resize(device_.GetDeviceConfiguration().bufferingCount);
61 defaultCopyData_.byteBuffer = make_unique<ByteArray>(0U);
62
63 const IRenderDataStoreManager& dsManager = renderContext.GetRenderDataStoreManager();
64 dsStaging_ = static_cast<IRenderDataStoreDefaultStaging*>(
65 dsManager.GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_STAGING).get());
66 PLUGIN_ASSERT(dsStaging_);
67 dsCpuToGpuCopy_ = static_cast<IRenderDataStoreDefaultGpuResourceDataCopy*>(
68 dsManager.GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_DATA_COPY).get());
69 PLUGIN_ASSERT(dsCpuToGpuCopy_);
70 }
71
BeginFrame()72 void RenderFrameUtil::BeginFrame()
73 {
74 frameHasWaitForIdle_ = false;
75 {
76 auto ClearAndReserve = [](const size_t count, auto& frameData) {
77 frameData.copyData.clear();
78 frameData.copyData.reserve(count);
79 };
80
81 const auto lock = std::lock_guard(mutex_);
82
83 thisFrameCopiedData_.clear();
84 const uint64_t frameIndex = device_.GetFrameCount();
85 for (auto& ref : thisFrameSignalData_.gpuSemaphores) {
86 if (ref) {
87 gpuSignalDeferredDestroy_.push_back({ frameIndex, move(ref) });
88 }
89 }
90 thisFrameSignalData_.gpuSemaphores.clear();
91 thisFrameSignalData_.signalData.clear();
92
93 // process backbuffer
94 postBackBufferConfig_ = preBackBufferConfig_; // NOTE: copy
95 // process copies
96 const size_t count = preFrame_.copyData.size();
97 auto& bufferedPostFrame = bufferedPostFrame_[bufferedIndex_];
98 ClearAndReserve(count, postFrame_);
99 ClearAndReserve(count, bufferedPostFrame);
100 for (size_t idx = 0; idx < count; ++idx) {
101 if (preFrame_.copyData[idx].copyFlags == CopyFlagBits::WAIT_FOR_IDLE) {
102 postFrame_.copyData.push_back(preFrame_.copyData[idx]);
103 frameHasWaitForIdle_ = true;
104 } else {
105 bufferedPostFrame.copyData.push_back(preFrame_.copyData[idx]);
106 }
107 }
108 preFrame_.copyData.clear();
109 // process signals
110 postSignalData_ = move(preSignalData_);
111 preSignalData_.clear();
112 }
113 // advance to next buffer position, the copies are done for the oldest data
114 bufferedIndex_ = (bufferedIndex_ + 1) % bufferedPostFrame_.size();
115
116 // process deferred destruction
117 ProcessFrameSignalDeferredDestroy();
118
119 ProcessFrameCopyData();
120 ProcessFrameSignalData();
121 ProcessFrameBackBufferConfiguration();
122 }
123
ProcessFrameCopyData()124 void RenderFrameUtil::ProcessFrameCopyData()
125 {
126 // try to reserve
127 thisFrameCopiedData_.reserve(postFrame_.copyData.size() + bufferedPostFrame_[bufferedIndex_].copyData.size());
128
129 // wait for idle
130 ProcessFrameInputCopyData(postFrame_);
131 // copy everything if wait for idle has been added
132 if (frameHasWaitForIdle_) {
133 for (auto& ref : bufferedPostFrame_) {
134 ProcessFrameInputCopyData(ref);
135 }
136 } else {
137 ProcessFrameInputCopyData(bufferedPostFrame_[bufferedIndex_]);
138 }
139 }
140
ProcessFrameInputCopyData(const RenderFrameUtil::CopyData & copyData)141 void RenderFrameUtil::ProcessFrameInputCopyData(const RenderFrameUtil::CopyData& copyData)
142 {
143 IGpuResourceManager& gpuResourceMgr = device_.GetGpuResourceManager();
144 const auto count = static_cast<uint32_t>(copyData.copyData.size());
145 for (uint32_t idx = 0; idx < count; ++idx) {
146 const auto& dataToBeCopied = copyData.copyData[idx];
147 const RenderHandleType type = dataToBeCopied.handle.GetHandleType();
148 thisFrameCopiedData_.push_back({});
149 auto& copyDataRef = thisFrameCopiedData_.back();
150 copyDataRef = { {}, dataToBeCopied.frameIndex, dataToBeCopied.handle, dataToBeCopied.copyFlags, {} };
151
152 const bool byteBufferCopy = ((dataToBeCopied.copyFlags & IRenderFrameUtil::GPU_BUFFER_ONLY) == 0);
153 const EngineBufferCreationFlags ebcf = byteBufferCopy ? 0U : CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER;
154 if (type == RenderHandleType::GPU_BUFFER) {
155 const GpuBufferDesc desc = gpuResourceMgr.GetBufferDescriptor(dataToBeCopied.handle);
156 const uint32_t byteSize = desc.byteSize;
157
158 copyDataRef.bufferHandle = gpuResourceMgr.Create(GetStagingBufferDesc(byteSize, ebcf));
159 // byte buffer only created if needed
160 if (byteBufferCopy) {
161 copyDataRef.byteBuffer = make_unique<ByteArray>(byteSize);
162 }
163
164 const BufferCopy bc {
165 0, // srcOffset
166 0, // dstOffset
167 byteSize, // size
168 };
169 dsStaging_->CopyBufferToBuffer(dataToBeCopied.handle, copyDataRef.bufferHandle, bc,
170 IRenderDataStoreDefaultStaging::ResourceCopyInfo::END_FRAME);
171 } else if (type == RenderHandleType::GPU_IMAGE) {
172 const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(dataToBeCopied.handle);
173 const uint32_t bytesPerPixel = gpuResourceMgr.GetFormatProperties(dataToBeCopied.handle).bytesPerPixel;
174 const uint32_t byteSize = desc.width * desc.height * bytesPerPixel;
175
176 copyDataRef.bufferHandle = gpuResourceMgr.Create(GetStagingBufferDesc(byteSize, ebcf));
177 if (byteBufferCopy) {
178 copyDataRef.byteBuffer = make_unique<ByteArray>(byteSize);
179 }
180
181 const BufferImageCopy bic {
182 0, // bufferOffset
183 0, // bufferRowLength
184 0, // bufferImageHeight
185 ImageSubresourceLayers { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1u }, // imageSubresource
186 Size3D { 0, 0, 0 }, // imageOffset
187 Size3D { desc.width, desc.height, 1u }, // imageExtent
188 };
189 dsStaging_->CopyImageToBuffer(dataToBeCopied.handle, copyDataRef.bufferHandle, bic,
190 IRenderDataStoreDefaultStaging::ResourceCopyInfo::END_FRAME);
191 }
192
193 if (copyDataRef.byteBuffer && copyDataRef.bufferHandle) {
194 IRenderDataStoreDefaultGpuResourceDataCopy::GpuResourceDataCopy dataCopy;
195 if (copyDataRef.copyFlags & CopyFlagBits::WAIT_FOR_IDLE) {
196 dataCopy.copyType = IRenderDataStoreDefaultGpuResourceDataCopy::CopyType::WAIT_FOR_IDLE;
197 }
198 dataCopy.gpuHandle = copyDataRef.bufferHandle;
199 dataCopy.byteArray = copyDataRef.byteBuffer.get();
200 dsCpuToGpuCopy_->AddCopyOperation(dataCopy);
201 }
202 }
203 }
204
ProcessFrameSignalData()205 void RenderFrameUtil::ProcessFrameSignalData()
206 {
207 // try to reserve
208 thisFrameSignalData_.gpuSemaphores.reserve(postSignalData_.size());
209 thisFrameSignalData_.signalData.reserve(postSignalData_.size());
210
211 auto& device = (Device&)device_;
212 const DeviceBackendType backendType = device.GetBackendType();
213 // check the input data and create possible semaphores
214 for (const auto& ref : postSignalData_) {
215 SignalData sd = ref;
216 sd.signalResourceType = (backendType == DeviceBackendType::VULKAN) ? SignalResourceType::GPU_SEMAPHORE
217 : SignalResourceType::GPU_FENCE;
218 if (ref.gpuSignalResourceHandle) { // input signal handle given
219 // validity checked with input method
220 // create a view to external handle
221 thisFrameSignalData_.gpuSemaphores.push_back(device.CreateGpuSemaphoreView(ref.gpuSignalResourceHandle));
222 } else {
223 // create semaphore
224 thisFrameSignalData_.gpuSemaphores.push_back(device.CreateGpuSemaphore());
225 }
226 sd.gpuSignalResourceHandle = thisFrameSignalData_.gpuSemaphores.back()->GetHandle();
227 thisFrameSignalData_.signalData.push_back(sd);
228 }
229 }
230
ProcessFrameBackBufferConfiguration()231 void RenderFrameUtil::ProcessFrameBackBufferConfiguration()
232 {
233 if (postBackBufferConfig_.force) {
234 const auto& rdsMgr = renderContext_.GetRenderDataStoreManager();
235 if (refcnt_ptr<IRenderDataStorePod> dataStorePod = rdsMgr.GetRenderDataStore(RENDER_DATA_STORE_POD)) {
236 NodeGraphBackBufferConfiguration ngbbc;
237 ngbbc.backBufferName[postBackBufferConfig_.bbc.backBufferName.copy(
238 ngbbc.backBufferName, countof(ngbbc.backBufferName) - 1)] = '\0';
239 ngbbc.backBufferType =
240 static_cast<NodeGraphBackBufferConfiguration::BackBufferType>(postBackBufferConfig_.bbc.backBufferType);
241 ngbbc.backBufferHandle = postBackBufferConfig_.bbc.backBufferHandle.GetHandle();
242 ngbbc.gpuBufferHandle = postBackBufferConfig_.bbc.gpuBufferHandle.GetHandle();
243 ngbbc.present = postBackBufferConfig_.bbc.present;
244 ngbbc.gpuSemaphoreHandle = postBackBufferConfig_.bbc.gpuSemaphoreHandle;
245
246 dataStorePod->Set(POD_NAME, arrayviewU8(ngbbc));
247 }
248 }
249 }
250
ProcessFrameSignalDeferredDestroy()251 void RenderFrameUtil::ProcessFrameSignalDeferredDestroy()
252 {
253 // already used in previous frame
254 const auto& device = (const Device&)device_;
255 const uint64_t frameCount = device.GetFrameCount();
256 const auto minAge = device.GetCommandBufferingCount();
257 const auto ageLimit = (frameCount < minAge) ? 0 : (frameCount - minAge);
258
259 for (auto iter = gpuSignalDeferredDestroy_.begin(); iter != gpuSignalDeferredDestroy_.end();) {
260 if (iter->frameUseIndex < ageLimit) {
261 iter = gpuSignalDeferredDestroy_.erase(iter);
262 } else {
263 ++iter;
264 }
265 }
266 }
267
EndFrame()268 void RenderFrameUtil::EndFrame()
269 {
270 frameHasWaitForIdle_ = false;
271
272 postFrame_.copyData.clear();
273 if (frameHasWaitForIdle_) {
274 for (auto& ref : bufferedPostFrame_) {
275 ref.copyData.clear();
276 }
277 } else {
278 bufferedPostFrame_[bufferedIndex_].copyData.clear();
279 }
280 }
281
CopyToCpu(const RenderHandleReference & handle,const CopyFlags flags)282 void RenderFrameUtil::CopyToCpu(const RenderHandleReference& handle, const CopyFlags flags)
283 {
284 if (!ValidateInput(handle)) {
285 return;
286 }
287
288 const auto lock = std::lock_guard(mutex_);
289
290 const uint64_t frameIndex = device_.GetFrameCount();
291 preFrame_.copyData.push_back({ frameIndex, handle, flags });
292 }
293
ValidateInput(const RenderHandleReference & handle)294 bool RenderFrameUtil::ValidateInput(const RenderHandleReference& handle)
295 {
296 bool valid = true;
297 const RenderHandleType type = handle.GetHandleType();
298 IGpuResourceManager& gpuResourceMgr = device_.GetGpuResourceManager();
299 if (type == RenderHandleType::GPU_BUFFER) {
300 const GpuBufferDesc desc = gpuResourceMgr.GetBufferDescriptor(handle);
301 if ((desc.usageFlags & BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT) == 0) {
302 valid = false;
303 #if (RENDER_VALIDATION_ENABLED == 1)
304 const string strId = string("rfu_CopyToCpu_") + BASE_NS::to_string(handle.GetHandle().id);
305 PLUGIN_LOG_ONCE_W(strId.c_str(),
306 "Render frame util needs usage flag CORE_BUFFER_USAGE_TRANSFER_SRC_BIT to CPU copies. (name:%s)",
307 gpuResourceMgr.GetName(handle).c_str());
308 #endif
309 }
310 } else if (type == RenderHandleType::GPU_IMAGE) {
311 const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(handle);
312 if ((desc.usageFlags & BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT) == 0) {
313 valid = false;
314 #if (RENDER_VALIDATION_ENABLED == 1)
315 const string strId = string("rfu_CopyToCpu_") + BASE_NS::to_string(handle.GetHandle().id);
316 PLUGIN_LOG_ONCE_W(strId.c_str(),
317 "Render frame util needs usage flag CORE_BUFFER_USAGE_TRANSFER_SRC_BIT to CPU copies. (name:%s)",
318 gpuResourceMgr.GetName(handle).c_str());
319 #endif
320 }
321 } else {
322 valid = false;
323 #if (RENDER_VALIDATION_ENABLED == 1)
324 const string strId = string("rfu_CopyToCpu_") + BASE_NS::to_string(handle.GetHandle().id);
325 PLUGIN_LOG_ONCE_W(strId.c_str(), "Render frame util CopyToCpu works only on GPU buffers and images.");
326 #endif
327 }
328 return valid;
329 }
330
GetFrameCopyData()331 array_view<IRenderFrameUtil::FrameCopyData> RenderFrameUtil::GetFrameCopyData()
332 {
333 // NOTE: not thread safe (should not be called during rendering)
334 return thisFrameCopiedData_;
335 }
336
GetFrameCopyData(const RenderHandleReference & handle)337 const IRenderFrameUtil::FrameCopyData& RenderFrameUtil::GetFrameCopyData(const RenderHandleReference& handle)
338 {
339 // NOTE: not thread safe (should not be called during rendering)
340 if (handle) {
341 const RenderHandle rawHandle = handle.GetHandle();
342 for (const auto& ref : thisFrameCopiedData_) {
343 if (ref.handle.GetHandle() == rawHandle) {
344 return ref;
345 }
346 }
347 }
348 return defaultCopyData_;
349 }
350
SetBackBufferConfiguration(const BackBufferConfiguration & backBufferConfiguration)351 void RenderFrameUtil::SetBackBufferConfiguration(const BackBufferConfiguration& backBufferConfiguration)
352 {
353 const auto lock = std::lock_guard(mutex_);
354
355 preBackBufferConfig_.force = true;
356 preBackBufferConfig_.bbc = backBufferConfiguration;
357 }
358
AddGpuSignal(const SignalData & signalData)359 void RenderFrameUtil::AddGpuSignal(const SignalData& signalData)
360 {
361 bool valid = true;
362 if (signalData.signaled) {
363 valid = false;
364 PLUGIN_LOG_E("Already signalled GPU signal cannot be processed. (Not supported)");
365 }
366 if (signalData.gpuSignalResourceHandle) {
367 const DeviceBackendType backendType = device_.GetBackendType();
368 const SignalResourceType signalResourceType = signalData.signalResourceType;
369 if ((backendType == DeviceBackendType::VULKAN) && (signalResourceType != SignalResourceType::GPU_SEMAPHORE)) {
370 valid = false;
371 } else if ((backendType != DeviceBackendType::VULKAN) &&
372 (signalResourceType != SignalResourceType::GPU_FENCE)) {
373 valid = false;
374 }
375 if (!valid) {
376 PLUGIN_LOG_E("Invalid signal type (%u) for platform (%u)", static_cast<uint32_t>(signalResourceType),
377 static_cast<uint32_t>(backendType));
378 }
379 }
380
381 if (valid) {
382 const auto lock = std::lock_guard(mutex_);
383
384 preSignalData_.push_back(signalData);
385 }
386 }
387
GetFrameGpuSignalData()388 BASE_NS::array_view<IRenderFrameUtil::SignalData> RenderFrameUtil::GetFrameGpuSignalData()
389 {
390 // NOTE: not thread safe (should not be called during rendering)
391 return thisFrameSignalData_.signalData;
392 }
393
GetFrameGpuSignalData(const RenderHandleReference & handle)394 IRenderFrameUtil::SignalData RenderFrameUtil::GetFrameGpuSignalData(const RenderHandleReference& handle)
395 {
396 // NOTE: not thread safe (should not be called during rendering)
397 if (handle) {
398 const RenderHandle rawHandle = handle.GetHandle();
399 for (const auto& ref : thisFrameSignalData_.signalData) {
400 if (ref.handle.GetHandle() == rawHandle) {
401 return ref;
402 }
403 }
404 }
405 return {};
406 }
407
HasGpuSignals() const408 bool RenderFrameUtil::HasGpuSignals() const
409 {
410 return !thisFrameSignalData_.gpuSemaphores.empty();
411 }
412
GetGpuSemaphores()413 array_view<unique_ptr<GpuSemaphore>> RenderFrameUtil::GetGpuSemaphores()
414 {
415 return thisFrameSignalData_.gpuSemaphores;
416 }
417
418 RENDER_END_NAMESPACE()
419