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 #ifndef API_3D_RENDER_IRENDER_DATA_STORE_DEFAULT_MATERIAL_H
17 #define API_3D_RENDER_IRENDER_DATA_STORE_DEFAULT_MATERIAL_H
18 
19 #include <cstdint>
20 
21 #include <3d/ecs/components/material_component.h>
22 #include <3d/render/render_data_defines_3d.h>
23 #include <base/containers/array_view.h>
24 #include <base/math/matrix.h>
25 #include <base/math/vector.h>
26 #include <core/namespace.h>
27 #include <render/datastore/intf_render_data_store.h>
28 #include <render/device/intf_shader_manager.h>
29 #include <render/resource_handle.h>
30 
31 CORE3D_BEGIN_NAMESPACE()
32 /** @ingroup group_render_irenderdatastoredefaultmaterial */
33 /** RenderDataDefaultMaterial.
34  */
35 struct RenderDataDefaultMaterial {
36     /** min supported roughness value. clamped to this - 1.0.
37     Avoids division with zero in shader BRDF calculations and prevents "zero" size speculars. */
38     static constexpr float MIN_ROUGHNESS { 0.089f };
39     /** max supported skin matrix count */
40     static constexpr uint32_t MAX_SKIN_MATRIX_COUNT { 128u };
41 
42     /** Count of uvec4 variables for material uniforms (must match 3d_dm_structure_common.h)
43      * Aligned for 256 bytes with indices.
44      */
45     static constexpr uint32_t MATERIAL_FACTOR_UNIFORM_VEC4_COUNT { 15u };
46     static constexpr uint32_t MATERIAL_PACKED_UNIFORM_UVEC4_COUNT { 15u };
47 
48     /** Count of uvec4 variables for material uniforms (must match 3d_dm_structure_common.h) */
49     static constexpr uint32_t MATERIAL_TEXTURE_COUNT { 11u };
50 
51     /** max default material custom resources */
52     static constexpr uint32_t MAX_MATERIAL_CUSTOM_RESOURCE_COUNT { 4u };
53 
54     /** max default material custom resources */
55     static constexpr uint32_t MAX_MESH_USER_VEC4_COUNT { 8u };
56 
57     /** max default material custom resources */
58     static constexpr uint32_t MAX_MATERIAL_CUSTOM_PROPERTY_BYTE_SIZE { 256u };
59 
60     /** Input material uniforms
61      * There's no conversion happening to these, so pre-multiplications etc needs to happen prior
62      */
63     struct InputMaterialUniforms {
64         struct TextureData {
65             BASE_NS::Math::Vec4 factor { 0.0f, 0.0f, 0.0f, 0.0f };
66             BASE_NS::Math::Vec2 translation { 0.0f, 0.0f };
67             float rotation { 0.0f };
68             BASE_NS::Math::Vec2 scale { 1.0f, 1.0f };
69         };
70         TextureData textureData[MATERIAL_TEXTURE_COUNT];
71         // separate values which is pushed to shader
72         // alpha cutoff
73         float alphaCutoff { 0.5f };
74         // texcoord set bits, selection for uv0 or uv1
75         uint32_t texCoordSetBits { 0u };
76         // texcoord transform set bits
77         uint32_t texTransformSetBits { 0u };
78         /** material id */
79         uint64_t id { 0 };
80     };
81 
82     /** Material uniforms (NOTE: rotScaleTrans could be packed more)
83      */
84     struct MaterialUniforms {
85         // Factors as half4
86         // 0: baseColor
87         // 1: normal
88         // 2: material
89         // 3: emissive
90         // 4: ao
91         // 5: clearcoat
92         // 6: clearcoat roughness
93         // 7: clearcoat normal
94         // 8: sheen
95         // 9: transmission
96         // 10: specular
97         // 11: alpha cutoff
98 
99         BASE_NS::Math::Vec4 factors[MATERIAL_FACTOR_UNIFORM_VEC4_COUNT];
100 
101         // unpacked, .xy material id,
102         BASE_NS::Math::UVec4 indices { 0u, 0u, 0u, 0u };
103     };
104 
105     struct MaterialPackedUniforms {
106         // Texture transforms as half4 ({2x2 mat}, {2d offset, unused})
107         // 0: rotScaleTrans baseColor
108         // 1: rotScaleTrans normal
109         // 2: rotScaleTrans material
110         // 3: rotScaleTrans emissive
111         // 4: rotScaleTrans ao
112         // 5: rotScaleTrans clearcoat
113         // 6: rotScaleTrans clearcoat roughness
114         // 7: rotScaleTrans clearcoat normal
115         // 8: rotScaleTrans sheen
116         // 9: rotScaleTrans transmission
117         // 10: rotScaleTrans specular
118 
119         //
120         // 12: alphaCutoff, unused, useTexcoord | hasTransform
121         BASE_NS::Math::UVec4 packed[MATERIAL_PACKED_UNIFORM_UVEC4_COUNT];
122 
123         // unpacked, .xy material id,
124         BASE_NS::Math::UVec4 indices { 0u, 0u, 0u, 0u };
125     };
126 
127     /*
128      * Combined uniforms for factors and packed transforms
129      **/
130     struct AllMaterialUniforms {
131         /** Material factor uniforms */
132         MaterialUniforms factors;
133         /** Material packed transforms */
134         MaterialPackedUniforms transforms;
135     };
136 
137     /** Material handles
138      */
139     struct MaterialHandles {
140         /** Source images for different texture types */
141         RENDER_NS::RenderHandleReference images[MATERIAL_TEXTURE_COUNT];
142         /** Samplers for different texture types */
143         RENDER_NS::RenderHandleReference samplers[MATERIAL_TEXTURE_COUNT];
144     };
145 
146     /** Material shader
147      */
148     struct MaterialShader {
149         /** Shader to be used. (If invalid, a default is chosen by the default material renderer) */
150         RENDER_NS::RenderHandleReference shader;
151         /** Shader graphics state to be used. (If invalid, a default is chosen by the default material renderer) */
152         RENDER_NS::RenderHandleReference graphicsState;
153     };
154 
155     /** Material data
156      */
157     struct MaterialData {
158         /** Render material type */
159         RenderMaterialType materialType { RenderMaterialType::METALLIC_ROUGHNESS };
160         /** Render extra rendering flags */
161         RenderExtraRenderingFlags extraMaterialRenderingFlags { 0u };
162         /** Render material flags */
163         RenderMaterialFlags renderMaterialFlags { 0u };
164 
165         /** Custom render slot id */
166         uint32_t customRenderSlotId { ~0u };
167         /** Material shader */
168         MaterialShader materialShader;
169         /** Depth shader */
170         MaterialShader depthShader;
171     };
172 
173     /** Submesh material flags
174      */
175     struct SubmeshMaterialFlags {
176         /** Material type */
177         RenderMaterialType materialType { RenderMaterialType::METALLIC_ROUGHNESS };
178         /* Render submesh's submesh flags, dublicated here for convenience */
179         RenderSubmeshFlags submeshFlags { 0u };
180         /** Extra material rendering flags */
181         RenderExtraRenderingFlags extraMaterialRenderingFlags { 0u };
182 
183         /** Render material flags */
184         RenderMaterialFlags renderMaterialFlags { 0u };
185 
186         /** 32 bit hash based on the variables above */
187         uint32_t renderHash { 0u };
188     };
189 
190     struct SlotMaterialData {
191         /** Combined sort layer from render submesh */
192         uint16_t combinedRenderSortLayer { 0u };
193         /** Combined of render materials flags hash, material idx, shader id */
194         uint32_t renderSortHash { 0u };
195         /** Render material flags */
196         RenderMaterialFlags renderMaterialFlags { 0u };
197         /** Custom shader handle or invalid handle */
198         RENDER_NS::RenderHandleReference shader;
199         /** Custom graphics state handle or invalid handle */
200         RENDER_NS::RenderHandleReference gfxState;
201     };
202 
203     /** Object counts for rendering.
204      */
205     struct ObjectCounts {
206         /** Mesh count, NOTE: is currently global */
207         uint32_t meshCount { 0u };
208         /** Submesh count */
209         uint32_t submeshCount { 0u };
210         /** Skin count */
211         uint32_t skinCount { 0u };
212         /** Material count */
213         uint32_t materialCount { 0u };
214     };
215 
216     /** Per mesh skin joint matrices.
217      */
218     struct JointMatrixData {
219         /** Matrices */
220         BASE_NS::Math::Mat4X4* data { nullptr };
221         /** Matrix count */
222         uint32_t count { 0 };
223     };
224 
225     /** Material custom resources.
226      */
227     struct CustomResourceData {
228         /** invalid handle if custom material shader not given.
229          * With default material build-in render nodes must have compatible pipeline layout.
230          * With custom render slots and custom render nodes can be anything.
231          */
232         RENDER_NS::RenderHandleReference shaderHandle;
233 
234         /** handle count */
235         uint32_t resourceHandleCount { 0u };
236         /** invalid handles if not given */
237         RENDER_NS::RenderHandleReference resourceHandles[MAX_MATERIAL_CUSTOM_RESOURCE_COUNT];
238     };
239 
240     /** Material slot types. Where
241      */
242     enum class MaterialSlotType : uint32_t {
243         /** Basic opaque slot */
244         SLOT_TYPE_OPAQUE = 0,
245         /** Basic translucent slot */
246         SLOT_TYPE_TRANSLUCENT = 1,
247         /** Basic depth slot for shadows and depth pre-pass */
248         SLOT_TYPE_DEPTH = 2,
249     };
250 
251     /** Material indices.
252      */
253     struct MaterialIndices {
254         /** Material index */
255         uint32_t materialIndex { ~0u };
256         /** Material custom resource index */
257         uint32_t materialCustomResourceIndex { ~0u };
258     };
259 };
260 
261 /** @ingroup group_render_irenderdatastoredefaultmaterial */
262 /** RenderDataStoreDefaultMaterial interface.
263  * Not internally syncronized.
264  */
265 class IRenderDataStoreDefaultMaterial : public RENDER_NS::IRenderDataStore {
266 public:
267     static constexpr BASE_NS::Uid UID { "fdd9f86b-f5fc-45da-8832-41cbd649ed49" };
268 
269     ~IRenderDataStoreDefaultMaterial() override = default;
270 
271     /** Add mesh data.
272      * @param meshData All mesh data.
273      * @return Mesh index for submesh to use.
274      */
275     virtual uint32_t AddMeshData(const RenderMeshData& meshData) = 0;
276 
277     /** Add material and get material index.
278      * @param materialUniforms input uniform data.
279      * @param materialHandles raw GPU resource handles.
280      * @param materialData Material data.
281      * @param customPropertyData Custom property data per material.
282      * @return Material index for submesh to use.
283      */
284     virtual uint32_t AddMaterialData(const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
285         const RenderDataDefaultMaterial::MaterialHandles& materialHandles,
286         const RenderDataDefaultMaterial::MaterialData& materialData,
287         const BASE_NS::array_view<const uint8_t> customPropertyData) = 0;
288 
289     /** Add material and get material index.
290      * Automatic hashing with id. (E.g. material entity id)
291      * Final rendering material flags are per submesh (RenderDataDefaultMaterial::SubmeshMaterialFlags)
292      * @param id Material component id. In typical ECS usage material entity id.
293      * @param materialUniforms input material uniforms.
294      * @param materialHandles raw GPU resource handles.
295      * @param materialData Material data.
296      * @param customPropertyData Custom property data per material.
297      * @return Material index for submesh to use.
298      */
299     virtual uint32_t AddMaterialData(const uint64_t id,
300         const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
301         const RenderDataDefaultMaterial::MaterialHandles& materialHandles,
302         const RenderDataDefaultMaterial::MaterialData& materialData,
303         const BASE_NS::array_view<const uint8_t> customPropertyData) = 0;
304 
305     /** Reserve space for instanceCount materials.
306      * @param id Material component id. In typical ECS usage material entity id.
307      * @param instanceCount How many submesh instances will be will be draw.
308      * @return Material index for the first submesh instance.
309      */
310     virtual uint32_t AllocateMaterials(uint64_t id, uint32_t instanceCount) = 0;
311 
312     /** Add material with preallocated index.
313      * @param materialIndex Index to first submesh material (from AllocateMaterials).
314      * @param materialInstanceIndex Offset to submesh instance's material.
315      * @param materialInstanceCount How many times is the material data duplicated.
316      * @param materialUniforms input material uniforms.
317      * @param materialHandles raw GPU resource handles.
318      * @param materialData Material data.
319      * @param customPropertyData Custom property data per material.
320      */
321     virtual void AddInstanceMaterialData(uint32_t materialIndex, uint32_t materialInstanceIndex,
322         uint32_t materialInstanceCount, const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
323         const RenderDataDefaultMaterial::MaterialHandles& materialHandles,
324         const RenderDataDefaultMaterial::MaterialData& materialData,
325         const BASE_NS::array_view<const uint8_t> customPropertyData) = 0;
326 
327     /** Add material with preallocated index. Material handles and material data is not passed as inputs.
328      * Use for inputting material GPU instances (the shader data and material GPU image handles cannot change)
329      * @param materialIndex Index to first submesh material (from AllocateMaterials).
330      * @param materialInstanceIndex Offset to submesh instance's material.
331      * @param materialInstanceCount How many times is the material data duplicated.
332      * @param materialUniforms input material uniforms.
333      * @param customPropertyData Custom property data per material.
334      */
335     virtual void AddInstanceMaterialData(uint32_t materialIndex, uint32_t materialInstanceIndex,
336         uint32_t materialInstanceCount, const RenderDataDefaultMaterial::InputMaterialUniforms& materialUniforms,
337         const BASE_NS::array_view<const uint8_t> customPropertyData) = 0;
338 
339     /** Get material index if already created with the same id.
340      * It's beneficial to use unique materials and use as few of them as possible (there will be copying and such).
341      * @param id Material component id. In typical ECS usage material entity id.
342      * @return Material index for submesh to use. (if no material created with the id
343      * RenderSceneDataConstants::INVALID_INDEX is returned)
344      */
345     virtual uint32_t GetMaterialIndex(const uint64_t id) const = 0;
346 
347     /** Get material custom resource index if already created for the same material.
348      * @param id Material component id. In typical ECS usage material entity id.
349      * @return Material custom resource index for submesh to use. (if no material custorm resource created with the id
350      * RenderSceneDataConstants::INVALID_INDEX is returned)
351      */
352     virtual uint32_t GetMaterialCustomResourceIndex(const uint64_t id) const = 0;
353 
354     /** Get material indices.
355      * @param id Material component id. In typical ECS usage material entity id.
356      * @return Material indices.
357      */
358     virtual RenderDataDefaultMaterial::MaterialIndices GetMaterialIndices(const uint64_t id) const = 0;
359 
360     /** Get material indices.
361      * @param id Material component id. In typical ECS usage material entity id.
362      * @paran instanceCount Expected instance count for the material id.
363      * @return Material indices.
364      */
365     virtual RenderDataDefaultMaterial::MaterialIndices GetMaterialIndices(
366         uint64_t id, uint32_t instanceCount) const = 0;
367 
368     /** Add skin joint matrices and get an index for render submesh.
369      * If skinJointMatrices.size() != previousSkinJointMatrices.size()
370      * The skinJointMatrices are copied to previous frame buffer.
371      * @param skinJointMatrices All skin joint matrices.
372      * @param prevSkinJointMatrices All skin joint matrices for previous frame.
373      * @return Skin joint matrices index for submesh to use. (if no skin joints are given
374      * RenderSceneDataConstants::INVALID_INDEX is returned)
375      */
376     virtual uint32_t AddSkinJointMatrices(const BASE_NS::array_view<const BASE_NS::Math::Mat4X4> skinJointMatrices,
377         const BASE_NS::array_view<const BASE_NS::Math::Mat4X4> prevSkinJointMatrices) = 0;
378 
379     /** Add custom material resources. (Extra resources on top of default material resources)
380      * With built-in default material render nodes, the resources are mapped to user
381      * defined custom pipeline layout to the single descriptor set which is after default material descriptor sets.
382      * The pipeline layout must be compatible.
383      * Invalid GPU resource handles are ignored.
384      * Automatic hashing with id. (E.g. material entity id)
385      * @param bindings Valid GPU resource handles. (<= MAX_MATERIAL_CUSTOM_RESOURCE_COUNT)
386      * @param id Material component id. In typical ECS usage material entity id.
387      * @return Index for custom material resources. (if no bindings are given
388      * RenderSceneDataConstants::INVALID_INDEX is returned)
389      */
390     virtual uint32_t AddMaterialCustomResources(
391         const uint64_t id, const BASE_NS::array_view<const RENDER_NS::RenderHandleReference> bindings) = 0;
392 
393     /** Add submeshes safely with default material to rendering. Render slots are evaluated automatically.
394      * @param submesh Submesh.
395      */
396     virtual void AddSubmesh(const RenderSubmesh& submesh) = 0;
397 
398     /** Add submeshes safely with default material to rendering.
399      * @param submesh Submesh.
400      * @param renderSlotAndShaders All the render slots where the submesh is handled.
401      */
402     virtual void AddSubmesh(const RenderSubmesh& submesh,
403         const BASE_NS::array_view<const RENDER_NS::IShaderManager::RenderSlotData> renderSlotAndShaders) = 0;
404 
405     /** Set render slots for material types.
406      * @param materialSlotType Material slot type.
407      * @param renderSlotIds All render slot ids.
408      */
409     virtual void SetRenderSlots(const RenderDataDefaultMaterial::MaterialSlotType materialSlotType,
410         const BASE_NS::array_view<const uint32_t> renderSlotIds) = 0;
411 
412     /** Get render slot mask for material type.
413      * @param materialSlotType Material slot type.
414      * @return Mask of render slot ids.
415      */
416     virtual uint64_t GetRenderSlotMask(const RenderDataDefaultMaterial::MaterialSlotType materialSlotType) const = 0;
417 
418     /** Get all object count which were send to rendering
419      * @return ObjectCounts
420      */
421     virtual RenderDataDefaultMaterial::ObjectCounts GetObjectCounts() const = 0;
422 
423     /** Get list of mesh data
424      */
425     virtual BASE_NS::array_view<const RenderMeshData> GetMeshData() const = 0;
426 
427     /** Get list of mesh skin joint matrices
428      */
429     virtual BASE_NS::array_view<const RenderDataDefaultMaterial::JointMatrixData> GetMeshJointMatrices() const = 0;
430 
431     /** Get slot submesh indices
432      * @param renderSlotId Index
433      */
434     virtual BASE_NS::array_view<const uint32_t> GetSlotSubmeshIndices(const uint32_t renderSlotId) const = 0;
435 
436     /** Get slot submesh shader handles
437      * @param renderSlotId Index
438      */
439     virtual BASE_NS::array_view<const RenderDataDefaultMaterial::SlotMaterialData> GetSlotSubmeshMaterialData(
440         const uint32_t renderSlotId) const = 0;
441 
442     /** Get object counts per render slot
443      * @param renderSlotId Index
444      */
445     virtual RenderDataDefaultMaterial::ObjectCounts GetSlotObjectCounts(const uint32_t renderSlotId) const = 0;
446 
447     /** Get list of render submeshes
448      */
449     virtual BASE_NS::array_view<const RenderSubmesh> GetSubmeshes() const = 0;
450 
451     /** Get submesh joint matrix data
452      * @param skinJointIndex Skin joint index from RenderSubmesh got from AddSkinJointMatrices().
453      */
454     virtual BASE_NS::array_view<const BASE_NS::Math::Mat4X4> GetSubmeshJointMatrixData(
455         const uint32_t skinJointIndex) const = 0;
456 
457     /** Get material uniforms (per material) */
458     virtual BASE_NS::array_view<const RenderDataDefaultMaterial::AllMaterialUniforms> GetMaterialUniforms() const = 0;
459     /** Get material handles (per material) */
460     virtual BASE_NS::array_view<const RenderDataDefaultMaterial::MaterialHandles> GetMaterialHandles() const = 0;
461     /** Get material custom property data with material index.
462      * @param materialIndex Index of material from RenderSubmesh and an index if going through e.g. material unforms
463      */
464     virtual BASE_NS::array_view<const uint8_t> GetMaterialCustomPropertyData(const uint32_t materialIndex) const = 0;
465     /** Get submesh material flags (per submesh) */
466     virtual BASE_NS::array_view<const RenderDataDefaultMaterial::SubmeshMaterialFlags>
467     GetSubmeshMaterialFlags() const = 0;
468 
469     /** Get custom resource handles */
470     virtual BASE_NS::array_view<const RenderDataDefaultMaterial::CustomResourceData>
471     GetCustomResourceHandles() const = 0;
472 
473     /** Generate render hash (32 bits as RenderDataDefaultMaterial::SubmeshMaterialFlags::renderHash) */
474     virtual uint32_t GenerateRenderHash(const RenderDataDefaultMaterial::SubmeshMaterialFlags& flags) const = 0;
475 
476 protected:
477     IRenderDataStoreDefaultMaterial() = default;
478 };
479 CORE3D_END_NAMESPACE()
480 
481 #endif // API_3D_RENDER_IRENDER_DATA_STORE_DEFAULT_MATERIAL_H
482