• 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 "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     if (valid_ && dataStoreCamera) {
159         CORE_ASSERT(dataStoreCamera->HasBlendEnvironments());
160         UpdateImageData();
161         InitializeShaderData();
162 
163         RENDER_DEBUG_MARKER_COL_SCOPE(cmdList, "3DEnvCubemapBlender", DefaultDebugConstants::DEFAULT_DEBUG_COLOR);
164         const auto renderEnvironments = dataStoreCamera->GetEnvironments();
165 
166         environmentUbo_ = renderNodeContextMgr_->GetGpuResourceManager().GetBufferHandle(
167             stores_.dataStoreNameScene.c_str() + DefaultMaterialSceneConstants::SCENE_ENVIRONMENT_DATA_BUFFER_NAME);
168         if (RenderHandleUtil::IsValid(environmentUbo_)) {
169             for (uint32_t idx = 0U; idx < static_cast<uint32_t>(renderEnvironments.size()); ++idx) {
170                 const auto& ref = renderEnvironments[idx];
171                 if (ref.multiEnvCount != 0U) {
172                     ExecuteSingleEnvironment(cmdList, renderEnvironments, idx);
173                 }
174             }
175         }
176     }
177 
178     // clear targets which are not used this frame
179     for (auto iter = envTargetData_.begin(); iter != envTargetData_.end();) {
180         if (iter->usedThisFrame) {
181             ++iter;
182         } else {
183             envTargetData_.erase(iter);
184         }
185     }
186 }
187 
188 namespace {
189 constexpr ImageResourceBarrier SRC_UNDEFINED { 0, CORE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, CORE_IMAGE_LAYOUT_UNDEFINED };
190 constexpr ImageResourceBarrier COL_ATTACHMENT { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
191     CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
192 constexpr ImageResourceBarrier SHDR_READ { CORE_ACCESS_SHADER_READ_BIT, CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
193     CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
194 } // namespace
195 
GetEnvironmentTargetHandle(const RenderCamera::Environment & environment)196 RenderHandle RenderNodeDefaultEnvironmentBlender::GetEnvironmentTargetHandle(
197     const RenderCamera::Environment& environment)
198 {
199     RenderHandle target;
200     if (environment.radianceCubemap) {
201         // there's a target available which we should use
202         target = environment.radianceCubemap.GetHandle();
203 #if (CORE3D_VALIDATION_ENABLED == 1)
204         const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
205         const GpuImageDesc& desc = gpuResourceMgr.GetImageDescriptor(target);
206         if ((desc.usageFlags & ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0U) {
207             CORE_LOG_ONCE_W("target_usage_cubemap_color_attachment_" + to_string(target.id),
208                 "CORE3D_VALIDATION: Environment blending radiance cubemap target has invalid flags");
209         }
210 #endif
211     } else {
212         // mark for frame usage
213         for (auto& targetRef : envTargetData_) {
214             if (targetRef.id == environment.id) {
215                 targetRef.usedThisFrame = true;
216                 target = targetRef.handle.GetHandle();
217                 break;
218             }
219         }
220         if (!RenderHandleUtil::IsValid(target)) {
221             CORE_LOG_W("Target handle issues with cubemap blender");
222         }
223     }
224     return target;
225 }
226 
FillBlendEnvironments(const array_view<const RenderCamera::Environment> environments,const uint32_t envIdx,array_view<RenderHandle> & blendEnvs) const227 void RenderNodeDefaultEnvironmentBlender::FillBlendEnvironments(
228     const array_view<const RenderCamera::Environment> environments, const uint32_t envIdx,
229     array_view<RenderHandle>& blendEnvs) const
230 {
231     const auto& env = environments[envIdx];
232     // fetch all the radiance cubemaps
233     uint32_t mvEnvIdx = 0U;
234     for (uint32_t idx = 0; idx < env.multiEnvCount; ++idx) {
235         if (mvEnvIdx >= blendEnvs.size()) {
236             break;
237         }
238         if (idx < env.multiEnvCount) {
239             for (const auto& mvEnvRef : environments) {
240                 if (mvEnvRef.id == env.multiEnvIds[idx]) {
241                     blendEnvs[mvEnvIdx++] = (mvEnvRef.radianceCubemap)
242                                                 ? mvEnvRef.radianceCubemap.GetHandle()
243                                                 : defaultImagesAndSamplers_.skyBoxRadianceCubemapHandle;
244                     break;
245                 }
246             }
247         }
248     }
249 }
250 
ExecuteSingleEnvironment(IRenderCommandList & cmdList,const array_view<const RenderCamera::Environment> environments,const uint32_t envIdx)251 void RenderNodeDefaultEnvironmentBlender::ExecuteSingleEnvironment(
252     IRenderCommandList& cmdList, const array_view<const RenderCamera::Environment> environments, const uint32_t envIdx)
253 {
254     const auto& envRef = environments[envIdx];
255     CORE_ASSERT(envRef.multiEnvCount > 0U);
256 
257     const RenderHandle target = GetEnvironmentTargetHandle(envRef);
258     if (!RenderHandleUtil::IsValid(target)) {
259         return;
260     }
261 
262     RenderHandle blendEnvironments[2U] { defaultImagesAndSamplers_.skyBoxRadianceCubemapHandle,
263         defaultImagesAndSamplers_.skyBoxRadianceCubemapHandle };
264     array_view<RenderHandle> beView { blendEnvironments, countof(blendEnvironments) };
265     FillBlendEnvironments(environments, envIdx, beView);
266 
267     const GpuImageDesc desc = renderNodeContextMgr_->GetGpuResourceManager().GetImageDescriptor(target);
268     Math::UVec2 currSize = { desc.width, desc.height };
269 
270     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
271     RenderPass renderPass;
272     renderPass.renderPassDesc.attachmentCount = 1U;
273     renderPass.renderPassDesc.attachmentHandles[0U] = target;
274     renderPass.renderPassDesc.attachments[0U].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
275     renderPass.renderPassDesc.attachments[0U].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
276     renderPass.renderPassDesc.attachments[0U].layer = 0U;
277     renderPass.renderPassDesc.renderArea = { 0U, 0U, currSize.x, currSize.y };
278     renderPass.renderPassDesc.subpassCount = 1U;
279     renderPass.subpassDesc.viewMask = 0x3f;
280     renderPass.subpassDesc.colorAttachmentCount = 1U;
281     renderPass.subpassDesc.colorAttachmentIndices[0U] = 0U;
282 
283     auto& sets = allEnvSets_[envIdx];
284     for (uint32_t mipIdx = 0; mipIdx < desc.mipCount; ++mipIdx) {
285         // handle all descriptor set updates
286         UpdateSet0(cmdList, beView, envIdx, mipIdx);
287         const auto& bindings = sets.localSets[mipIdx]->GetDescriptorSetLayoutBindingResources();
288         cmdList.UpdateDescriptorSet(sets.localSets[mipIdx]->GetDescriptorSetHandle(), bindings);
289     }
290 
291     cmdList.BeginDisableAutomaticBarrierPoints();
292 
293     // change all the layouts accordingly
294     {
295         ImageSubresourceRange imageSubresourceRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0,
296             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
297         cmdList.CustomImageBarrier(target, SRC_UNDEFINED, COL_ATTACHMENT, imageSubresourceRange);
298         cmdList.AddCustomBarrierPoint();
299     }
300 
301     for (uint32_t mipIdx = 0; mipIdx < desc.mipCount; ++mipIdx) {
302         renderPass.renderPassDesc.attachments[0U].mipLevel = mipIdx;
303         if (mipIdx != 0U) {
304             currSize.x = Math::max(1U, currSize.x / 2U);
305             currSize.y = Math::max(1U, currSize.y / 2U);
306         }
307         renderPass.renderPassDesc.renderArea = { 0U, 0U, currSize.x, currSize.y };
308 
309         cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
310 
311         cmdList.BindPipeline(psoHandle_);
312         // bind all sets
313         cmdList.BindDescriptorSet(0U, sets.localSets[mipIdx]->GetDescriptorSetHandle());
314 
315         // dynamic state
316         const ViewportDesc viewportDesc = renderNodeUtil.CreateDefaultViewport(renderPass);
317         const ScissorDesc scissorDesc = renderNodeUtil.CreateDefaultScissor(renderPass);
318         cmdList.SetDynamicStateViewport(viewportDesc);
319         cmdList.SetDynamicStateScissor(scissorDesc);
320 
321         if (pipelineLayout_.pushConstant.byteSize > 0U) {
322             // mipIdx as lodlevel
323             Math::UVec4 indices { envIdx, mipIdx, 0U, 0U };
324             cmdList.PushConstantData(pipelineLayout_.pushConstant, arrayviewU8(indices));
325         }
326 
327         cmdList.Draw(3u, 1u, 0u, 0u);
328         cmdList.EndRenderPass();
329     }
330 
331     // change all the layouts accordingly
332     {
333         ImageSubresourceRange imageSubresourceRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0,
334             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
335         cmdList.CustomImageBarrier(target, COL_ATTACHMENT, SHDR_READ, imageSubresourceRange);
336         cmdList.AddCustomBarrierPoint();
337     }
338 
339     cmdList.EndDisableAutomaticBarrierPoints();
340 }
341 
UpdateSet0(IRenderCommandList & cmdList,const array_view<const RenderHandle> blendImages,const uint32_t envIdx,const uint32_t mipIdx)342 void RenderNodeDefaultEnvironmentBlender::UpdateSet0(IRenderCommandList& cmdList,
343     const array_view<const RenderHandle> blendImages, const uint32_t envIdx, const uint32_t mipIdx)
344 {
345     // bind all radiance cubemaps
346     const auto& sets = allEnvSets_[envIdx];
347     auto& binder = *sets.localSets[mipIdx];
348     CORE_ASSERT(sets.localSets[mipIdx]);
349     CORE_ASSERT(blendImages.size() == 2U);
350 
351     const uint32_t maxCount = Math::min(DefaultMaterialCameraConstants::MAX_CAMERA_MULTI_ENVIRONMENT_COUNT, 2U);
352     uint32_t binding = 0U;
353     binder.BindBuffer(binding++, { environmentUbo_ });
354     BindableImage bi;
355     // additional cubemaps from first index
356     for (uint32_t resIdx = 0U; resIdx < maxCount; ++resIdx) {
357         // filled with valid handles
358         bi.handle = blendImages[resIdx];
359         bi.samplerHandle = defaultImagesAndSamplers_.cubemapSamplerHandle;
360         binder.BindImage(binding++, bi, {});
361     }
362 }
363 
InitializeShaderData()364 void RenderNodeDefaultEnvironmentBlender::InitializeShaderData()
365 {
366     if (!hasInitializedShaderData_) {
367         hasInitializedShaderData_ = true;
368 
369         auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
370         defaultImagesAndSamplers_ = GetDefaultImagesAndSamplers(gpuResourceMgr);
371         const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
372         const RenderHandleType handleType = RenderHandleUtil::GetHandleType(shader_);
373         const RenderHandle plHandle = shaderMgr.GetReflectionPipelineLayoutHandle(shader_);
374         pipelineLayout_ = shaderMgr.GetPipelineLayout(plHandle);
375         if (handleType == RenderHandleType::SHADER_STATE_OBJECT) {
376             const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(shader_);
377             psoHandle_ = renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(
378                 shader_, graphicsState, pipelineLayout_, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
379         } else {
380             CORE_LOG_E("RN:%s needs a valid shader handle", renderNodeContextMgr_->GetName().data());
381         }
382         InitCreateBinders();
383     }
384 }
385 
InitCreateBinders()386 void RenderNodeDefaultEnvironmentBlender::InitCreateBinders()
387 {
388     const IRenderNodeUtil& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
389     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
390     {
391         DescriptorCounts dc = renderNodeUtil.GetDescriptorCounts(pipelineLayout_);
392         for (uint32_t idx = 0; idx < dc.counts.size(); ++idx) {
393             dc.counts[idx].count *= MAX_MIP_COUNT * CORE_DEFAULT_MATERIAL_MAX_ENVIRONMENT_COUNT;
394         }
395         descriptorSetMgr.ResetAndReserve(dc);
396     }
397 
398     allEnvSets_.clear();
399     allEnvSets_.resize(CORE_DEFAULT_MATERIAL_MAX_ENVIRONMENT_COUNT);
400 
401     for (auto& setsRef : allEnvSets_) {
402         setsRef.localSets.resize(MAX_MIP_COUNT);
403         const auto& bindings = pipelineLayout_.descriptorSetLayouts[0U].bindings;
404         for (uint32_t idx = 0; idx < MAX_MIP_COUNT; ++idx) {
405             const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
406             setsRef.localSets[idx] = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
407         }
408     }
409 
410     if ((!RenderHandleUtil::IsValid(shader_)) || (!RenderHandleUtil::IsValid(psoHandle_))) {
411         valid_ = false;
412     }
413 }
414 
ParseRenderNodeInputs()415 void RenderNodeDefaultEnvironmentBlender::ParseRenderNodeInputs()
416 {
417     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
418     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
419     const auto shaderName = parserUtil.GetStringValue(jsonVal, "shader");
420     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
421     if (!shaderName.empty()) {
422         shader_ = shaderMgr.GetShaderHandle(shaderName);
423     } else {
424         shader_ = shaderMgr.GetShaderHandle(DEFAULT_CUBEMAP_BLENDER_SHADER);
425     }
426 }
427 
UpdateImageData()428 void RenderNodeDefaultEnvironmentBlender::UpdateImageData()
429 {
430     const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
431     if (!RenderHandleUtil::IsValid(builtInVariables_.defBlackImage)) {
432         builtInVariables_.defBlackImage = gpuResourceMgr.GetImageHandle(CORE_DEFAULT_GPU_IMAGE_BLACK);
433     }
434     if (!RenderHandleUtil::IsValid(builtInVariables_.defSampler)) {
435         builtInVariables_.defSampler = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
436     }
437 }
438 
439 // for plugin / factory interface
Create()440 IRenderNode* RenderNodeDefaultEnvironmentBlender::Create()
441 {
442     return new RenderNodeDefaultEnvironmentBlender();
443 }
444 
Destroy(IRenderNode * instance)445 void RenderNodeDefaultEnvironmentBlender::Destroy(IRenderNode* instance)
446 {
447     delete static_cast<RenderNodeDefaultEnvironmentBlender*>(instance);
448 }
449 CORE3D_END_NAMESPACE()
450