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