1 /*
2 * Copyright (c) 2022 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 =
154 byteBufferCopy
155 ? 0U
156 : (CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER | CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE);
157 if (type == RenderHandleType::GPU_BUFFER) {
158 const GpuBufferDesc desc = gpuResourceMgr.GetBufferDescriptor(dataToBeCopied.handle);
159 const uint32_t byteSize = desc.byteSize;
160
161 copyDataRef.bufferHandle = gpuResourceMgr.Create(GetStagingBufferDesc(byteSize, ebcf));
162 // byte buffer only created if needed
163 if (byteBufferCopy) {
164 copyDataRef.byteBuffer = make_unique<ByteArray>(byteSize);
165 }
166
167 const BufferCopy bc {
168 0, // srcOffset
169 0, // dstOffset
170 byteSize, // size
171 };
172 dsStaging_->CopyBufferToBuffer(dataToBeCopied.handle, copyDataRef.bufferHandle, bc,
173 IRenderDataStoreDefaultStaging::ResourceCopyInfo::END_FRAME);
174 } else if (type == RenderHandleType::GPU_IMAGE) {
175 const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(dataToBeCopied.handle);
176 const uint32_t bytesPerPixel = gpuResourceMgr.GetFormatProperties(dataToBeCopied.handle).bytesPerPixel;
177 const uint32_t byteSize = desc.width * desc.height * bytesPerPixel;
178
179 copyDataRef.bufferHandle = gpuResourceMgr.Create(GetStagingBufferDesc(byteSize, ebcf));
180 if (byteBufferCopy) {
181 copyDataRef.byteBuffer = make_unique<ByteArray>(byteSize);
182 }
183
184 const BufferImageCopy bic {
185 0, // bufferOffset
186 0, // bufferRowLength
187 0, // bufferImageHeight
188 ImageSubresourceLayers { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1u }, // imageSubresource
189 Size3D { 0, 0, 0 }, // imageOffset
190 Size3D { desc.width, desc.height, 1u }, // imageExtent
191 };
192 dsStaging_->CopyImageToBuffer(dataToBeCopied.handle, copyDataRef.bufferHandle, bic,
193 IRenderDataStoreDefaultStaging::ResourceCopyInfo::END_FRAME);
194 }
195
196 if (copyDataRef.byteBuffer && copyDataRef.bufferHandle) {
197 IRenderDataStoreDefaultGpuResourceDataCopy::GpuResourceDataCopy dataCopy;
198 if (copyDataRef.copyFlags & CopyFlagBits::WAIT_FOR_IDLE) {
199 dataCopy.copyType = IRenderDataStoreDefaultGpuResourceDataCopy::CopyType::WAIT_FOR_IDLE;
200 }
201 dataCopy.gpuHandle = copyDataRef.bufferHandle;
202 dataCopy.byteArray = copyDataRef.byteBuffer.get();
203 dsCpuToGpuCopy_->AddCopyOperation(dataCopy);
204 }
205 }
206 }
207
ProcessFrameSignalData()208 void RenderFrameUtil::ProcessFrameSignalData()
209 {
210 // try to reserve
211 thisFrameSignalData_.gpuSemaphores.reserve(postSignalData_.size());
212 thisFrameSignalData_.signalData.reserve(postSignalData_.size());
213
214 auto& device = (Device&)device_;
215 const DeviceBackendType backendType = device.GetBackendType();
216 // check the input data and create possible semaphores
217 for (const auto& ref : postSignalData_) {
218 SignalData sd = ref;
219 sd.signalResourceType = (backendType == DeviceBackendType::VULKAN) ? SignalResourceType::GPU_SEMAPHORE
220 : SignalResourceType::GPU_FENCE;
221 if (ref.gpuSignalResourceHandle) { // input signal handle given
222 // validity checked with input method
223 // create a view to external handle
224 thisFrameSignalData_.gpuSemaphores.push_back(device.CreateGpuSemaphoreView(ref.gpuSignalResourceHandle));
225 } else {
226 // create semaphore
227 thisFrameSignalData_.gpuSemaphores.push_back(device.CreateGpuSemaphore());
228 }
229 sd.gpuSignalResourceHandle = thisFrameSignalData_.gpuSemaphores.back()->GetHandle();
230 thisFrameSignalData_.signalData.push_back(sd);
231 }
232 }
233
ProcessFrameBackBufferConfiguration()234 void RenderFrameUtil::ProcessFrameBackBufferConfiguration()
235 {
236 if (postBackBufferConfig_.force) {
237 const auto& rdsMgr = renderContext_.GetRenderDataStoreManager();
238 if (refcnt_ptr<IRenderDataStorePod> dataStorePod = rdsMgr.GetRenderDataStore(RENDER_DATA_STORE_POD)) {
239 NodeGraphBackBufferConfiguration ngbbc;
240 ngbbc.backBufferName[postBackBufferConfig_.bbc.backBufferName.copy(
241 ngbbc.backBufferName, countof(ngbbc.backBufferName) - 1)] = '\0';
242 ngbbc.backBufferType =
243 static_cast<NodeGraphBackBufferConfiguration::BackBufferType>(postBackBufferConfig_.bbc.backBufferType);
244 ngbbc.backBufferHandle = postBackBufferConfig_.bbc.backBufferHandle.GetHandle();
245 ngbbc.gpuBufferHandle = postBackBufferConfig_.bbc.gpuBufferHandle.GetHandle();
246 ngbbc.present = postBackBufferConfig_.bbc.present;
247 ngbbc.gpuSemaphoreHandle = postBackBufferConfig_.bbc.gpuSemaphoreHandle;
248
249 dataStorePod->Set(POD_NAME, arrayviewU8(ngbbc));
250 }
251 }
252 }
253
ProcessFrameSignalDeferredDestroy()254 void RenderFrameUtil::ProcessFrameSignalDeferredDestroy()
255 {
256 // already used in previous frame
257 const auto& device = (const Device&)device_;
258 const uint64_t frameCount = device.GetFrameCount();
259 const auto minAge = device.GetCommandBufferingCount();
260 const auto ageLimit = (frameCount < minAge) ? 0 : (frameCount - minAge);
261
262 for (auto iter = gpuSignalDeferredDestroy_.begin(); iter != gpuSignalDeferredDestroy_.end();) {
263 if (iter->frameUseIndex < ageLimit) {
264 iter = gpuSignalDeferredDestroy_.erase(iter);
265 } else {
266 ++iter;
267 }
268 }
269 }
270
EndFrame()271 void RenderFrameUtil::EndFrame()
272 {
273 frameHasWaitForIdle_ = false;
274
275 postFrame_.copyData.clear();
276 if (frameHasWaitForIdle_) {
277 for (auto& ref : bufferedPostFrame_) {
278 ref.copyData.clear();
279 }
280 } else {
281 bufferedPostFrame_[bufferedIndex_].copyData.clear();
282 }
283 }
284
CopyToCpu(const RenderHandleReference & handle,const CopyFlags flags)285 void RenderFrameUtil::CopyToCpu(const RenderHandleReference& handle, const CopyFlags flags)
286 {
287 if (!ValidateInput(handle)) {
288 return;
289 }
290
291 const auto lock = std::lock_guard(mutex_);
292
293 const uint64_t frameIndex = device_.GetFrameCount();
294 preFrame_.copyData.push_back({ frameIndex, handle, flags });
295 }
296
ValidateInput(const RenderHandleReference & handle)297 bool RenderFrameUtil::ValidateInput(const RenderHandleReference& handle)
298 {
299 bool valid = true;
300 const RenderHandleType type = handle.GetHandleType();
301 IGpuResourceManager& gpuResourceMgr = device_.GetGpuResourceManager();
302 if (type == RenderHandleType::GPU_BUFFER) {
303 const GpuBufferDesc desc = gpuResourceMgr.GetBufferDescriptor(handle);
304 if ((desc.usageFlags & BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT) == 0) {
305 valid = false;
306 #if (RENDER_VALIDATION_ENABLED == 1)
307 const string strId = string("rfu_CopyToCpu_") + BASE_NS::to_string(handle.GetHandle().id);
308 PLUGIN_LOG_ONCE_W(strId.c_str(),
309 "Render frame util needs usage flag CORE_BUFFER_USAGE_TRANSFER_SRC_BIT to CPU copies. (name:%s)",
310 gpuResourceMgr.GetName(handle).c_str());
311 #endif
312 }
313 } else if (type == RenderHandleType::GPU_IMAGE) {
314 const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(handle);
315 if ((desc.usageFlags & BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT) == 0) {
316 valid = false;
317 #if (RENDER_VALIDATION_ENABLED == 1)
318 const string strId = string("rfu_CopyToCpu_") + BASE_NS::to_string(handle.GetHandle().id);
319 PLUGIN_LOG_ONCE_W(strId.c_str(),
320 "Render frame util needs usage flag CORE_BUFFER_USAGE_TRANSFER_SRC_BIT to CPU copies. (name:%s)",
321 gpuResourceMgr.GetName(handle).c_str());
322 #endif
323 }
324 } else {
325 valid = false;
326 #if (RENDER_VALIDATION_ENABLED == 1)
327 const string strId = string("rfu_CopyToCpu_") + BASE_NS::to_string(handle.GetHandle().id);
328 PLUGIN_LOG_ONCE_W(strId.c_str(), "Render frame util CopyToCpu works only on GPU buffers and images.");
329 #endif
330 }
331 return valid;
332 }
333
GetFrameCopyData()334 array_view<IRenderFrameUtil::FrameCopyData> RenderFrameUtil::GetFrameCopyData()
335 {
336 // NOTE: not thread safe (should not be called during rendering)
337 return thisFrameCopiedData_;
338 }
339
GetFrameCopyData(const RenderHandleReference & handle)340 const IRenderFrameUtil::FrameCopyData& RenderFrameUtil::GetFrameCopyData(const RenderHandleReference& handle)
341 {
342 // NOTE: not thread safe (should not be called during rendering)
343 if (handle) {
344 const RenderHandle rawHandle = handle.GetHandle();
345 for (const auto& ref : thisFrameCopiedData_) {
346 if (ref.handle.GetHandle() == rawHandle) {
347 return ref;
348 }
349 }
350 }
351 return defaultCopyData_;
352 }
353
SetBackBufferConfiguration(const BackBufferConfiguration & backBufferConfiguration)354 void RenderFrameUtil::SetBackBufferConfiguration(const BackBufferConfiguration& backBufferConfiguration)
355 {
356 const auto lock = std::lock_guard(mutex_);
357
358 preBackBufferConfig_.force = true;
359 preBackBufferConfig_.bbc = backBufferConfiguration;
360 }
361
AddGpuSignal(const SignalData & signalData)362 void RenderFrameUtil::AddGpuSignal(const SignalData& signalData)
363 {
364 bool valid = true;
365 if (signalData.signaled) {
366 valid = false;
367 PLUGIN_LOG_E("Already signalled GPU signal cannot be processed. (Not supported)");
368 }
369 if (signalData.gpuSignalResourceHandle) {
370 const DeviceBackendType backendType = device_.GetBackendType();
371 const SignalResourceType signalResourceType = signalData.signalResourceType;
372 if ((backendType == DeviceBackendType::VULKAN) && (signalResourceType != SignalResourceType::GPU_SEMAPHORE)) {
373 valid = false;
374 } else if ((backendType != DeviceBackendType::VULKAN) &&
375 (signalResourceType != SignalResourceType::GPU_FENCE)) {
376 valid = false;
377 }
378 if (!valid) {
379 PLUGIN_LOG_E("Invalid signal type (%u) for platform (%u)", static_cast<uint32_t>(signalResourceType),
380 static_cast<uint32_t>(backendType));
381 }
382 }
383
384 if (valid) {
385 const auto lock = std::lock_guard(mutex_);
386
387 preSignalData_.push_back(signalData);
388 }
389 }
390
GetFrameGpuSignalData()391 BASE_NS::array_view<IRenderFrameUtil::SignalData> RenderFrameUtil::GetFrameGpuSignalData()
392 {
393 // NOTE: not thread safe (should not be called during rendering)
394 return thisFrameSignalData_.signalData;
395 }
396
GetFrameGpuSignalData(const RenderHandleReference & handle)397 IRenderFrameUtil::SignalData RenderFrameUtil::GetFrameGpuSignalData(const RenderHandleReference& handle)
398 {
399 // NOTE: not thread safe (should not be called during rendering)
400 if (handle) {
401 const RenderHandle rawHandle = handle.GetHandle();
402 for (const auto& ref : thisFrameSignalData_.signalData) {
403 if (ref.handle.GetHandle() == rawHandle) {
404 return ref;
405 }
406 }
407 }
408 return {};
409 }
410
HasGpuSignals() const411 bool RenderFrameUtil::HasGpuSignals() const
412 {
413 return !thisFrameSignalData_.gpuSemaphores.empty();
414 }
415
GetGpuSemaphores()416 array_view<unique_ptr<GpuSemaphore>> RenderFrameUtil::GetGpuSemaphores()
417 {
418 return thisFrameSignalData_.gpuSemaphores;
419 }
420
421 RENDER_END_NAMESPACE()
422