• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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