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 "util/property_util.h"
17 
18 #include <PropertyTools/core_metadata.inl>
19 #include <cinttypes>
20 
21 #include <base/math/vector.h>
22 #include <core/log.h>
23 #include <core/property/intf_property_handle.h>
24 #include <core/property/property_types.h>
25 
26 #include "util/component_util_functions.h"
27 #include "util/json_util.h"
28 #include "util/string_util.h"
29 
30 CORE_BEGIN_NAMESPACE()
31 static constexpr inline bool operator==(const Property& lhs, const Property& rhs) noexcept
32 {
33     return (lhs.type == rhs.type) && (lhs.hash == rhs.hash) && (lhs.name == rhs.name);
34 }
35 CORE_END_NAMESPACE()
36 
37 CORE3D_BEGIN_NAMESPACE()
38 using namespace BASE_NS;
39 using namespace CORE_NS;
40 
41 namespace {
GetPropertyTypeByteSize(const PropertyTypeDecl & typeDecl)42 uint32_t GetPropertyTypeByteSize(const PropertyTypeDecl& typeDecl)
43 {
44     uint32_t byteSize = 0; // zero means that un-supported property type
45     switch (typeDecl) {
46         case PropertyType::UINT32_T:
47         case PropertyType::INT32_T:
48         case PropertyType::FLOAT_T:
49         case PropertyType::BOOL_T:
50             byteSize = sizeof(uint32_t);
51             break;
52         case PropertyType::UVEC2_T:
53         case PropertyType::IVEC2_T:
54         case PropertyType::VEC2_T:
55             byteSize = sizeof(Math::UVec2);
56             break;
57         case PropertyType::UVEC3_T:
58         case PropertyType::IVEC3_T:
59         case PropertyType::VEC3_T:
60             byteSize = sizeof(Math::UVec3);
61             break;
62         case PropertyType::UVEC4_T:
63         case PropertyType::IVEC4_T:
64         case PropertyType::VEC4_T:
65             byteSize = sizeof(Math::UVec4);
66             break;
67         case PropertyType::MAT3X3_T:
68             byteSize = sizeof(Math::Mat3X3);
69             break;
70         case PropertyType::MAT4X4_T:
71             byteSize = sizeof(Math::Mat4X4);
72             break;
73         default:
74             break;
75     }
76     return byteSize;
77 }
78 
GetMetaData(const PropertyTypeDecl & typeDecl)79 constexpr MetaData GetMetaData(const PropertyTypeDecl& typeDecl)
80 {
81     switch (typeDecl) {
82         case PropertyType::UINT32_T:
83             return PropertyType::MetaDataFrom<uint32_t>(nullptr);
84         case PropertyType::INT32_T:
85             return PropertyType::MetaDataFrom<int32_t>(nullptr);
86         case PropertyType::FLOAT_T:
87             return PropertyType::MetaDataFrom<float>(nullptr);
88 
89         case PropertyType::BOOL_T:
90             return PropertyType::MetaDataFrom<bool>(nullptr);
91 
92         case PropertyType::UVEC2_T:
93             return PropertyType::MetaDataFrom<Math::UVec2>(nullptr);
94         case PropertyType::IVEC2_T:
95             return PropertyType::MetaDataFrom<Math::IVec2>(nullptr);
96         case PropertyType::VEC2_T:
97             return PropertyType::MetaDataFrom<Math::Vec2>(nullptr);
98 
99         case PropertyType::UVEC3_T:
100             return PropertyType::MetaDataFrom<Math::UVec3>(nullptr);
101         case PropertyType::IVEC3_T:
102             return PropertyType::MetaDataFrom<Math::IVec3>(nullptr);
103         case PropertyType::VEC3_T:
104             return PropertyType::MetaDataFrom<Math::Vec3>(nullptr);
105 
106         case PropertyType::UVEC4_T:
107             return PropertyType::MetaDataFrom<Math::UVec4>(nullptr);
108         case PropertyType::IVEC4_T:
109             return PropertyType::MetaDataFrom<Math::IVec4>(nullptr);
110         case PropertyType::VEC4_T:
111             return PropertyType::MetaDataFrom<Math::Vec4>(nullptr);
112 
113         case PropertyType::MAT3X3_T:
114             return PropertyType::MetaDataFrom<Math::Mat3X3>(nullptr);
115         case PropertyType::MAT4X4_T:
116             return PropertyType::MetaDataFrom<Math::Mat4X4>(nullptr);
117         default:
118             break;
119     }
120     return {};
121 }
122 } // namespace
123 
CustomPropertyPodContainer(size_t reserveByteSize)124 CustomPropertyPodContainer::CustomPropertyPodContainer(size_t reserveByteSize)
125 {
126     data_.reserve(reserveByteSize);
127 }
128 
PropertyCount() const129 size_t CustomPropertyPodContainer::PropertyCount() const
130 {
131     return metaData_.size();
132 }
133 
MetaData(size_t index) const134 const Property* CustomPropertyPodContainer::MetaData(size_t index) const
135 {
136     if (index < metaData_.size()) {
137         return &metaData_[index];
138     }
139 
140     return nullptr;
141 }
142 
MetaData() const143 array_view<const Property> CustomPropertyPodContainer::MetaData() const
144 {
145     return { metaData_ };
146 }
147 
Type() const148 uint64_t CustomPropertyPodContainer::Type() const
149 {
150     return 0;
151 }
152 
Create() const153 IPropertyHandle* CustomPropertyPodContainer::Create() const
154 {
155     return nullptr;
156 }
157 
Clone(const IPropertyHandle *) const158 IPropertyHandle* CustomPropertyPodContainer::Clone(const IPropertyHandle* /* src */) const
159 {
160     return nullptr;
161 }
162 
Release(IPropertyHandle *) const163 void CustomPropertyPodContainer::Release(IPropertyHandle* /* handle */) const {}
164 
Reset()165 void CustomPropertyPodContainer::Reset()
166 {
167     metaStrings_.clear();
168     metaData_.clear();
169     data_.clear();
170 }
171 
ReservePropertyCount(size_t propertyCount)172 void CustomPropertyPodContainer::ReservePropertyCount(size_t propertyCount)
173 {
174     reservePropertyCount_ = propertyCount;
175     metaStrings_.reserve(reservePropertyCount_);
176     metaData_.reserve(reservePropertyCount_);
177 }
178 
179 // CustomProperties IPropertyHandle
Owner() const180 const IPropertyApi* CustomPropertyPodContainer::Owner() const
181 {
182     return this;
183 }
184 
Size() const185 size_t CustomPropertyPodContainer::Size() const
186 {
187     return data_.size();
188 }
189 
RLock() const190 const void* CustomPropertyPodContainer::RLock() const
191 {
192     return data_.data();
193 }
194 
RUnlock() const195 void CustomPropertyPodContainer::RUnlock() const {}
196 
WLock()197 void* CustomPropertyPodContainer::WLock()
198 {
199     return data_.data();
200 }
201 
WUnlock()202 void CustomPropertyPodContainer::WUnlock() {}
203 
204 //
205 
AddOffsetProperty(const string_view propertyName,const string_view displayName,const uintptr_t offset,const PropertyTypeDecl & typeDecl)206 void CustomPropertyPodContainer::AddOffsetProperty(const string_view propertyName, const string_view displayName,
207     const uintptr_t offset, const PropertyTypeDecl& typeDecl)
208 {
209     const size_t byteSize = GetPropertyTypeByteSize(typeDecl);
210     const bool reserved = (metaStrings_.size() < reservePropertyCount_);
211     if ((byteSize > 0) && reserved) {
212         metaStrings_.push_back({ string { propertyName }, string { displayName } });
213         const auto& strings = metaStrings_.back();
214         const Property meta {
215             strings.name,                                        // name
216             FNV1aHash(strings.name.data(), strings.name.size()), // hash
217             typeDecl,                                            // type
218             1U,                                                  // count
219             byteSize,                                            // size
220             offset,                                              // offset
221             strings.displayName,                                 // displayName
222             0U,                                                  // flags
223             GetMetaData(typeDecl),                               // metaData
224         };
225         metaData_.push_back(meta);
226         data_.resize(Math::max(data_.size(), meta.offset + meta.size));
227     } else {
228         CORE_LOG_W("unsupported property addition for custom property POD container");
229     }
230 }
231 
AddOffsetProperty(const string_view propertyName,const string_view displayName,const uintptr_t offset,const PropertyTypeDecl & typeDecl,const array_view<const uint8_t> data)232 void CustomPropertyPodContainer::AddOffsetProperty(const string_view propertyName, const string_view displayName,
233     const uintptr_t offset, const PropertyTypeDecl& typeDecl, const array_view<const uint8_t> data)
234 {
235     const size_t byteSize = GetPropertyTypeByteSize(typeDecl);
236     const bool reserved = (metaStrings_.size() < reservePropertyCount_);
237     if ((byteSize > 0) && reserved) {
238         metaStrings_.push_back({ string { propertyName }, string { displayName } });
239         const auto& strings = metaStrings_.back();
240         const Property meta {
241             strings.name,                                        // name
242             FNV1aHash(strings.name.data(), strings.name.size()), // hash
243             typeDecl,                                            // type
244             1U,                                                  // count
245             byteSize,                                            // size
246             offset,                                              // offset
247             strings.displayName,                                 // displayName
248             0U,                                                  // flags
249             GetMetaData(typeDecl),                               // metaData
250         };
251         metaData_.push_back(meta);
252         data_.resize(Math::max(data_.size(), meta.offset + meta.size));
253         if (data.size_bytes() == byteSize) {
254             CloneData(data_.data() + offset, data_.size_in_bytes() - offset, data.data(), data.size_bytes());
255         }
256     } else {
257         CORE_LOG_W("unsupported property addition for custom property POD container");
258     }
259 }
260 
SetValue(const string_view propertyName,const array_view<const uint8_t> data)261 bool CustomPropertyPodContainer::SetValue(const string_view propertyName, const array_view<const uint8_t> data)
262 {
263     for (const auto& metaRef : metaData_) {
264         if ((metaRef.name == propertyName) && (metaRef.size == data.size_bytes())) {
265             return SetValue(metaRef.offset, data);
266         }
267     }
268     return false;
269 }
270 
SetValue(const size_t byteOffset,const array_view<const uint8_t> data)271 bool CustomPropertyPodContainer::SetValue(const size_t byteOffset, const array_view<const uint8_t> data)
272 {
273     return CloneData(data_.data() + byteOffset,
274         (byteOffset < data_.size_in_bytes()) ? (data_.size_in_bytes() - byteOffset) : 0U, data.data(),
275         data.size_bytes());
276 }
277 
GetValue(const string_view propertyName) const278 array_view<const uint8_t> CustomPropertyPodContainer::GetValue(const string_view propertyName) const
279 {
280     for (const auto& metaRef : metaData_) {
281         if (metaRef.name == propertyName) {
282             const size_t endData = metaRef.offset + metaRef.size;
283             if (endData <= data_.size_in_bytes()) {
284                 return { data_.data() + metaRef.offset, metaRef.size };
285             }
286         }
287     }
288     return {};
289 }
290 
GetByteSize() const291 size_t CustomPropertyPodContainer::GetByteSize() const
292 {
293     return data_.size_in_bytes();
294 }
295 
CopyValues(const CustomPropertyPodContainer & other)296 void CustomPropertyPodContainer::CopyValues(const CustomPropertyPodContainer& other)
297 {
298     // copy values with matching type and name
299     for (const auto& otherProperty : other.MetaData()) {
300         if (auto pos = std::find(metaData_.cbegin(), metaData_.cend(), otherProperty); pos != metaData_.cend()) {
301             SetValue(pos->offset, other.GetValue(otherProperty.name));
302         }
303     }
304 }
305 
306 //
307 
GetPropertyTypeDeclaration(const string_view type)308 PropertyTypeDecl CustomPropertyPodHelper::GetPropertyTypeDeclaration(const string_view type)
309 {
310     if (type == "vec4") {
311         return PropertyType::VEC4_T;
312     } else if (type == "uvec4") {
313         return PropertyType::UVEC4_T;
314     } else if (type == "ivec4") {
315         return PropertyType::IVEC4_T;
316     } else if (type == "vec3") {
317         return PropertyType::VEC3_T;
318     } else if (type == "uvec3") {
319         return PropertyType::UVEC3_T;
320     } else if (type == "ivec3") {
321         return PropertyType::IVEC3_T;
322     } else if (type == "vec2") {
323         return PropertyType::VEC2_T;
324     } else if (type == "uvec2") {
325         return PropertyType::UVEC2_T;
326     } else if (type == "ivec2") {
327         return PropertyType::IVEC2_T;
328     } else if (type == "float") {
329         return PropertyType::FLOAT_T;
330     } else if (type == "uint") {
331         return PropertyType::UINT32_T;
332     } else if (type == "int") {
333         return PropertyType::INT32_T;
334     } else if (type == "bool") {
335         return PropertyType::BOOL_T;
336     } else if (type == "mat3x3") {
337         return PropertyType::MAT3X3_T;
338     } else if (type == "mat4x4") {
339         return PropertyType::MAT4X4_T;
340     } else {
341         CORE_LOG_W("CORE3D_VALIDATION: Invalid property type only int, uint, float, bool, and XvecX variants, and "
342                    "mat3x3 and mat4x4 are supported");
343     }
344     // NOTE: does not handle invalid types
345     return PropertyType::INVALID;
346 }
347 
GetPropertyTypeAlignment(const PropertyTypeDecl & propertyType)348 size_t CustomPropertyPodHelper::GetPropertyTypeAlignment(const PropertyTypeDecl& propertyType)
349 {
350     size_t align = 1U;
351     static_assert(sizeof(float) == sizeof(uint32_t) && sizeof(float) == sizeof(int32_t));
352     switch (propertyType) {
353         case PropertyType::FLOAT_T:
354             [[fallthrough]];
355         case PropertyType::UINT32_T:
356             [[fallthrough]];
357         case PropertyType::INT32_T:
358             [[fallthrough]];
359         case PropertyType::BOOL_T:
360             align = sizeof(float);
361             break;
362         case PropertyType::VEC2_T:
363             [[fallthrough]];
364         case PropertyType::UVEC2_T:
365             [[fallthrough]];
366         case PropertyType::IVEC2_T:
367             align = sizeof(float) * 2U;
368             break;
369         case PropertyType::VEC3_T:
370             [[fallthrough]];
371         case PropertyType::UVEC3_T:
372             [[fallthrough]];
373         case PropertyType::IVEC3_T:
374             [[fallthrough]];
375         case PropertyType::VEC4_T:
376             [[fallthrough]];
377         case PropertyType::UVEC4_T:
378             [[fallthrough]];
379         case PropertyType::IVEC4_T:
380             align = sizeof(float) * 4U;
381             break;
382         case PropertyType::MAT3X3_T:
383             align = sizeof(float) * 4U * 3U;
384             break;
385         case PropertyType::MAT4X4_T:
386             align = sizeof(float) * 4U * 4U;
387             break;
388     }
389     return align;
390 }
391 
SetCustomPropertyBlobValue(const PropertyTypeDecl & propertyType,const json::value * value,CustomPropertyPodContainer & customProperties,const size_t offset)392 void CustomPropertyPodHelper::SetCustomPropertyBlobValue(const PropertyTypeDecl& propertyType, const json::value* value,
393     CustomPropertyPodContainer& customProperties, const size_t offset)
394 {
395     if (propertyType == PropertyType::VEC4_T) {
396         Math::Vec4 val;
397         FromJson(*value, val);
398         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec4) });
399     } else if (propertyType == PropertyType::UVEC4_T) {
400         Math::UVec4 val;
401         FromJson(*value, val);
402         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec4) });
403     } else if (propertyType == PropertyType::IVEC4_T) {
404         Math::IVec4 val;
405         FromJson(*value, val);
406         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec4) });
407     } else if (propertyType == PropertyType::VEC3_T) {
408         Math::Vec3 val;
409         FromJson(*value, val);
410         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec3) });
411     } else if (propertyType == PropertyType::UVEC3_T) {
412         Math::UVec3 val;
413         FromJson(*value, val);
414         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec3) });
415     } else if (propertyType == PropertyType::IVEC3_T) {
416         Math::IVec3 val;
417         FromJson(*value, val);
418         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec3) });
419     } else if (propertyType == PropertyType::VEC2_T) {
420         Math::Vec2 val;
421         FromJson(*value, val);
422         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec2) });
423     } else if (propertyType == PropertyType::UVEC2_T) {
424         Math::UVec2 val;
425         FromJson(*value, val);
426         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec2) });
427     } else if (propertyType == PropertyType::IVEC2_T) {
428         Math::IVec2 val;
429         FromJson(*value, val);
430         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec2) });
431     } else if (propertyType == PropertyType::FLOAT_T) {
432         float val;
433         FromJson(*value, val);
434         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(float) });
435     } else if (propertyType == PropertyType::UINT32_T) {
436         uint32_t val;
437         FromJson(*value, val);
438         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(float) });
439     } else if (propertyType == PropertyType::INT32_T) {
440         int32_t val;
441         FromJson(*value, val);
442         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(float) });
443     } else if (propertyType == PropertyType::BOOL_T) {
444         bool tmpVal;
445         FromJson(*value, tmpVal);
446         uint32_t val = tmpVal;
447         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(float) });
448     } else if (propertyType == PropertyType::MAT3X3_T) {
449         Math::Mat3X3 val;
450         FromJson(*value, val);
451         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Mat3X3) });
452     } else if (propertyType == PropertyType::MAT4X4_T) {
453         Math::Mat4X4 val;
454         FromJson(*value, val);
455         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Mat4X4) });
456     } else {
457         CORE_LOG_W("CORE3D_VALIDATION: Invalid property type only int, uint, float, and XvecX variants supported");
458     }
459     // NOTE: does not handle invalid types
460 }
461 
462 CORE3D_END_NAMESPACE()
463