• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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_default_environment_blender.h"
17 
18 #include <3d/render/intf_render_data_store_default_camera.h>
19 #include <3d/render/intf_render_data_store_default_light.h>
20 #include <3d/render/intf_render_data_store_default_scene.h>
21 #include <base/math/mathf.h>
22 #include <core/log.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/intf_render_data_store_post_process.h>
26 #include <render/datastore/render_data_store_render_pods.h>
27 #include <render/device/intf_gpu_resource_manager.h>
28 #include <render/device/intf_shader_manager.h>
29 #include <render/device/pipeline_layout_desc.h>
30 #include <render/device/pipeline_state_desc.h>
31 #include <render/namespace.h>
32 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
33 #include <render/nodecontext/intf_node_context_pso_manager.h>
34 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
35 #include <render/nodecontext/intf_render_command_list.h>
36 #include <render/nodecontext/intf_render_node_context_manager.h>
37 #include <render/nodecontext/intf_render_node_graph_share_manager.h>
38 #include <render/nodecontext/intf_render_node_parser_util.h>
39 #include <render/nodecontext/intf_render_node_util.h>
40 
41 #include "render/default_constants.h"
42 
43 // shaders
44 #include <render/shaders/common/render_post_process_structs_common.h>
45 
46 using namespace BASE_NS;
47 using namespace RENDER_NS;
48 
49 CORE3D_BEGIN_NAMESPACE()
50 namespace {
51 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
52 
53 constexpr uint32_t MAX_MIP_COUNT { 16U };
54 constexpr string_view CORE_DEFAULT_GPU_IMAGE_BLACK { "CORE_DEFAULT_GPU_IMAGE" };
55 constexpr string_view DEFAULT_CUBEMAP_BLENDER_SHADER { "3dshaders://shader/core3d_dm_camera_cubemap_blender.shader" };
56 
57 constexpr GpuImageDesc CUBEMAP_DEFAULT_DESC { CORE_IMAGE_TYPE_2D, CORE_IMAGE_VIEW_TYPE_CUBE,
58     BASE_FORMAT_B10G11R11_UFLOAT_PACK32, CORE_IMAGE_TILING_OPTIMAL,
59     CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | CORE_IMAGE_USAGE_SAMPLED_BIT, CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
60     CORE_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS, 256U, 256U, 1U, 9U, 6U,
61     CORE_SAMPLE_COUNT_1_BIT, ComponentMapping {} };
62 
GetDefaultImagesAndSamplers(const IRenderNodeGpuResourceManager & gpuResourceMgr)63 RenderNodeDefaultEnvironmentBlender::DefaultImagesAndSamplers GetDefaultImagesAndSamplers(
64     const IRenderNodeGpuResourceManager& gpuResourceMgr)
65 {
66     RenderNodeDefaultEnvironmentBlender::DefaultImagesAndSamplers dias;
67     dias.cubemapSamplerHandle =
68         gpuResourceMgr.GetSamplerHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_RADIANCE_CUBEMAP_SAMPLER);
69     dias.linearHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
70     dias.nearestHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_NEAREST_CLAMP");
71     dias.linearMipHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP");
72     dias.skyBoxRadianceCubemapHandle =
73         gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_RADIANCE_CUBEMAP);
74     return dias;
75 }
76 
CreateRadianceCubemap(IRenderNodeGpuResourceManager & gpuResourceMgr,const string_view name)77 RenderHandleReference CreateRadianceCubemap(IRenderNodeGpuResourceManager& gpuResourceMgr, const string_view name)
78 {
79     return gpuResourceMgr.Create(name, CUBEMAP_DEFAULT_DESC);
80 }
81 } // namespace
82 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)83 void RenderNodeDefaultEnvironmentBlender::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
84 {
85     renderNodeContextMgr_ = &renderNodeContextMgr;
86 
87     valid_ = true;
88 
89     ParseRenderNodeInputs();
90     const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
91     stores_ = RenderNodeSceneUtil::GetSceneRenderDataStores(
92         renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
93 
94     UpdateImageData();
95 }
96 
PreExecuteFrame()97 void RenderNodeDefaultEnvironmentBlender::PreExecuteFrame()
98 {
99     hasBlendEnvironments_ = false;
100 
101     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
102     const auto* dataStoreCamera =
103         static_cast<IRenderDataStoreDefaultCamera*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameCamera));
104     const auto* dataStoreScene =
105         static_cast<IRenderDataStoreDefaultScene*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameScene));
106     valid_ = (dataStoreScene && dataStoreCamera);
107     if (!valid_) {
108         return;
109     }
110     if (!dataStoreCamera->HasBlendEnvironments()) {
111         // need to clear targets
112         envTargetData_ = {};
113         return; // early out
114     }
115 
116     hasBlendEnvironments_ = true;
117 
118     // create possible targets
119     const auto& renderEnvironments = dataStoreCamera->GetEnvironments();
120     for (uint32_t idx = 0U; idx < static_cast<uint32_t>(renderEnvironments.size()); ++idx) {
121         const auto& currEnv = renderEnvironments[idx];
122         if (currEnv.multiEnvCount != 0U) {
123             if (!currEnv.radianceCubemap) {
124                 bool targetFound = false;
125                 // create target if not available and mark for frame usage
126                 for (auto& targetRef : envTargetData_) {
127                     if (targetRef.id == currEnv.id) {
128                         targetFound = true;
129                         break;
130                     }
131                 }
132                 if (!targetFound) {
133                     const string name = string(stores_.dataStoreNameScene) +
134                                         DefaultMaterialSceneConstants::ENVIRONMENT_RADIANCE_CUBEMAP_PREFIX_NAME +
135                                         to_hex(currEnv.id);
136                     envTargetData_.push_back({ currEnv.id,
137                         CreateRadianceCubemap(renderNodeContextMgr_->GetGpuResourceManager(), name.c_str()), true });
138                 }
139             }
140         }
141     }
142 }
143 
GetExecuteFlags() const144 IRenderNode::ExecuteFlags RenderNodeDefaultEnvironmentBlender::GetExecuteFlags() const
145 {
146     if (valid_ && hasBlendEnvironments_) {
147         return 0U;
148     } else {
149         return IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE;
150     }
151 }
152 
ExecuteFrame(IRenderCommandList & cmdList)153 void RenderNodeDefaultEnvironmentBlender::ExecuteFrame(IRenderCommandList& cmdList)
154 {
155     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
156     const auto* dataStoreCamera =
157         static_cast<IRenderDataStoreDefaultCamera*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameCamera));
158     const auto* dataStoreScene =
159         static_cast<IRenderDataStoreDefaultScene*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameScene));
160     if (valid_ && dataStoreCamera && dataStoreScene) {
161         CORE_ASSERT(dataStoreCamera->HasBlendEnvironments());
162         UpdateImageData();
163         InitializeShaderData();
164 
165         RENDER_DEBUG_MARKER_COL_SCOPE(cmdList, "3DEnvCubemapBlender", DefaultDebugConstants::DEFAULT_DEBUG_COLOR);
166         const auto renderEnvironments = dataStoreCamera->GetEnvironments();
167 
168         environmentUbo_ = renderNodeContextMgr_->GetGpuResourceManager().GetBufferHandle(
169             stores_.dataStoreNameScene.c_str() + DefaultMaterialSceneConstants::SCENE_ENVIRONMENT_DATA_BUFFER_NAME);
170         if (RenderHandleUtil::IsValid(environmentUbo_)) {
171             for (uint32_t idx = 0U; idx < static_cast<uint32_t>(renderEnvironments.size()); ++idx) {
172                 const auto& ref = renderEnvironments[idx];
173                 if (ref.multiEnvCount != 0U) {
174                     ExecuteSingleEnvironment(cmdList, renderEnvironments, idx);
175                 }
176             }
177         }
178     }
179 
180     // clear targets which are not used this frame
181     for (auto iter = envTargetData_.begin(); iter != envTargetData_.end();) {
182         if (iter->usedThisFrame) {
183             ++iter;
184         } else {
185             envTargetData_.erase(iter);
186         }
187     }
188 }
189 
190 namespace {
191 constexpr ImageResourceBarrier SRC_UNDEFINED { 0, CORE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, CORE_IMAGE_LAYOUT_UNDEFINED };
192 constexpr ImageResourceBarrier COL_ATTACHMENT { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
193     CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
194 constexpr ImageResourceBarrier SHDR_READ { CORE_ACCESS_SHADER_READ_BIT, CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
195     CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
196 } // namespace
197 
GetEnvironmentTargetHandle(const RenderCamera::Environment & environment)198 RenderHandle RenderNodeDefaultEnvironmentBlender::GetEnvironmentTargetHandle(
199     const RenderCamera::Environment& environment)
200 {
201     RenderHandle target;
202     if (environment.radianceCubemap) {
203         // there's a target available which we should use
204         target = environment.radianceCubemap.GetHandle();
205 #if (CORE3D_VALIDATION_ENABLED == 1)
206         const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
207         const GpuImageDesc& desc = gpuResourceMgr.GetImageDescriptor(target);
208         if ((desc.usageFlags & ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0U) {
209             CORE_LOG_ONCE_W("target_usage_cubemap_color_attachment_" + to_string(target.id),
210                 "CORE3D_VALIDATION: Environment blending radiance cubemap target has invalid flags");
211         }
212 #endif
213     } else {
214         // mark for frame usage
215         for (auto& targetRef : envTargetData_) {
216             if (targetRef.id == environment.id) {
217                 targetRef.usedThisFrame = true;
218                 target = targetRef.handle.GetHandle();
219                 break;
220             }
221         }
222         if (!RenderHandleUtil::IsValid(target)) {
223             CORE_LOG_W("Target handle issues with cubemap blender");
224         }
225     }
226     return target;
227 }
228 
FillBlendEnvironments(const array_view<const RenderCamera::Environment> environments,const uint32_t envIdx,array_view<RenderHandle> & blendEnvs) const229 void RenderNodeDefaultEnvironmentBlender::FillBlendEnvironments(
230     const array_view<const RenderCamera::Environment> environments, const uint32_t envIdx,
231     array_view<RenderHandle>& blendEnvs) const
232 {
233     const auto& env = environments[envIdx];
234     // fetch all the radiance cubemaps
235     uint32_t mvEnvIdx = 0U;
236     for (uint32_t idx = 0; idx < env.multiEnvCount; ++idx) {
237         if (mvEnvIdx >= blendEnvs.size()) {
238             break;
239         }
240         if (idx < env.multiEnvCount) {
241             for (const auto& mvEnvRef : environments) {
242                 if (mvEnvRef.id == env.multiEnvIds[idx]) {
243                     blendEnvs[mvEnvIdx++] = (mvEnvRef.radianceCubemap)
244                                                 ? mvEnvRef.radianceCubemap.GetHandle()
245                                                 : defaultImagesAndSamplers_.skyBoxRadianceCubemapHandle;
246                     break;
247                 }
248             }
249         }
250     }
251 }
252 
ExecuteSingleEnvironment(IRenderCommandList & cmdList,const array_view<const RenderCamera::Environment> environments,const uint32_t envIdx)253 void RenderNodeDefaultEnvironmentBlender::ExecuteSingleEnvironment(
254     IRenderCommandList& cmdList, const array_view<const RenderCamera::Environment> environments, const uint32_t envIdx)
255 {
256     const auto& envRef = environments[envIdx];
257     CORE_ASSERT(envRef.multiEnvCount > 0U);
258 
259     const RenderHandle target = GetEnvironmentTargetHandle(envRef);
260     if (!RenderHandleUtil::IsValid(target)) {
261         return;
262     }
263 
264     RenderHandle blendEnvironments[2U] { defaultImagesAndSamplers_.skyBoxRadianceCubemapHandle,
265         defaultImagesAndSamplers_.skyBoxRadianceCubemapHandle };
266     array_view<RenderHandle> beView { blendEnvironments, countof(blendEnvironments) };
267     FillBlendEnvironments(environments, envIdx, beView);
268 
269     const GpuImageDesc desc = renderNodeContextMgr_->GetGpuResourceManager().GetImageDescriptor(target);
270     Math::UVec2 currSize = { desc.width, desc.height };
271 
272     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
273     RenderPass renderPass;
274     renderPass.renderPassDesc.attachmentCount = 1U;
275     renderPass.renderPassDesc.attachmentHandles[0U] = target;
276     renderPass.renderPassDesc.attachments[0U].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
277     renderPass.renderPassDesc.attachments[0U].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
278     renderPass.renderPassDesc.attachments[0U].layer = 0U;
279     renderPass.renderPassDesc.renderArea = { 0U, 0U, currSize.x, currSize.y };
280     renderPass.renderPassDesc.subpassCount = 1U;
281     renderPass.subpassDesc.viewMask = 0x3f;
282     renderPass.subpassDesc.colorAttachmentCount = 1U;
283     renderPass.subpassDesc.colorAttachmentIndices[0U] = 0U;
284 
285     auto& sets = allEnvSets_[envIdx];
286     for (uint32_t mipIdx = 0; mipIdx < desc.mipCount; ++mipIdx) {
287         // handle all descriptor set updates
288         UpdateSet0(cmdList, beView, envIdx, mipIdx);
289         const auto& bindings = sets.localSets[mipIdx]->GetDescriptorSetLayoutBindingResources();
290         cmdList.UpdateDescriptorSet(sets.localSets[mipIdx]->GetDescriptorSetHandle(), bindings);
291     }
292 
293     cmdList.BeginDisableAutomaticBarrierPoints();
294 
295     // change all the layouts accordingly
296     {
297         ImageSubresourceRange imageSubresourceRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0,
298             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
299         cmdList.CustomImageBarrier(target, SRC_UNDEFINED, COL_ATTACHMENT, imageSubresourceRange);
300         cmdList.AddCustomBarrierPoint();
301     }
302 
303     for (uint32_t mipIdx = 0; mipIdx < desc.mipCount; ++mipIdx) {
304         renderPass.renderPassDesc.attachments[0U].mipLevel = mipIdx;
305         if (mipIdx != 0U) {
306             currSize.x = Math::max(1U, currSize.x / 2U);
307             currSize.y = Math::max(1U, currSize.y / 2U);
308         }
309         renderPass.renderPassDesc.renderArea = { 0U, 0U, currSize.x, currSize.y };
310 
311         cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
312 
313         cmdList.BindPipeline(psoHandle_);
314         // bind all sets
315         cmdList.BindDescriptorSet(0U, sets.localSets[mipIdx]->GetDescriptorSetHandle());
316 
317         // dynamic state
318         const ViewportDesc viewportDesc = renderNodeUtil.CreateDefaultViewport(renderPass);
319         const ScissorDesc scissorDesc = renderNodeUtil.CreateDefaultScissor(renderPass);
320         cmdList.SetDynamicStateViewport(viewportDesc);
321         cmdList.SetDynamicStateScissor(scissorDesc);
322 
323         if (pipelineLayout_.pushConstant.byteSize > 0U) {
324             // mipIdx as lodlevel
325             Math::UVec4 indices { envIdx, mipIdx, 0U, 0U };
326             cmdList.PushConstantData(pipelineLayout_.pushConstant, arrayviewU8(indices));
327         }
328 
329         cmdList.Draw(3u, 1u, 0u, 0u);
330         cmdList.EndRenderPass();
331     }
332 
333     // change all the layouts accordingly
334     {
335         ImageSubresourceRange imageSubresourceRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0,
336             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
337         cmdList.CustomImageBarrier(target, COL_ATTACHMENT, SHDR_READ, imageSubresourceRange);
338         cmdList.AddCustomBarrierPoint();
339     }
340 
341     cmdList.EndDisableAutomaticBarrierPoints();
342 }
343 
UpdateSet0(IRenderCommandList & cmdList,const array_view<const RenderHandle> blendImages,const uint32_t envIdx,const uint32_t mipIdx)344 void RenderNodeDefaultEnvironmentBlender::UpdateSet0(IRenderCommandList& cmdList,
345     const array_view<const RenderHandle> blendImages, const uint32_t envIdx, const uint32_t mipIdx)
346 {
347     // bind all radiance cubemaps
348     const auto& sets = allEnvSets_[envIdx];
349     auto& binder = *sets.localSets[mipIdx];
350     CORE_ASSERT(sets.localSets[mipIdx]);
351     CORE_ASSERT(blendImages.size() == 2U);
352 
353     const uint32_t maxCount = Math::min(DefaultMaterialCameraConstants::MAX_CAMERA_MULTI_ENVIRONMENT_COUNT, 2U);
354     uint32_t binding = 0U;
355     binder.BindBuffer(binding++, { environmentUbo_ });
356     BindableImage bi;
357     // additional cubemaps from first index
358     for (uint32_t resIdx = 0U; resIdx < maxCount; ++resIdx) {
359         // filled with valid handles
360         bi.handle = blendImages[resIdx];
361         bi.samplerHandle = defaultImagesAndSamplers_.cubemapSamplerHandle;
362         binder.BindImage(binding++, bi, {});
363     }
364 }
365 
InitializeShaderData()366 void RenderNodeDefaultEnvironmentBlender::InitializeShaderData()
367 {
368     if (!hasInitializedShaderData_) {
369         hasInitializedShaderData_ = true;
370 
371         auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
372         defaultImagesAndSamplers_ = GetDefaultImagesAndSamplers(gpuResourceMgr);
373         const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
374         const RenderHandleType handleType = RenderHandleUtil::GetHandleType(shader_);
375         const RenderHandle plHandle = shaderMgr.GetReflectionPipelineLayoutHandle(shader_);
376         pipelineLayout_ = shaderMgr.GetPipelineLayout(plHandle);
377         if (handleType == RenderHandleType::SHADER_STATE_OBJECT) {
378             const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(shader_);
379             psoHandle_ = renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(
380                 shader_, graphicsState, pipelineLayout_, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
381         } else {
382             CORE_LOG_E("RN:%s needs a valid shader handle", renderNodeContextMgr_->GetName().data());
383         }
384         InitCreateBinders();
385     }
386 }
387 
InitCreateBinders()388 void RenderNodeDefaultEnvironmentBlender::InitCreateBinders()
389 {
390     const IRenderNodeUtil& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
391     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
392     {
393         DescriptorCounts dc = renderNodeUtil.GetDescriptorCounts(pipelineLayout_);
394         for (uint32_t idx = 0; idx < dc.counts.size(); ++idx) {
395             dc.counts[idx].count *= MAX_MIP_COUNT * CORE_DEFAULT_MATERIAL_MAX_ENVIRONMENT_COUNT;
396         }
397         descriptorSetMgr.ResetAndReserve(dc);
398     }
399 
400     allEnvSets_.clear();
401     allEnvSets_.resize(CORE_DEFAULT_MATERIAL_MAX_ENVIRONMENT_COUNT);
402 
403     for (auto& setsRef : allEnvSets_) {
404         setsRef.localSets.resize(MAX_MIP_COUNT);
405         const auto& bindings = pipelineLayout_.descriptorSetLayouts[0U].bindings;
406         for (uint32_t idx = 0; idx < MAX_MIP_COUNT; ++idx) {
407             const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
408             setsRef.localSets[idx] = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
409         }
410     }
411 
412     if ((!RenderHandleUtil::IsValid(shader_)) || (!RenderHandleUtil::IsValid(psoHandle_))) {
413         valid_ = false;
414     }
415 }
416 
ParseRenderNodeInputs()417 void RenderNodeDefaultEnvironmentBlender::ParseRenderNodeInputs()
418 {
419     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
420     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
421     const auto shaderName = parserUtil.GetStringValue(jsonVal, "shader");
422     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
423     if (!shaderName.empty()) {
424         shader_ = shaderMgr.GetShaderHandle(shaderName);
425     } else {
426         shader_ = shaderMgr.GetShaderHandle(DEFAULT_CUBEMAP_BLENDER_SHADER);
427     }
428 }
429 
UpdateImageData()430 void RenderNodeDefaultEnvironmentBlender::UpdateImageData()
431 {
432     const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
433     if (!RenderHandleUtil::IsValid(builtInVariables_.defBlackImage)) {
434         builtInVariables_.defBlackImage = gpuResourceMgr.GetImageHandle(CORE_DEFAULT_GPU_IMAGE_BLACK);
435     }
436     if (!RenderHandleUtil::IsValid(builtInVariables_.defSampler)) {
437         builtInVariables_.defSampler = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
438     }
439 }
440 
441 // for plugin / factory interface
Create()442 IRenderNode* RenderNodeDefaultEnvironmentBlender::Create()
443 {
444     return new RenderNodeDefaultEnvironmentBlender();
445 }
446 
Destroy(IRenderNode * instance)447 void RenderNodeDefaultEnvironmentBlender::Destroy(IRenderNode* instance)
448 {
449     delete static_cast<RenderNodeDefaultEnvironmentBlender*>(instance);
450 }
451 CORE3D_END_NAMESPACE()
452