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