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_material_render_slot.h"
17
18 #include <algorithm>
19
20 #include <3d/render/default_material_constants.h>
21 #include <3d/render/intf_render_data_store_default_camera.h>
22 #include <3d/render/intf_render_data_store_default_light.h>
23 #include <3d/render/intf_render_data_store_default_material.h>
24 #include <3d/render/intf_render_data_store_default_scene.h>
25 #include <base/math/matrix_util.h>
26 #include <base/math/vector.h>
27 #include <core/log.h>
28 #include <core/namespace.h>
29 #include <render/datastore/intf_render_data_store.h>
30 #include <render/datastore/intf_render_data_store_manager.h>
31 #include <render/datastore/intf_render_data_store_pod.h>
32 #include <render/datastore/render_data_store_render_pods.h>
33 #include <render/device/intf_gpu_resource_manager.h>
34 #include <render/device/intf_shader_manager.h>
35 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
36 #include <render/nodecontext/intf_node_context_pso_manager.h>
37 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
38 #include <render/nodecontext/intf_render_command_list.h>
39 #include <render/nodecontext/intf_render_node_context_manager.h>
40 #include <render/nodecontext/intf_render_node_parser_util.h>
41 #include <render/nodecontext/intf_render_node_util.h>
42 #include <render/resource_handle.h>
43
44 #include "render/render_node_scene_util.h"
45
46 #if (CORE3D_DEV_ENABLED == 1)
47 #include "render/datastore/render_data_store_default_material.h"
48 #endif
49
50 namespace {
51 #include <3d/shaders/common/3d_dm_structures_common.h>
52 #include <render/shaders/common/render_post_process_structs_common.h>
53 } // namespace
54
55 CORE3D_BEGIN_NAMESPACE()
56 using namespace BASE_NS;
57 using namespace RENDER_NS;
58
59 namespace {
60 constexpr string_view POST_PROCESS_DATA_STORE_TYPE_NAME { "RenderDataStorePod" };
61 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
62 constexpr DynamicStateEnum DYNAMIC_STATES_FSR[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR,
63 CORE_DYNAMIC_STATE_ENUM_FRAGMENT_SHADING_RATE };
64
65 constexpr uint32_t UBO_BIND_OFFSET_ALIGNMENT { PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
66
67 static constexpr uint64_t LIGHTING_FLAGS_SHIFT { 32u };
68 static constexpr uint64_t LIGHTING_FLAGS_MASK { 0xF00000000u };
69 static constexpr uint64_t POST_PROCESS_FLAGS_SHIFT { 36u };
70 static constexpr uint64_t POST_PROCESS_FLAGS_MASK { 0xF000000000u };
71 static constexpr uint64_t CAMERA_FLAGS_SHIFT { 40u };
72 static constexpr uint64_t CAMERA_FLAGS_MASK { 0xF0000000000u };
73 static constexpr uint64_t RENDER_HASH_FLAGS_MASK { 0xFFFFffffu };
74
75 // our light weight straight to screen post processes are only interested in these
76 static constexpr uint32_t POST_PROCESS_IMPORTANT_FLAGS_MASK { 0xffu };
77
78 static constexpr uint32_t FIXED_CUSTOM_SET3 { 3u };
79 static constexpr uint32_t CUSTOM_SET_DESCRIPTOR_SET_COUNT { 4u };
80
GetDefaultMaterialGpuResources(const IRenderNodeGpuResourceManager & gpuResourceMgr,RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct & defaultMat)81 void GetDefaultMaterialGpuResources(const IRenderNodeGpuResourceManager& gpuResourceMgr,
82 RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct& defaultMat)
83 {
84 defaultMat.resources[MaterialComponent::TextureIndex::BASE_COLOR].handle =
85 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_BASE_COLOR);
86 defaultMat.resources[MaterialComponent::TextureIndex::NORMAL].handle =
87 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_NORMAL);
88 defaultMat.resources[MaterialComponent::TextureIndex::MATERIAL].handle =
89 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_MATERIAL);
90 defaultMat.resources[MaterialComponent::TextureIndex::EMISSIVE].handle =
91 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_EMISSIVE);
92 defaultMat.resources[MaterialComponent::TextureIndex::AO].handle =
93 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_AO);
94
95 defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT].handle =
96 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT);
97 defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT_ROUGHNESS].handle =
98 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT_ROUGHNESS);
99 defaultMat.resources[MaterialComponent::TextureIndex::CLEARCOAT_NORMAL].handle =
100 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_CLEARCOAT_NORMAL);
101
102 defaultMat.resources[MaterialComponent::TextureIndex::SHEEN].handle =
103 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_SHEEN);
104
105 defaultMat.resources[MaterialComponent::TextureIndex::TRANSMISSION].handle =
106 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_TRANSMISSION);
107
108 defaultMat.resources[MaterialComponent::TextureIndex::SPECULAR].handle =
109 gpuResourceMgr.GetImageHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_MATERIAL_SPECULAR);
110
111 const RenderHandle samplerHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT");
112 for (uint32_t idx = 0; idx < countof(defaultMat.resources); ++idx) {
113 defaultMat.resources[idx].samplerHandle = samplerHandle;
114 }
115 }
116
GetShadowBufferNodeData(IRenderNodeGpuResourceManager & gpuResourceMgr,const string_view sceneName)117 RenderNodeDefaultMaterialRenderSlot::ShadowBuffers GetShadowBufferNodeData(
118 IRenderNodeGpuResourceManager& gpuResourceMgr, const string_view sceneName)
119 {
120 RenderNodeDefaultMaterialRenderSlot::ShadowBuffers sb;
121 sb.vsmSamplerHandle =
122 gpuResourceMgr.GetSamplerHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_VSM_SHADOW_SAMPLER);
123 sb.pcfSamplerHandle =
124 gpuResourceMgr.GetSamplerHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_PCF_SHADOW_SAMPLER);
125
126 sb.depthHandle =
127 gpuResourceMgr.GetImageHandle(sceneName + DefaultMaterialLightingConstants::SHADOW_DEPTH_BUFFER_NAME);
128 sb.vsmColorHandle =
129 gpuResourceMgr.GetImageHandle(sceneName + DefaultMaterialLightingConstants::SHADOW_VSM_COLOR_BUFFER_NAME);
130 if (!RenderHandleUtil::IsValid(sb.depthHandle)) {
131 sb.depthHandle = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_GPU_IMAGE_WHITE");
132 }
133 if (!RenderHandleUtil::IsValid(sb.vsmColorHandle)) {
134 sb.vsmColorHandle = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_GPU_IMAGE");
135 }
136
137 return sb;
138 }
139
HashShaderDataAndSubmesh(const uint64_t shaderDataHash,const uint32_t renderHash,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags & cameraShaderFlags,const PostProcessConfiguration::PostProcessEnableFlags postProcessFlags)140 inline uint64_t HashShaderDataAndSubmesh(const uint64_t shaderDataHash, const uint32_t renderHash,
141 const IRenderDataStoreDefaultLight::LightingFlags lightingFlags, const RenderCamera::ShaderFlags& cameraShaderFlags,
142 const PostProcessConfiguration::PostProcessEnableFlags postProcessFlags)
143 {
144 const uint32_t ppEnabled = (postProcessFlags > 0);
145 uint64_t hash = ((uint64_t)renderHash & RENDER_HASH_FLAGS_MASK) |
146 (((uint64_t)lightingFlags << LIGHTING_FLAGS_SHIFT) & LIGHTING_FLAGS_MASK) |
147 (((uint64_t)ppEnabled << POST_PROCESS_FLAGS_SHIFT) & POST_PROCESS_FLAGS_MASK) |
148 (((uint64_t)cameraShaderFlags << CAMERA_FLAGS_SHIFT) & CAMERA_FLAGS_MASK);
149 HashCombine(hash, shaderDataHash);
150 return hash;
151 }
152
IsInverseWinding(const RenderSubmeshFlags submeshFlags,const RenderSceneFlags sceneRenderingFlags,const RenderCamera::Flags cameraRenderingFlags)153 inline bool IsInverseWinding(const RenderSubmeshFlags submeshFlags, const RenderSceneFlags sceneRenderingFlags,
154 const RenderCamera::Flags cameraRenderingFlags)
155 {
156 const bool flipWinding = (sceneRenderingFlags & RENDER_SCENE_FLIP_WINDING_BIT) |
157 (cameraRenderingFlags & RenderCamera::CAMERA_FLAG_INVERSE_WINDING_BIT);
158 const bool isNegative = flipWinding
159 ? !((submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT) > 0)
160 : ((submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_INVERSE_WINDING_BIT) > 0);
161 return isNegative;
162 }
163
UpdateCurrentMaterialHandles(const RenderSubmesh & currSubmesh,const RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct & defaultMat,const RenderDataDefaultMaterial::MaterialHandles & currSubmeshHandles,RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct & currMaterialHandles)164 void UpdateCurrentMaterialHandles(const RenderSubmesh& currSubmesh,
165 const RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct& defaultMat,
166 const RenderDataDefaultMaterial::MaterialHandles& currSubmeshHandles,
167 RenderNodeDefaultMaterialRenderSlot::MaterialHandleStruct& currMaterialHandles)
168 {
169 for (uint32_t idx = 0; idx < countof(currSubmeshHandles.images); ++idx) {
170 const auto& defaultRes = defaultMat.resources[idx];
171 const auto& srcImage = currSubmeshHandles.images[idx].GetHandle();
172 const auto& srcSampler = currSubmeshHandles.samplers[idx].GetHandle();
173 auto& dst = currMaterialHandles.resources[idx];
174 dst.handle = RenderHandleUtil::IsValid(srcImage) ? srcImage : defaultRes.handle;
175 dst.samplerHandle = RenderHandleUtil::IsValid(srcSampler) ? srcSampler : defaultRes.samplerHandle;
176 }
177 }
178 } // namespace
179
InitNode(IRenderNodeContextManager & renderNodeContextMgr)180 void RenderNodeDefaultMaterialRenderSlot::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
181 {
182 renderNodeContextMgr_ = &renderNodeContextMgr;
183 ParseRenderNodeInputs();
184
185 const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
186 stores_ = RenderNodeSceneUtil::GetSceneRenderDataStores(
187 renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
188
189 // reset
190 currentScene_ = {};
191 allShaderData_ = {};
192 objectCounts_ = {};
193
194 if ((jsonInputs_.nodeFlags & RenderSceneFlagBits::RENDER_SCENE_DIRECT_POST_PROCESS_BIT) &&
195 jsonInputs_.renderDataStore.dataStoreName.empty()) {
196 CORE_LOG_V("%s: render data store post process configuration not set in render node graph",
197 renderNodeContextMgr_->GetName().data());
198 }
199 rngRenderPass_ = renderNodeContextMgr_->GetRenderNodeUtil().CreateRenderPass(inputRenderPass_);
200 CreateDefaultShaderData();
201
202 auto& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
203 defaultSamplers_.cubemapHandle =
204 gpuResourceMgr.GetSamplerHandle(DefaultMaterialGpuResourceConstants::CORE_DEFAULT_RADIANCE_CUBEMAP_SAMPLER);
205 defaultSamplers_.linearHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
206 defaultSamplers_.nearestHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_NEAREST_CLAMP");
207 defaultSamplers_.linearMipHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP");
208 defaultColorPrePassHandle_ = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_GPU_IMAGE");
209
210 GetSceneUniformBuffers(stores_.dataStoreNameScene);
211
212 shadowBuffers_ = GetShadowBufferNodeData(gpuResourceMgr, stores_.dataStoreNameScene);
213
214 GetDefaultMaterialGpuResources(gpuResourceMgr, defaultMaterialStruct_);
215 }
216
PreExecuteFrame()217 void RenderNodeDefaultMaterialRenderSlot::PreExecuteFrame()
218 {
219 // re-create needed gpu resources
220 const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
221 const IRenderDataStoreDefaultMaterial* dataStoreMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(
222 renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameMaterial));
223 // we need to have all buffers created (reason to have at least 1u)
224 if (dataStoreMaterial) {
225 const auto dsOc = dataStoreMaterial->GetSlotObjectCounts(jsonInputs_.renderSlotId);
226 const ObjectCounts oc {
227 Math::max(dsOc.meshCount, 1u),
228 Math::max(dsOc.submeshCount, 1u),
229 Math::max(dsOc.skinCount, 1u),
230 Math::max(dsOc.materialCount, 1u),
231 };
232 ProcessBuffersAndDescriptors(oc);
233 } else if (objectCounts_.maxSlotMeshCount == 0) {
234 ProcessBuffersAndDescriptors({ 1u, 1u, 1u, 1u });
235 }
236 }
237
ExecuteFrame(IRenderCommandList & cmdList)238 void RenderNodeDefaultMaterialRenderSlot::ExecuteFrame(IRenderCommandList& cmdList)
239 {
240 const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
241 const auto* dataStoreScene =
242 static_cast<IRenderDataStoreDefaultScene*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameScene));
243 const auto* dataStoreMaterial = static_cast<IRenderDataStoreDefaultMaterial*>(
244 renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameMaterial));
245 const auto* dataStoreCamera =
246 static_cast<IRenderDataStoreDefaultCamera*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameCamera));
247 const auto* dataStoreLight =
248 static_cast<IRenderDataStoreDefaultLight*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameLight));
249
250 const bool validRenderDataStore = dataStoreScene && dataStoreMaterial && dataStoreCamera && dataStoreLight;
251 if (validRenderDataStore) {
252 UpdateCurrentScene(*dataStoreScene, *dataStoreCamera, *dataStoreLight);
253 } else {
254 CORE_LOG_E("invalid render data stores in RenderNodeDefaultMaterialRenderSlot");
255 }
256
257 cmdList.BeginRenderPass(renderPass_.renderPassDesc, renderPass_.subpassStartIndex, renderPass_.subpassDesc);
258
259 if (validRenderDataStore) {
260 const auto cameras = dataStoreCamera->GetCameras();
261 const auto scene = dataStoreScene->GetScene();
262
263 const bool hasShaders = allShaderData_.slotHasShaders;
264 const bool hasCamera =
265 (!cameras.empty() && (currentScene_.cameraIdx < (uint32_t)cameras.size())) ? true : false;
266
267 ProcessSlotSubmeshes(*dataStoreCamera, *dataStoreMaterial);
268 const bool hasSubmeshes = (!sortedSlotSubmeshes_.empty());
269 if (hasShaders && hasCamera && hasSubmeshes) {
270 UpdatePostProcessConfiguration();
271 RenderSubmeshes(cmdList, *dataStoreMaterial, *dataStoreCamera);
272 }
273 }
274
275 cmdList.EndRenderPass();
276 }
277
RenderSubmeshes(IRenderCommandList & cmdList,const IRenderDataStoreDefaultMaterial & dataStoreMaterial,const IRenderDataStoreDefaultCamera & dataStoreCamera)278 void RenderNodeDefaultMaterialRenderSlot::RenderSubmeshes(IRenderCommandList& cmdList,
279 const IRenderDataStoreDefaultMaterial& dataStoreMaterial, const IRenderDataStoreDefaultCamera& dataStoreCamera)
280 {
281 const size_t submeshCount = sortedSlotSubmeshes_.size();
282 CORE_ASSERT(submeshCount <= objectCounts_.maxSlotSubmeshCount);
283
284 // dynamic state
285 cmdList.SetDynamicStateViewport(currentScene_.viewportDesc);
286 cmdList.SetDynamicStateScissor(currentScene_.scissorDesc);
287 if (fsrEnabled_) {
288 cmdList.SetDynamicStateFragmentShadingRate(
289 { 1u, 1u }, FragmentShadingRateCombinerOps { CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE,
290 CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE });
291 }
292
293 // set 0, update camera, general data, and lighting
294 // set 1, update mesh matrices, material data, and skinning data (uses dynamic offset)
295 UpdateSet01(cmdList);
296
297 // first two sets are only bound for the first submesh (inside for loop)
298 // no bindless, we need to update images per object
299 RenderHandle boundPsoHandle = {};
300 uint64_t boundShaderHash = 0;
301 uint32_t currMaterialIndex = ~0u;
302 MaterialHandleStruct currentMaterialHandles;
303 bool initialBindDone = false; // cannot be checked from the idx
304 bool boundCustomSetNeed = false;
305
306 const auto& materialHandles = dataStoreMaterial.GetMaterialHandles();
307 const auto& submeshMaterialFlags = dataStoreMaterial.GetSubmeshMaterialFlags();
308 const auto& submeshes = dataStoreMaterial.GetSubmeshes();
309 const auto& customResourceHandles = dataStoreMaterial.GetCustomResourceHandles();
310 const uint64_t camLayerMask = currentScene_.camera.layerMask;
311 for (size_t idx = 0; idx < submeshCount; ++idx) {
312 const auto& ssp = sortedSlotSubmeshes_[idx];
313 const uint32_t submeshIndex = ssp.submeshIndex;
314 const auto& currSubmesh = submeshes[submeshIndex];
315 const auto& currSubmeshMatHandles = materialHandles[currSubmesh.materialIndex];
316 const RenderSubmeshFlags submeshFlags = currSubmesh.submeshFlags | jsonInputs_.nodeSubmeshExtraFlags;
317 auto currMaterialFlags = submeshMaterialFlags[submeshIndex];
318
319 // sorted slot submeshes should already have removed layers if default sorting was used
320 if (((camLayerMask & currSubmesh.layerMask) == 0) ||
321 ((jsonInputs_.nodeFlags & RENDER_SCENE_DISCARD_MATERIAL_BIT) &&
322 (currMaterialFlags.extraMaterialRenderingFlags &
323 RenderExtraRenderingFlagBits::RENDER_EXTRA_RENDERING_DISCARD_BIT))) {
324 continue;
325 }
326
327 uint32_t renderHash = currMaterialFlags.renderHash;
328 if (!currentScene_.hasShadow) { // remove shadow if not in scene
329 currMaterialFlags.renderMaterialFlags =
330 currMaterialFlags.renderMaterialFlags & (~RenderMaterialFlagBits::RENDER_MATERIAL_SHADOW_RECEIVER_BIT);
331 renderHash = dataStoreMaterial.GenerateRenderHash(currMaterialFlags);
332 }
333 // get shader and graphics state and start hashing
334 ShaderStateData ssd { ssp.shaderHandle, ssp.gfxStateHandle, 0 };
335 ssd.hash = (ssd.shader.id << 32U) | (ssd.gfxState.id & 0xFFFFffff);
336 // current shader state is fetched for build-in and custom shaders (decision is made later)
337 ssd.hash = HashShaderDataAndSubmesh(ssd.hash, renderHash, currentScene_.lightingFlags,
338 currentScene_.cameraShaderFlags, currentRenderPPConfiguration_.flags.x);
339 if (ssd.hash != boundShaderHash) {
340 const PsoAndInfo psoAndInfo = GetSubmeshPso(
341 ssd, currMaterialFlags, submeshFlags, currentScene_.lightingFlags, currentScene_.cameraShaderFlags);
342 if (psoAndInfo.pso.id != boundPsoHandle.id) {
343 boundShaderHash = ssd.hash;
344 boundPsoHandle = psoAndInfo.pso;
345 cmdList.BindPipeline(boundPsoHandle);
346 boundCustomSetNeed = psoAndInfo.set3;
347 }
348 }
349
350 // bind first set only the first time
351 if (!initialBindDone) {
352 RenderHandle setResourceHandles[2u] { allDescriptorSets_.set01[0u]->GetDescriptorSetHandle(),
353 allDescriptorSets_.set01[1u]->GetDescriptorSetHandle() };
354 cmdList.BindDescriptorSets(0, { setResourceHandles, 2u });
355 }
356
357 // set 1 (mesh matrix, skin matrices, material, material user data)
358 const uint32_t currMeshMatrixOffset = currSubmesh.meshIndex * UBO_BIND_OFFSET_ALIGNMENT;
359 const uint32_t currMaterialOffset = currSubmesh.materialIndex * UBO_BIND_OFFSET_ALIGNMENT;
360 const uint32_t currMaterialTransformOffset = currSubmesh.materialIndex * UBO_BIND_OFFSET_ALIGNMENT;
361 const uint32_t currUserMaterialOffset = currSubmesh.materialIndex * UBO_BIND_OFFSET_ALIGNMENT;
362 uint32_t currJointMatrixOffset = 0u;
363 if (submeshFlags & RenderSubmeshFlagBits::RENDER_SUBMESH_SKIN_BIT) {
364 currJointMatrixOffset =
365 currSubmesh.skinJointIndex * static_cast<uint32_t>(sizeof(DefaultMaterialSkinStruct));
366 }
367 const uint32_t dynamicOffsets[] = { currMeshMatrixOffset, currJointMatrixOffset, currMaterialOffset,
368 currMaterialTransformOffset, currUserMaterialOffset };
369 // set to bind, handle to resource, offsets for dynamic descs
370 cmdList.BindDescriptorSet(1u, allDescriptorSets_.set01[1u]->GetDescriptorSetHandle(), dynamicOffsets);
371
372 // update material descriptor set
373 if ((!initialBindDone) || (currMaterialIndex != currSubmesh.materialIndex)) {
374 // the data changes, when the material changes, so we need to rebind the material data
375 UpdateCurrentMaterialHandles(
376 currSubmesh, defaultMaterialStruct_, currSubmeshMatHandles, currentMaterialHandles);
377 UpdateAndBindSet2(cmdList, currentMaterialHandles, static_cast<uint32_t>(idx));
378 currMaterialIndex = currSubmesh.materialIndex;
379 }
380
381 initialBindDone = true;
382
383 // custom set 3 resources
384 if (boundCustomSetNeed) {
385 // if we do not have custom resources, and if we have binding issues we skip
386 if ((!(currSubmesh.customResourcesIndex < static_cast<uint32_t>(customResourceHandles.size()))) ||
387 (!UpdateAndBindSet3(cmdList, customResourceHandles[currSubmesh.customResourcesIndex]))) {
388 continue; // we prevent drawing
389 }
390 }
391
392 // vertex buffers and draw
393 if (currSubmesh.vertexBufferCount > 0) {
394 VertexBuffer vbs[RENDER_NS::PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT];
395 for (uint32_t vbIdx = 0; vbIdx < currSubmesh.vertexBufferCount; ++vbIdx) {
396 vbs[vbIdx] = ConvertVertexBuffer(currSubmesh.vertexBuffers[vbIdx]);
397 }
398 cmdList.BindVertexBuffers({ vbs, currSubmesh.vertexBufferCount });
399 }
400 const auto& dc = currSubmesh.drawCommand;
401 const RenderVertexBuffer& iArgs = currSubmesh.indirectArgsBuffer;
402 const bool indirectDraw = iArgs.bufferHandle ? true : false;
403 if (currSubmesh.indexBuffer.byteSize > 0U) {
404 cmdList.BindIndexBuffer(ConvertIndexBuffer(currSubmesh.indexBuffer));
405 if (indirectDraw) {
406 cmdList.DrawIndexedIndirect(iArgs.bufferHandle.GetHandle(), iArgs.bufferOffset, 1u, 0u);
407 } else {
408 cmdList.DrawIndexed(dc.indexCount, dc.instanceCount, 0, 0, 0);
409 }
410 } else {
411 if (indirectDraw) {
412 cmdList.DrawIndirect(iArgs.bufferHandle.GetHandle(), iArgs.bufferOffset, 1u, 0u);
413 } else {
414 cmdList.Draw(dc.vertexCount, dc.instanceCount, 0, 0);
415 }
416 }
417 }
418 }
419
UpdateSet01(IRenderCommandList & cmdList)420 void RenderNodeDefaultMaterialRenderSlot::UpdateSet01(IRenderCommandList& cmdList)
421 {
422 auto& binder0 = *allDescriptorSets_.set01[0u];
423 auto& binder1 = *allDescriptorSets_.set01[1u];
424 {
425 auto& binder = binder0;
426 uint32_t bindingIndex = 0;
427 binder.BindBuffer(bindingIndex++, sceneBuffers_.camera, 0u);
428 binder.BindBuffer(bindingIndex++, cameraBuffers_.generalData, 0u);
429
430 const RenderHandle radianceCubemap = currentScene_.cameraEnvRadianceHandle;
431 const RenderHandle colorPrePass = RenderHandleUtil::IsValid(currentScene_.prePassColorTarget)
432 ? currentScene_.prePassColorTarget
433 : defaultColorPrePassHandle_;
434
435 binder.BindBuffer(
436 bindingIndex++, { cameraBuffers_.environment, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
437 binder.BindBuffer(bindingIndex++, { cameraBuffers_.fog, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
438 binder.BindBuffer(bindingIndex++, { cameraBuffers_.light, 0u, PipelineStateConstants ::GPU_BUFFER_WHOLE_SIZE });
439 binder.BindBuffer(
440 bindingIndex++, { cameraBuffers_.postProcess, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
441 binder.BindBuffer(
442 bindingIndex++, { cameraBuffers_.lightCluster, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
443 // use immutable samplers for all set 0 samplers
444 BindableImage bi;
445 bi.handle = colorPrePass;
446 bi.samplerHandle = defaultSamplers_.linearMipHandle;
447 binder.BindImage(bindingIndex++, bi, CORE_ADDITIONAL_DESCRIPTOR_IMMUTABLE_SAMPLER_BIT);
448 bi.handle = shadowBuffers_.vsmColorHandle;
449 bi.samplerHandle = shadowBuffers_.vsmSamplerHandle;
450 binder.BindImage(bindingIndex++, bi, CORE_ADDITIONAL_DESCRIPTOR_IMMUTABLE_SAMPLER_BIT);
451 bi.handle = shadowBuffers_.depthHandle;
452 bi.samplerHandle = shadowBuffers_.pcfSamplerHandle;
453 binder.BindImage(bindingIndex++, bi, CORE_ADDITIONAL_DESCRIPTOR_IMMUTABLE_SAMPLER_BIT);
454 bi.handle = radianceCubemap;
455 bi.samplerHandle = defaultSamplers_.cubemapHandle;
456 binder.BindImage(bindingIndex++, bi, CORE_ADDITIONAL_DESCRIPTOR_IMMUTABLE_SAMPLER_BIT);
457 }
458 {
459 auto& binder = binder1;
460 // NOTE: should be PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE or current size
461 constexpr uint32_t skinSize = sizeof(DefaultMaterialSkinStruct);
462 uint32_t bindingIdx = 0u;
463 binder.BindBuffer(bindingIdx++, sceneBuffers_.mesh, 0u, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
464 binder.BindBuffer(bindingIdx++, sceneBuffers_.skinJoint, 0u, skinSize);
465 binder.BindBuffer(bindingIdx++, sceneBuffers_.material, 0, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
466 binder.BindBuffer(
467 bindingIdx++, sceneBuffers_.materialTransform, 0, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
468 binder.BindBuffer(
469 bindingIdx++, sceneBuffers_.materialCustom, 0, PipelineLayoutConstants::MAX_UBO_BIND_BYTE_SIZE);
470 }
471
472 const RenderHandle handles[] { binder0.GetDescriptorSetHandle(), binder1.GetDescriptorSetHandle() };
473 const DescriptorSetLayoutBindingResources resources[] { binder0.GetDescriptorSetLayoutBindingResources(),
474 binder1.GetDescriptorSetLayoutBindingResources() };
475 cmdList.UpdateDescriptorSets(handles, resources);
476 }
477
UpdateAndBindSet2(IRenderCommandList & cmdList,const MaterialHandleStruct & materialHandles,const uint32_t objIdx)478 void RenderNodeDefaultMaterialRenderSlot::UpdateAndBindSet2(
479 IRenderCommandList& cmdList, const MaterialHandleStruct& materialHandles, const uint32_t objIdx)
480 {
481 auto& binder = *allDescriptorSets_.sets2[objIdx];
482 uint32_t bindingIdx = 0u;
483
484 // base color is bound separately to support e.g. gles automatic OES shader modification
485 binder.BindImage(bindingIdx++, materialHandles.resources[MaterialComponent::TextureIndex::BASE_COLOR]);
486
487 CORE_STATIC_ASSERT(MaterialComponent::TextureIndex::BASE_COLOR == 0);
488 // skip baseColor as it's bound already
489 constexpr size_t theCount = RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT - 1;
490 binder.BindImages(bindingIdx++, array_view(materialHandles.resources + 1, theCount));
491
492 cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
493 cmdList.BindDescriptorSet(2u, binder.GetDescriptorSetHandle()); // set to bind
494 }
495
UpdateAndBindSet3(IRenderCommandList & cmdList,const RenderDataDefaultMaterial::CustomResourceData & customResourceData)496 bool RenderNodeDefaultMaterialRenderSlot::UpdateAndBindSet3(
497 IRenderCommandList& cmdList, const RenderDataDefaultMaterial::CustomResourceData& customResourceData)
498 {
499 IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
500 INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
501 const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
502
503 RenderHandle currPlHandle =
504 shaderMgr.GetPipelineLayoutHandleByShaderHandle(customResourceData.shaderHandle.GetHandle());
505 const PipelineLayout& plRef = shaderMgr.GetPipelineLayout(currPlHandle);
506 if (plRef.descriptorSetCount < CUSTOM_SET_DESCRIPTOR_SET_COUNT) {
507 return false; // early out
508 }
509 const auto& descBindings = plRef.descriptorSetLayouts[FIXED_CUSTOM_SET3].bindings;
510 const RenderHandle descSetHandle = descriptorSetMgr.CreateOneFrameDescriptorSet(descBindings);
511 bool valid = false;
512 if (RenderHandleUtil::IsValid(descSetHandle) && (descBindings.size() == customResourceData.resourceHandleCount)) {
513 IDescriptorSetBinder::Ptr binderPtr = descriptorSetMgr.CreateDescriptorSetBinder(descSetHandle, descBindings);
514 if (binderPtr) {
515 auto& binder = *binderPtr;
516 for (uint32_t idx = 0; idx < customResourceData.resourceHandleCount; ++idx) {
517 CORE_ASSERT(idx < descBindings.size());
518 const RenderHandle& currRes = customResourceData.resourceHandles[idx].GetHandle();
519 if (gpuResourceMgr.IsGpuBuffer(currRes)) {
520 binder.BindBuffer(idx, currRes, 0);
521 } else if (gpuResourceMgr.IsGpuImage(currRes)) {
522 if (descBindings[idx].descriptorType ==
523 DescriptorType::CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
524 binder.BindImage(idx, currRes, defaultSamplers_.linearMipHandle);
525 } else {
526 binder.BindImage(idx, currRes);
527 }
528 } else if (gpuResourceMgr.IsGpuSampler(currRes)) {
529 binder.BindSampler(idx, currRes);
530 }
531 }
532
533 // user generated setup, we check for validity of all bindings in the descriptor set
534 if (binder.GetDescriptorSetLayoutBindingValidity()) {
535 cmdList.UpdateDescriptorSet(
536 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
537 cmdList.BindDescriptorSet(FIXED_CUSTOM_SET3, binder.GetDescriptorSetHandle());
538 valid = true;
539 }
540 }
541 }
542 if (!valid) {
543 #if (CORE3D_VALIDATION_ENABLED == 1)
544 CORE_LOG_ONCE_W("material_render_slot_custom_set3_issue",
545 "invalid bindings with custom shader descriptor set 3 (render node: %s)",
546 renderNodeContextMgr_->GetName().data());
547 #endif
548 }
549 return valid;
550 }
551
GetSubmeshPso(const ShaderStateData & ssd,const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMaterialFlags,const RenderSubmeshFlags submeshFlags,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags cameraShaderFlags)552 RenderNodeDefaultMaterialRenderSlot::PsoAndInfo RenderNodeDefaultMaterialRenderSlot::GetSubmeshPso(
553 const ShaderStateData& ssd, const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMaterialFlags,
554 const RenderSubmeshFlags submeshFlags, const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,
555 const RenderCamera::ShaderFlags cameraShaderFlags)
556 {
557 if (const auto dataIter = allShaderData_.shaderIdToData.find(ssd.hash);
558 dataIter != allShaderData_.shaderIdToData.cend()) {
559 const auto& ref = allShaderData_.perShaderData[dataIter->second];
560 return { ref.psoHandle, ref.needsCustomSetBindings };
561 }
562
563 return CreateNewPso(ssd, submeshMaterialFlags, submeshFlags, lightingFlags, cameraShaderFlags);
564 }
565
UpdatePostProcessConfiguration()566 void RenderNodeDefaultMaterialRenderSlot::UpdatePostProcessConfiguration()
567 {
568 if (jsonInputs_.nodeFlags & RenderSceneFlagBits::RENDER_SCENE_DIRECT_POST_PROCESS_BIT) {
569 if (!jsonInputs_.renderDataStore.dataStoreName.empty()) {
570 auto const& dsMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
571 if (const IRenderDataStore* ds = dsMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName); ds) {
572 if (jsonInputs_.renderDataStore.typeName == POST_PROCESS_DATA_STORE_TYPE_NAME) {
573 auto const dataStore = static_cast<IRenderDataStorePod const*>(ds);
574 auto const dataView = dataStore->Get(jsonInputs_.renderDataStore.configurationName);
575 if (dataView.data() && (dataView.size_bytes() == sizeof(PostProcessConfiguration))) {
576 const PostProcessConfiguration* data = (const PostProcessConfiguration*)dataView.data();
577 currentRenderPPConfiguration_ =
578 renderNodeContextMgr_->GetRenderNodeUtil().GetRenderPostProcessConfiguration(*data);
579 currentRenderPPConfiguration_.flags.x =
580 (currentRenderPPConfiguration_.flags.x & POST_PROCESS_IMPORTANT_FLAGS_MASK);
581 }
582 }
583 }
584 }
585 }
586 }
587
UpdateCurrentScene(const IRenderDataStoreDefaultScene & dataStoreScene,const IRenderDataStoreDefaultCamera & dataStoreCamera,const IRenderDataStoreDefaultLight & dataStoreLight)588 void RenderNodeDefaultMaterialRenderSlot::UpdateCurrentScene(const IRenderDataStoreDefaultScene& dataStoreScene,
589 const IRenderDataStoreDefaultCamera& dataStoreCamera, const IRenderDataStoreDefaultLight& dataStoreLight)
590 {
591 if (jsonInputs_.hasChangeableRenderPassHandles) {
592 const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
593 inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
594 rngRenderPass_ = renderNodeContextMgr_->GetRenderNodeUtil().CreateRenderPass(inputRenderPass_);
595 }
596 // get default RNG based render pass setup
597 renderPass_ = rngRenderPass_;
598
599 const auto scene = dataStoreScene.GetScene();
600 bool hasCustomCamera = false;
601 bool isNamedCamera = false; // NOTE: legacy support will be removed
602 uint32_t cameraIdx = scene.cameraIndex;
603 if (jsonInputs_.customCameraId != INVALID_CAM_ID) {
604 cameraIdx = dataStoreCamera.GetCameraIndex(jsonInputs_.customCameraId);
605 hasCustomCamera = true;
606 } else if (!(jsonInputs_.customCameraName.empty())) {
607 cameraIdx = dataStoreCamera.GetCameraIndex(jsonInputs_.customCameraName);
608 hasCustomCamera = true;
609 isNamedCamera = true;
610 }
611
612 if (const auto cameras = dataStoreCamera.GetCameras(); cameraIdx < (uint32_t)cameras.size()) {
613 // store current frame camera
614 currentScene_.camera = cameras[cameraIdx];
615 }
616 const auto camHandles = RenderNodeSceneUtil::GetSceneCameraImageHandles(
617 *renderNodeContextMgr_, stores_.dataStoreNameScene, currentScene_.camera.name, currentScene_.camera);
618 currentScene_.cameraEnvRadianceHandle = camHandles.radianceCubemap;
619
620 if (!currentScene_.camera.prePassColorTargetName.empty()) {
621 currentScene_.prePassColorTarget =
622 renderNodeContextMgr_->GetGpuResourceManager().GetImageHandle(currentScene_.camera.prePassColorTargetName);
623 }
624
625 // renderpass needs to be valid (created in init)
626 if (hasCustomCamera) {
627 // uses camera based loadOp clear override if given
628 RenderNodeSceneUtil::UpdateRenderPassFromCustomCamera(currentScene_.camera, isNamedCamera, renderPass_);
629 } else {
630 RenderNodeSceneUtil::UpdateRenderPassFromCamera(currentScene_.camera, renderPass_);
631 }
632 currentScene_.viewportDesc = RenderNodeSceneUtil::CreateViewportFromCamera(currentScene_.camera);
633 currentScene_.scissorDesc = RenderNodeSceneUtil::CreateScissorFromCamera(currentScene_.camera);
634
635 const IRenderDataStoreDefaultLight::LightCounts lightCounts = dataStoreLight.GetLightCounts();
636 currentScene_.hasShadow = (lightCounts.shadowCount > 0) ? true : false;
637 currentScene_.cameraIdx = cameraIdx;
638 currentScene_.shadowTypes = dataStoreLight.GetShadowTypes();
639 currentScene_.lightingFlags = dataStoreLight.GetLightingFlags();
640 currentScene_.cameraShaderFlags = currentScene_.camera.shaderFlags;
641 // remove fog explicitly if render node graph input and/or default render slot usage states so
642 if (jsonInputs_.nodeFlags & RenderSceneFlagBits::RENDER_SCENE_DISABLE_FOG_BIT) {
643 currentScene_.cameraShaderFlags &= (~RenderCamera::ShaderFlagBits::CAMERA_SHADER_FOG_BIT);
644 }
645 // add multi-view flags if needed
646 if (renderPass_.subpassDesc.viewMask > 1U) {
647 ResetRenderSlotData(jsonInputs_.shaderRenderSlotMultiviewId, true);
648 } else {
649 ResetRenderSlotData(jsonInputs_.shaderRenderSlotBaseId, false);
650 }
651 }
652
CreateDefaultShaderData()653 void RenderNodeDefaultMaterialRenderSlot::CreateDefaultShaderData()
654 {
655 allShaderData_ = {};
656
657 const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
658 allShaderData_.defaultPlHandle =
659 shaderMgr.GetPipelineLayoutHandle(DefaultMaterialShaderConstants::PIPELINE_LAYOUT_FORWARD);
660 allShaderData_.defaultPipelineLayout = shaderMgr.GetPipelineLayout(allShaderData_.defaultPlHandle);
661 allShaderData_.defaultVidHandle =
662 shaderMgr.GetVertexInputDeclarationHandle(DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD);
663
664 {
665 // get the default material shader and default shader state
666 const IShaderManager::RenderSlotData shaderRsd = shaderMgr.GetRenderSlotData(jsonInputs_.shaderRenderSlotId);
667 allShaderData_.defaultShaderHandle = shaderRsd.shader.GetHandle();
668 allShaderData_.defaultStateHandle = shaderRsd.graphicsState.GetHandle();
669 if (shaderMgr.IsShader(allShaderData_.defaultShaderHandle)) {
670 allShaderData_.slotHasShaders = true;
671 const ShaderSpecializationConstantView& sscv =
672 shaderMgr.GetReflectionSpecialization(allShaderData_.defaultShaderHandle);
673 allShaderData_.defaultSpecilizationConstants.resize(sscv.constants.size());
674 for (uint32_t idx = 0; idx < (uint32_t)allShaderData_.defaultSpecilizationConstants.size(); ++idx) {
675 allShaderData_.defaultSpecilizationConstants[idx] = sscv.constants[idx];
676 }
677 specializationData_.maxSpecializationCount =
678 Math::min(static_cast<uint32_t>(allShaderData_.defaultSpecilizationConstants.size()),
679 SpecializationData::MAX_FLAG_COUNT);
680 } else {
681 CORE_LOG_I("RenderNode: %s, no default shaders for render slot id %u",
682 renderNodeContextMgr_->GetName().data(), jsonInputs_.shaderRenderSlotId);
683 }
684 if (jsonInputs_.shaderRenderSlotId != jsonInputs_.stateRenderSlotId) {
685 const IShaderManager::RenderSlotData stateRsd = shaderMgr.GetRenderSlotData(jsonInputs_.stateRenderSlotId);
686 if (stateRsd.graphicsState) {
687 allShaderData_.defaultStateHandle = stateRsd.graphicsState.GetHandle();
688 } else {
689 CORE_LOG_I("RenderNode: %s, no default state for render slot id %u",
690 renderNodeContextMgr_->GetName().data(), jsonInputs_.stateRenderSlotId);
691 }
692 }
693 }
694 }
695
GetSceneUniformBuffers(const string_view us)696 void RenderNodeDefaultMaterialRenderSlot::GetSceneUniformBuffers(const string_view us)
697 {
698 sceneBuffers_ = RenderNodeSceneUtil::GetSceneBufferHandles(*renderNodeContextMgr_, stores_.dataStoreNameScene);
699
700 string camName;
701 if (jsonInputs_.customCameraId != INVALID_CAM_ID) {
702 camName = to_string(jsonInputs_.customCameraId);
703 } else if (!(jsonInputs_.customCameraName.empty())) {
704 camName = jsonInputs_.customCameraName;
705 }
706 cameraBuffers_ =
707 RenderNodeSceneUtil::GetSceneCameraBufferHandles(*renderNodeContextMgr_, stores_.dataStoreNameScene, camName);
708 }
709
CreateNewPso(const ShaderStateData & ssd,const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMaterialFlags,const RenderSubmeshFlags submeshFlags,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags cameraShaderFlags)710 RenderNodeDefaultMaterialRenderSlot::PsoAndInfo RenderNodeDefaultMaterialRenderSlot::CreateNewPso(
711 const ShaderStateData& ssd, const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMaterialFlags,
712 const RenderSubmeshFlags submeshFlags, const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,
713 const RenderCamera::ShaderFlags cameraShaderFlags)
714 {
715 const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
716 // NOTE: The easiest route would be to input shader and graphics state to material component
717 RenderHandle currShader;
718 RenderHandle currPl;
719 RenderHandle currVid;
720 RenderHandle currState;
721 // first try to find matching shader
722 if (RenderHandleUtil::GetHandleType(ssd.shader) == RenderHandleType::SHADER_STATE_OBJECT) {
723 // we force the given shader if explicit shader render slot is not given
724 if (!jsonInputs_.explicitShader) {
725 currShader = ssd.shader;
726 }
727 const RenderHandle slotShader = shaderMgr.GetShaderHandle(ssd.shader, jsonInputs_.shaderRenderSlotId);
728 if (RenderHandleUtil::IsValid(slotShader)) {
729 currShader = slotShader; // override with render slot variant
730 }
731 // if not explicit gfx state given, check if shader has graphics state for this slot
732 if (!RenderHandleUtil::IsValid(ssd.gfxState)) {
733 const auto gfxStateHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(currShader);
734 if (shaderMgr.GetRenderSlotId(gfxStateHandle) == jsonInputs_.stateRenderSlotId) {
735 currState = gfxStateHandle;
736 }
737 }
738 currVid = shaderMgr.GetVertexInputDeclarationHandleByShaderHandle(currShader);
739 currPl = shaderMgr.GetPipelineLayoutHandleByShaderHandle(currShader);
740 }
741 if (RenderHandleUtil::GetHandleType(ssd.gfxState) == RenderHandleType::GRAPHICS_STATE) {
742 const RenderHandle slotState = shaderMgr.GetGraphicsStateHandle(ssd.gfxState, jsonInputs_.stateRenderSlotId);
743 if (RenderHandleUtil::IsValid(slotState)) {
744 currState = slotState;
745 }
746 }
747
748 // NOTE: the pipeline layout compatibility should be checked
749
750 // fallback to defaults if needed
751 currShader = RenderHandleUtil::IsValid(currShader) ? currShader : allShaderData_.defaultShaderHandle;
752 currPl = RenderHandleUtil::IsValid(currPl) ? currPl : allShaderData_.defaultPlHandle;
753 currVid = RenderHandleUtil::IsValid(currVid) ? currVid : allShaderData_.defaultVidHandle;
754 currState = RenderHandleUtil::IsValid(currState) ? currState : allShaderData_.defaultStateHandle;
755
756 auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
757 RenderHandle psoHandle;
758 if (IsInverseWinding(submeshFlags, jsonInputs_.nodeFlags, currentScene_.camera.flags)) {
759 // we create a new graphics state with inverse winding
760 GraphicsState gfxState = shaderMgr.GetGraphicsState(currState);
761 gfxState.rasterizationState.frontFace = FrontFace::CORE_FRONT_FACE_CLOCKWISE;
762 const auto spec =
763 GetShaderSpecializationView(gfxState, submeshMaterialFlags, submeshFlags, lightingFlags, cameraShaderFlags);
764 psoHandle = psoMgr.GetGraphicsPsoHandle(currShader, gfxState, shaderMgr.GetPipelineLayout(currPl),
765 shaderMgr.GetVertexInputDeclarationView(currVid), spec, GetDynamicStates());
766 } else {
767 const GraphicsState& gfxState = shaderMgr.GetGraphicsState(currState);
768 const auto spec =
769 GetShaderSpecializationView(gfxState, submeshMaterialFlags, submeshFlags, lightingFlags, cameraShaderFlags);
770 psoHandle = psoMgr.GetGraphicsPsoHandle(currShader, currState, currPl, currVid, spec, GetDynamicStates());
771 }
772 const bool needsCustomSet =
773 shaderMgr.GetPipelineLayout(currPl).descriptorSetCount == CUSTOM_SET_DESCRIPTOR_SET_COUNT;
774
775 allShaderData_.perShaderData.push_back(PerShaderData { currShader, psoHandle, currState, needsCustomSet });
776 allShaderData_.shaderIdToData[ssd.hash] = (uint32_t)allShaderData_.perShaderData.size() - 1;
777 return { psoHandle, needsCustomSet };
778 }
779
GetShaderSpecializationView(const RENDER_NS::GraphicsState & gfxState,const RenderDataDefaultMaterial::SubmeshMaterialFlags & submeshMaterialFlags,const RenderSubmeshFlags submeshFlags,const IRenderDataStoreDefaultLight::LightingFlags lightingFlags,const RenderCamera::ShaderFlags cameraShaderFlags)780 ShaderSpecializationConstantDataView RenderNodeDefaultMaterialRenderSlot::GetShaderSpecializationView(
781 const RENDER_NS::GraphicsState& gfxState,
782 const RenderDataDefaultMaterial::SubmeshMaterialFlags& submeshMaterialFlags, const RenderSubmeshFlags submeshFlags,
783 const IRenderDataStoreDefaultLight::LightingFlags lightingFlags, const RenderCamera::ShaderFlags cameraShaderFlags)
784 {
785 RenderMaterialFlags combinedMaterialFlags = submeshMaterialFlags.renderMaterialFlags;
786 if (gfxState.colorBlendState.colorAttachmentCount > 0) {
787 // enable opaque flag if blending is not enabled with the first color attachment
788 combinedMaterialFlags |= (gfxState.colorBlendState.colorAttachments[0].enableBlend)
789 ? 0u
790 : RenderMaterialFlagBits::RENDER_MATERIAL_OPAQUE_BIT;
791 }
792 for (uint32_t idx = 0; idx < specializationData_.maxSpecializationCount; ++idx) {
793 const auto& ref = allShaderData_.defaultSpecilizationConstants[idx];
794 const uint32_t constantId = ref.offset / sizeof(uint32_t);
795
796 // NOTE: vertex and fragment have different specializations for the zero index
797 if (ref.shaderStage == ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT) {
798 if (ref.id == 0u) {
799 specializationData_.flags[constantId] = submeshFlags;
800 } else if (ref.id == 1u) {
801 specializationData_.flags[constantId] = combinedMaterialFlags;
802 }
803 } else if (ref.shaderStage == ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT) {
804 if (ref.id == 0u) {
805 specializationData_.flags[constantId] = static_cast<uint32_t>(submeshMaterialFlags.materialType);
806 } else if (ref.id == 1u) {
807 specializationData_.flags[constantId] = combinedMaterialFlags;
808 } else if (ref.id == 2u) {
809 specializationData_.flags[constantId] = lightingFlags;
810 } else if (ref.id == 3u) {
811 specializationData_.flags[constantId] = currentRenderPPConfiguration_.flags.x;
812 } else if (ref.id == 4u) {
813 specializationData_.flags[constantId] = cameraShaderFlags;
814 }
815 }
816 }
817
818 return { { allShaderData_.defaultSpecilizationConstants.data(), specializationData_.maxSpecializationCount },
819 { specializationData_.flags, specializationData_.maxSpecializationCount } };
820 }
821
ProcessBuffersAndDescriptors(const ObjectCounts & objectCounts)822 void RenderNodeDefaultMaterialRenderSlot::ProcessBuffersAndDescriptors(const ObjectCounts& objectCounts)
823 {
824 constexpr uint32_t overEstimate { 16u };
825 bool updateDescriptorSets = false;
826 if (objectCounts_.maxSlotMeshCount < objectCounts.maxSlotMeshCount) {
827 updateDescriptorSets = true;
828 objectCounts_.maxSlotMeshCount = objectCounts.maxSlotMeshCount + (objectCounts.maxSlotMeshCount / overEstimate);
829 }
830 if (objectCounts_.maxSlotSkinCount < objectCounts.maxSlotSkinCount) {
831 updateDescriptorSets = true;
832 objectCounts_.maxSlotSkinCount = objectCounts.maxSlotSkinCount + (objectCounts.maxSlotSkinCount / overEstimate);
833 }
834 if (objectCounts_.maxSlotSubmeshCount < objectCounts.maxSlotSubmeshCount) {
835 updateDescriptorSets = true;
836 objectCounts_.maxSlotSubmeshCount =
837 objectCounts.maxSlotSubmeshCount + (objectCounts.maxSlotSubmeshCount / overEstimate);
838 }
839
840 if (updateDescriptorSets) {
841 ResetAndUpdateDescriptorSets();
842 }
843 }
844
ResetAndUpdateDescriptorSets()845 void RenderNodeDefaultMaterialRenderSlot::ResetAndUpdateDescriptorSets()
846 {
847 INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
848 // known and calculated (could run through descriptorsets and calculate automatically as well)
849 const DescriptorCounts dc { {
850 // camera + general data + post process + 3 light buffers + (mat + mat user data) * objectCount
851 { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 6u },
852 // light cluster
853 { CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u },
854 // mesh and material data
855 { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 5u },
856 // set0 (4) + per submesh material images
857 { CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
858 4u + objectCounts_.maxSlotSubmeshCount * RenderDataDefaultMaterial::MATERIAL_TEXTURE_COUNT },
859 } };
860 descriptorSetMgr.ResetAndReserve(dc);
861
862 for (uint32_t setIdx = 0; setIdx < AllDescriptorSets::SINGLE_SET_COUNT; ++setIdx) {
863 const RenderHandle descriptorSetHandle =
864 descriptorSetMgr.CreateDescriptorSet(setIdx, allShaderData_.defaultPipelineLayout);
865 allDescriptorSets_.set01[setIdx] = descriptorSetMgr.CreateDescriptorSetBinder(
866 descriptorSetHandle, allShaderData_.defaultPipelineLayout.descriptorSetLayouts[setIdx].bindings);
867 }
868 {
869 const uint32_t set = 2u;
870 allDescriptorSets_.sets2.clear();
871 allDescriptorSets_.sets2.resize(objectCounts_.maxSlotSubmeshCount);
872 for (uint32_t idx = 0; idx < objectCounts_.maxSlotSubmeshCount; ++idx) {
873 const RenderHandle descriptorSetHandle =
874 descriptorSetMgr.CreateDescriptorSet(set, allShaderData_.defaultPipelineLayout);
875 allDescriptorSets_.sets2[idx] = descriptorSetMgr.CreateDescriptorSetBinder(
876 descriptorSetHandle, allShaderData_.defaultPipelineLayout.descriptorSetLayouts[set].bindings);
877 }
878 }
879 }
880
ProcessSlotSubmeshes(const IRenderDataStoreDefaultCamera & dataStoreCamera,const IRenderDataStoreDefaultMaterial & dataStoreMaterial)881 void RenderNodeDefaultMaterialRenderSlot::ProcessSlotSubmeshes(
882 const IRenderDataStoreDefaultCamera& dataStoreCamera, const IRenderDataStoreDefaultMaterial& dataStoreMaterial)
883 {
884 // currentScene has been updated prior, has the correct camera (scene camera or custom camera)
885 const IRenderNodeSceneUtil::RenderSlotInfo rsi { jsonInputs_.renderSlotId, jsonInputs_.sortType,
886 jsonInputs_.cullType, jsonInputs_.nodeMaterialDiscardFlags };
887 RenderNodeSceneUtil::GetRenderSlotSubmeshes(
888 dataStoreCamera, dataStoreMaterial, currentScene_.cameraIdx, rsi, sortedSlotSubmeshes_);
889 }
890
GetDynamicStates() const891 array_view<const DynamicStateEnum> RenderNodeDefaultMaterialRenderSlot::GetDynamicStates() const
892 {
893 if (fsrEnabled_) {
894 return { DYNAMIC_STATES_FSR, countof(DYNAMIC_STATES_FSR) };
895 } else {
896 return { DYNAMIC_STATES, countof(DYNAMIC_STATES) };
897 }
898 }
899
ParseRenderNodeInputs()900 void RenderNodeDefaultMaterialRenderSlot::ParseRenderNodeInputs()
901 {
902 const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
903 const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
904 jsonInputs_.renderPass = parserUtil.GetInputRenderPass(jsonVal, "renderPass");
905 jsonInputs_.customCameraName = parserUtil.GetStringValue(jsonVal, "customCameraName");
906 jsonInputs_.customCameraId = parserUtil.GetUintValue(jsonVal, "customCameraId");
907 jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
908
909 jsonInputs_.sortType = parserUtil.GetRenderSlotSortType(jsonVal, "renderSlotSortType");
910 jsonInputs_.cullType = parserUtil.GetRenderSlotCullType(jsonVal, "renderSlotCullType");
911 jsonInputs_.nodeFlags = static_cast<uint32_t>(parserUtil.GetUintValue(jsonVal, "nodeFlags"));
912 if (jsonInputs_.nodeFlags == ~0u) {
913 jsonInputs_.nodeFlags = 0;
914 }
915 jsonInputs_.nodeMaterialDiscardFlags =
916 static_cast<uint32_t>(parserUtil.GetUintValue(jsonVal, "nodeMaterialDiscardFlags"));
917 if (jsonInputs_.nodeMaterialDiscardFlags == ~0u) {
918 jsonInputs_.nodeMaterialDiscardFlags = 0;
919 }
920 // automatic default material velocity named target based parsing to add velocity calculations bit
921 for (const auto& ref : jsonInputs_.renderPass.attachments) {
922 if (ref.name == DefaultMaterialRenderNodeConstants::CORE_DM_CAMERA_VELOCITY_NORMAL) {
923 jsonInputs_.nodeSubmeshExtraFlags |= RenderSubmeshFlagBits::RENDER_SUBMESH_VELOCITY_BIT;
924 }
925 }
926
927 const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
928 const string renderSlot = parserUtil.GetStringValue(jsonVal, "renderSlot");
929 jsonInputs_.renderSlotId = shaderMgr.GetRenderSlotId(renderSlot);
930 jsonInputs_.shaderRenderSlotId = jsonInputs_.renderSlotId;
931 jsonInputs_.stateRenderSlotId = jsonInputs_.renderSlotId;
932 const string shaderRenderSlot = parserUtil.GetStringValue(jsonVal, "shaderRenderSlot");
933 if (!shaderRenderSlot.empty()) {
934 const uint32_t renderSlotId = shaderMgr.GetRenderSlotId(shaderRenderSlot);
935 if (renderSlotId != ~0U) {
936 jsonInputs_.shaderRenderSlotId = renderSlotId;
937 jsonInputs_.initialExplicitShader = true;
938 jsonInputs_.explicitShader = true;
939 }
940 }
941 jsonInputs_.shaderRenderSlotBaseId = jsonInputs_.shaderRenderSlotId;
942 const string stateRenderSlot = parserUtil.GetStringValue(jsonVal, "stateRenderSlot");
943 if (!stateRenderSlot.empty()) {
944 const uint32_t renderSlotId = shaderMgr.GetRenderSlotId(stateRenderSlot);
945 jsonInputs_.stateRenderSlotId = (renderSlotId != ~0U) ? renderSlotId : jsonInputs_.renderSlotId;
946 }
947 const string shaderMultiviewRenderSlot = parserUtil.GetStringValue(jsonVal, "shaderMultiviewRenderSlot");
948 if (!shaderMultiviewRenderSlot.empty()) {
949 jsonInputs_.shaderRenderSlotMultiviewId = shaderMgr.GetRenderSlotId(shaderMultiviewRenderSlot);
950 }
951
952 EvaluateFogBits();
953
954 const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
955 inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
956 if ((inputRenderPass_.fragmentShadingRateAttachmentIndex < inputRenderPass_.attachments.size()) &&
957 RenderHandleUtil::IsValid(
958 inputRenderPass_.attachments[inputRenderPass_.fragmentShadingRateAttachmentIndex].handle)) {
959 fsrEnabled_ = true;
960 }
961 jsonInputs_.hasChangeableRenderPassHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.renderPass);
962 }
963
ResetRenderSlotData(const uint32_t shaderRenderSlotId,const bool multiView)964 void RenderNodeDefaultMaterialRenderSlot::ResetRenderSlotData(const uint32_t shaderRenderSlotId, const bool multiView)
965 {
966 // can be reset to multi-view usage or reset back to default usage
967 if (shaderRenderSlotId != jsonInputs_.shaderRenderSlotId) {
968 jsonInputs_.shaderRenderSlotId = shaderRenderSlotId;
969 jsonInputs_.explicitShader = jsonInputs_.initialExplicitShader || multiView;
970 // reset
971 CreateDefaultShaderData();
972 }
973 }
974
EvaluateFogBits()975 void RenderNodeDefaultMaterialRenderSlot::EvaluateFogBits()
976 {
977 // if no explicit bits set we check default render slot usages
978 if ((jsonInputs_.nodeFlags & (RENDER_SCENE_ENABLE_FOG_BIT | RENDER_SCENE_DISABLE_FOG_BIT)) == 0) {
979 // check default render slots
980 const uint32_t opaqueSlotId = renderNodeContextMgr_->GetShaderManager().GetRenderSlotId(
981 DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE);
982 const uint32_t translucentSlotId = renderNodeContextMgr_->GetShaderManager().GetRenderSlotId(
983 DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT);
984 if ((jsonInputs_.renderSlotId == opaqueSlotId) || (jsonInputs_.renderSlotId == translucentSlotId)) {
985 jsonInputs_.nodeFlags |= RenderSceneFlagBits::RENDER_SCENE_ENABLE_FOG_BIT;
986 }
987 }
988 }
989
990 // for plugin / factory interface
Create()991 RENDER_NS::IRenderNode* RenderNodeDefaultMaterialRenderSlot::Create()
992 {
993 return new RenderNodeDefaultMaterialRenderSlot();
994 }
995
Destroy(IRenderNode * instance)996 void RenderNodeDefaultMaterialRenderSlot::Destroy(IRenderNode* instance)
997 {
998 delete static_cast<RenderNodeDefaultMaterialRenderSlot*>(instance);
999 }
1000 CORE3D_END_NAMESPACE()
1001