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