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