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 "render_node_create_gpu_images.h"
17
18 #include <render/device/intf_device.h>
19 #include <render/device/intf_gpu_resource_manager.h>
20 #include <render/intf_render_context.h>
21 #include <render/namespace.h>
22 #include <render/nodecontext/intf_node_context_pso_manager.h>
23 #include <render/nodecontext/intf_render_command_list.h>
24 #include <render/nodecontext/intf_render_node_context_manager.h>
25 #include <render/nodecontext/intf_render_node_graph_share_manager.h>
26 #include <render/nodecontext/intf_render_node_parser_util.h>
27 #include <render/render_data_structures.h>
28
29 #include "util/log.h"
30
31 using namespace BASE_NS;
32
33 RENDER_BEGIN_NAMESPACE()
34 namespace {
GetDependencyList(uint32_t dependencyFlags,const float dependencySizeScale,const GpuImageDesc & desc)35 RenderNodeCreateGpuImages::DependencyList GetDependencyList(
36 uint32_t dependencyFlags, const float dependencySizeScale, const GpuImageDesc& desc)
37 {
38 using DependencyFlagBits = RenderNodeGraphInputs::RenderNodeGraphGpuImageDesc::DependencyFlagBits;
39 RenderNodeCreateGpuImages::DependencyList depList;
40 if (dependencyFlags == 0) {
41 constexpr GpuImageDesc defDesc {};
42 if (desc.format == defDesc.format) {
43 depList.format = true;
44 }
45 if ((desc.width == defDesc.width) && (desc.height == defDesc.height) && (desc.depth == defDesc.depth)) {
46 depList.size = true;
47 }
48 if (desc.mipCount == defDesc.mipCount) {
49 depList.mipCount = true;
50 }
51 if (desc.layerCount == defDesc.layerCount) {
52 depList.layerCount = true;
53 }
54 if (desc.sampleCountFlags == defDesc.sampleCountFlags) {
55 depList.sampleCount = true;
56 }
57 } else {
58 if (dependencyFlags & DependencyFlagBits::FORMAT) {
59 depList.format = true;
60 }
61 if (dependencyFlags & DependencyFlagBits::SIZE) {
62 depList.size = true;
63 depList.sizeScale = dependencySizeScale;
64 }
65 if (dependencyFlags & DependencyFlagBits::MIP_COUNT) {
66 depList.mipCount = true;
67 }
68 if (dependencyFlags & DependencyFlagBits::LAYER_COUNT) {
69 depList.layerCount = true;
70 }
71 if (dependencyFlags & DependencyFlagBits::SAMPLES) {
72 depList.sampleCount = true;
73 }
74 }
75 return depList;
76 }
77
CheckForDescUpdates(const GpuImageDesc & dependencyDesc,const RenderNodeCreateGpuImages::DependencyList & dependencyList,GpuImageDesc & desc)78 bool CheckForDescUpdates(const GpuImageDesc& dependencyDesc,
79 const RenderNodeCreateGpuImages::DependencyList& dependencyList, GpuImageDesc& desc)
80 {
81 bool needsUpdate = false;
82 if (dependencyList.format && (desc.format != dependencyDesc.format)) {
83 needsUpdate = true;
84 desc.format = dependencyDesc.format;
85 }
86 if (dependencyList.size) {
87 // compare with dependency size scale
88 const uint32_t sWidth =
89 Math::max(1u, static_cast<uint32_t>(static_cast<float>(dependencyDesc.width) * dependencyList.sizeScale));
90 const uint32_t sHeight =
91 Math::max(1u, static_cast<uint32_t>(static_cast<float>(dependencyDesc.height) * dependencyList.sizeScale));
92 const uint32_t sDepth =
93 Math::max(1u, static_cast<uint32_t>(static_cast<float>(dependencyDesc.depth) * dependencyList.sizeScale));
94 if ((desc.width != sWidth) || (desc.height != sHeight) || (desc.depth != sDepth)) {
95 needsUpdate = true;
96 desc.width = sWidth;
97 desc.height = sHeight;
98 desc.depth = sDepth;
99 }
100 }
101 if (dependencyList.mipCount && (desc.mipCount != dependencyDesc.mipCount)) {
102 needsUpdate = true;
103 desc.mipCount = dependencyDesc.mipCount;
104 }
105 if (dependencyList.layerCount && (desc.layerCount != dependencyDesc.layerCount)) {
106 needsUpdate = true;
107 desc.layerCount = dependencyDesc.layerCount;
108 }
109 if (dependencyList.sampleCount && (desc.sampleCountFlags != dependencyDesc.sampleCountFlags)) {
110 needsUpdate = true;
111 desc.sampleCountFlags = dependencyDesc.sampleCountFlags;
112 }
113 return needsUpdate;
114 }
115
CheckFormat(const IRenderNodeGpuResourceManager & gpuResourceMgr,const string_view nodeName,GpuImageDesc & desc)116 void CheckFormat(const IRenderNodeGpuResourceManager& gpuResourceMgr, const string_view nodeName, GpuImageDesc& desc)
117 {
118 // minimal check with just 2 back-up formats (one for color and one for depth)
119 FormatFeatureFlags neededFormatFeatureFlags = 0;
120 if (desc.usageFlags & CORE_IMAGE_USAGE_TRANSFER_SRC_BIT) {
121 neededFormatFeatureFlags |= CORE_FORMAT_FEATURE_TRANSFER_SRC_BIT;
122 } else if (desc.usageFlags & CORE_IMAGE_USAGE_TRANSFER_DST_BIT) {
123 neededFormatFeatureFlags |= CORE_FORMAT_FEATURE_TRANSFER_DST_BIT;
124 } else if (desc.usageFlags & CORE_IMAGE_USAGE_SAMPLED_BIT) {
125 neededFormatFeatureFlags |= CORE_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
126 } else if (desc.usageFlags & CORE_IMAGE_USAGE_STORAGE_BIT) {
127 neededFormatFeatureFlags |= CORE_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
128 } else if (desc.usageFlags & CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
129 neededFormatFeatureFlags |= CORE_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
130 } else if (desc.usageFlags & CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
131 neededFormatFeatureFlags |= CORE_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
132 }
133 const FormatProperties formatProperties = gpuResourceMgr.GetFormatProperties(desc.format);
134 const FormatFeatureFlags formatFeatureFlags = (desc.imageTiling == CORE_IMAGE_TILING_LINEAR)
135 ? formatProperties.linearTilingFeatures
136 : formatProperties.optimalTilingFeatures;
137 if ((neededFormatFeatureFlags & formatFeatureFlags) != neededFormatFeatureFlags) {
138 const Format backupFormat = (neededFormatFeatureFlags & CORE_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
139 ? Format::BASE_FORMAT_D32_SFLOAT
140 : Format::BASE_FORMAT_R8G8B8A8_UNORM;
141 PLUGIN_LOG_W("Format flags not supported for format: %u, in render node %s, backup format: %u",
142 static_cast<uint32_t>(desc.format), nodeName.data(), static_cast<uint32_t>(backupFormat));
143 desc.format = backupFormat;
144 }
145 }
146
LocalClamp(const Size2D val,const Size2D minVal,const Size2D maxVal)147 inline constexpr Size2D LocalClamp(const Size2D val, const Size2D minVal, const Size2D maxVal)
148 {
149 return Size2D { Math::max(minVal.width, Math::min(val.width, maxVal.width)),
150 Math::max(minVal.height, Math::min(val.height, maxVal.height)) };
151 }
152 } // namespace
153
InitNode(IRenderNodeContextManager & renderNodeContextMgr)154 void RenderNodeCreateGpuImages::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
155 {
156 renderNodeContextMgr_ = &renderNodeContextMgr;
157 ParseRenderNodeInputs();
158
159 if (jsonInputs_.gpuImageDescs.empty()) {
160 PLUGIN_LOG_W("RenderNodeCreateGpuImages: No gpu image descs given");
161 }
162
163 auto& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
164 descs_.reserve(jsonInputs_.gpuImageDescs.size());
165 dependencyHandles_.reserve(jsonInputs_.gpuImageDescs.size());
166 dependencyList_.reserve(jsonInputs_.gpuImageDescs.size());
167 shadingRateTexelSizes_.reserve(jsonInputs_.gpuImageDescs.size());
168 for (const auto& ref : jsonInputs_.gpuImageDescs) {
169 GpuImageDesc desc = ref.desc;
170 if (desc.format != Format::BASE_FORMAT_UNDEFINED) {
171 CheckFormat(gpuResourceMgr, renderNodeContextMgr_->GetName(), desc);
172 }
173
174 RenderHandle dependencyHandle;
175 DependencyList dependencyList;
176 if (!ref.dependencyImageName.empty()) {
177 dependencyHandle = gpuResourceMgr.GetImageHandle(ref.dependencyImageName);
178 if (RenderHandleUtil::IsValid(dependencyHandle)) {
179 const GpuImageDesc dependencyDesc = gpuResourceMgr.GetImageDescriptor(dependencyHandle);
180 dependencyList = GetDependencyList(ref.dependencyFlags, ref.dependencySizeScale, desc);
181
182 // update desc
183 CheckForDescUpdates(dependencyDesc, dependencyList, desc);
184 } else {
185 PLUGIN_LOG_E("GpuImage dependency name not found: %s", ref.dependencyImageName.c_str());
186 }
187 }
188 dependencyHandles_.push_back(dependencyHandle);
189 dependencyList_.push_back(dependencyList);
190 shadingRateTexelSizes_.push_back(GetClampedShadingRateTexelSize(ref.shadingRateTexelSize));
191
192 names_.push_back({ string(ref.name), string(ref.shareName) });
193 descs_.push_back(desc);
194
195 // NOTE: shading rate is not in the desc
196 desc.width = static_cast<uint32_t>(Math::ceil(float(desc.width) / float(shadingRateTexelSizes_.back().width)));
197 desc.height =
198 static_cast<uint32_t>(Math::ceil(float(desc.height) / float(shadingRateTexelSizes_.back().height)));
199 resourceHandles_.push_back(gpuResourceMgr.Create(ref.name, desc));
200 }
201
202 // broadcast the resources
203 for (size_t idx = 0; idx < resourceHandles_.size(); ++idx) {
204 IRenderNodeGraphShareManager& rngShareMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
205 rngShareMgr.RegisterRenderNodeOutput(names_[idx].shareName, resourceHandles_[idx].GetHandle());
206 }
207 }
208
PreExecuteFrame()209 void RenderNodeCreateGpuImages::PreExecuteFrame()
210 {
211 auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
212 for (size_t idx = 0; idx < resourceHandles_.size(); ++idx) {
213 const RenderHandle dependencyHandle = dependencyHandles_[idx];
214 if (gpuResourceMgr.IsValid(dependencyHandle)) {
215 const GpuImageDesc& dependencyDesc = gpuResourceMgr.GetImageDescriptor(dependencyHandle);
216 const DependencyList& dependencyList = dependencyList_[idx];
217 GpuImageDesc& descRef = descs_[idx];
218
219 const bool recreateImage = CheckForDescUpdates(dependencyDesc, dependencyList, descRef);
220 if (recreateImage) {
221 descs_[idx] = descRef;
222 // NOTE: shading rate is not in the desc
223 const Size2D shadingRateTexelSize = shadingRateTexelSizes_[idx];
224 descRef.width =
225 static_cast<uint32_t>(Math::ceil(float(descRef.width) / float(shadingRateTexelSize.width)));
226 descRef.height =
227 static_cast<uint32_t>(Math::ceil(float(descRef.height) / float(shadingRateTexelSize.height)));
228 // replace the handle
229 resourceHandles_[idx] = gpuResourceMgr.Create(resourceHandles_[idx], descRef);
230 }
231 }
232 }
233
234 // broadcast the resources
235 for (size_t idx = 0; idx < resourceHandles_.size(); ++idx) {
236 IRenderNodeGraphShareManager& rngShareMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
237 rngShareMgr.RegisterRenderNodeOutput(names_[idx].shareName, resourceHandles_[idx].GetHandle());
238 }
239 }
240
GetClampedShadingRateTexelSize(const Size2D & shadingRateTexelSize)241 Size2D RenderNodeCreateGpuImages::GetClampedShadingRateTexelSize(const Size2D& shadingRateTexelSize)
242 {
243 Size2D srts = { 1u, 1u };
244 if ((shadingRateTexelSize.width > 1u) || (shadingRateTexelSize.height > 1u)) {
245 const IDevice& device = renderNodeContextMgr_->GetRenderContext().GetDevice();
246 auto fsrProps = device.GetCommonDeviceProperties().fragmentShadingRateProperties;
247 fsrProps.minFragmentShadingRateAttachmentTexelSize.width =
248 Math::max(1U, fsrProps.minFragmentShadingRateAttachmentTexelSize.width);
249 fsrProps.minFragmentShadingRateAttachmentTexelSize.height =
250 Math::max(1U, fsrProps.minFragmentShadingRateAttachmentTexelSize.height);
251 fsrProps.maxFragmentShadingRateAttachmentTexelSize.width =
252 Math::max(1U, fsrProps.maxFragmentShadingRateAttachmentTexelSize.width);
253 fsrProps.maxFragmentShadingRateAttachmentTexelSize.height =
254 Math::max(1U, fsrProps.maxFragmentShadingRateAttachmentTexelSize.height);
255 srts = LocalClamp(shadingRateTexelSize, fsrProps.minFragmentShadingRateAttachmentTexelSize,
256 fsrProps.maxFragmentShadingRateAttachmentTexelSize);
257 }
258 return srts;
259 }
260
ParseRenderNodeInputs()261 void RenderNodeCreateGpuImages::ParseRenderNodeInputs()
262 {
263 const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
264 const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
265 jsonInputs_.gpuImageDescs = parserUtil.GetGpuImageDescs(jsonVal, "gpuImageDescs");
266 }
267
268 // for plugin / factory interface
Create()269 IRenderNode* RenderNodeCreateGpuImages::Create()
270 {
271 return new RenderNodeCreateGpuImages();
272 }
273
Destroy(IRenderNode * instance)274 void RenderNodeCreateGpuImages::Destroy(IRenderNode* instance)
275 {
276 delete static_cast<RenderNodeCreateGpuImages*>(instance);
277 }
278 RENDER_END_NAMESPACE()
279