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 #include <render/property/property_types.h>
26 
27 #include "util/json_util.h"
28 #include "util/log.h"
29 
30 RENDER_BEGIN_NAMESPACE()
31 using namespace BASE_NS;
32 using namespace CORE_NS;
33 
34 namespace {
35 constexpr size_t BUFFER_HANDLE_REF_BYTE_SIZE = sizeof(BindableBufferWithHandleReference);
36 constexpr size_t IMAGE_HANDLE_REF_BYTE_SIZE = sizeof(BindableImageWithHandleReference);
37 constexpr size_t SAMPLER_HANDLE_REF_BYTE_SIZE = sizeof(BindableSamplerWithHandleReference);
38 constexpr size_t MAX_STRUCT_HANDLE_REF_BYTE_SIZE =
39     Math::max(BUFFER_HANDLE_REF_BYTE_SIZE, Math::max(IMAGE_HANDLE_REF_BYTE_SIZE, SAMPLER_HANDLE_REF_BYTE_SIZE));
40 
GetPropertyTypeByteSize(const PropertyTypeDecl & typeDecl)41 uint32_t GetPropertyTypeByteSize(const PropertyTypeDecl& typeDecl)
42 {
43     uint32_t byteSize = 0; // zero means that un-supported property type
44     switch (typeDecl) {
45         case PropertyType::UINT32_T:
46         case PropertyType::INT32_T:
47         case PropertyType::FLOAT_T:
48         case PropertyType::BOOL_T:
49             byteSize = sizeof(uint32_t);
50             break;
51         case PropertyType::UVEC2_T:
52         case PropertyType::IVEC2_T:
53         case PropertyType::VEC2_T:
54             byteSize = sizeof(Math::UVec2);
55             break;
56         case PropertyType::UVEC3_T:
57         case PropertyType::IVEC3_T:
58         case PropertyType::VEC3_T:
59             byteSize = sizeof(Math::UVec3);
60             break;
61         case PropertyType::UVEC4_T:
62         case PropertyType::IVEC4_T:
63         case PropertyType::VEC4_T:
64             byteSize = sizeof(Math::UVec4);
65             break;
66         case PropertyType::MAT3X3_T:
67             byteSize = sizeof(Math::Mat3X3);
68             break;
69         case PropertyType::MAT4X4_T:
70             byteSize = sizeof(Math::Mat4X4);
71             break;
72     }
73     return byteSize;
74 }
75 
GetMetaData(const PropertyTypeDecl & typeDecl)76 constexpr MetaData GetMetaData(const PropertyTypeDecl& typeDecl)
77 {
78     switch (typeDecl) {
79         case PropertyType::UINT32_T:
80             return PropertyType::MetaDataFrom<uint32_t>(nullptr);
81         case PropertyType::INT32_T:
82             return PropertyType::MetaDataFrom<int32_t>(nullptr);
83         case PropertyType::FLOAT_T:
84             return PropertyType::MetaDataFrom<float>(nullptr);
85 
86         case PropertyType::BOOL_T:
87             return PropertyType::MetaDataFrom<bool>(nullptr);
88 
89         case PropertyType::UVEC2_T:
90             return PropertyType::MetaDataFrom<Math::UVec2>(nullptr);
91         case PropertyType::IVEC2_T:
92             return PropertyType::MetaDataFrom<Math::IVec2>(nullptr);
93         case PropertyType::VEC2_T:
94             return PropertyType::MetaDataFrom<Math::Vec2>(nullptr);
95 
96         case PropertyType::UVEC3_T:
97             return PropertyType::MetaDataFrom<Math::UVec3>(nullptr);
98         case PropertyType::IVEC3_T:
99             return PropertyType::MetaDataFrom<Math::IVec3>(nullptr);
100         case PropertyType::VEC3_T:
101             return PropertyType::MetaDataFrom<Math::Vec3>(nullptr);
102 
103         case PropertyType::UVEC4_T:
104             return PropertyType::MetaDataFrom<Math::UVec4>(nullptr);
105         case PropertyType::IVEC4_T:
106             return PropertyType::MetaDataFrom<Math::IVec4>(nullptr);
107         case PropertyType::VEC4_T:
108             return PropertyType::MetaDataFrom<Math::Vec4>(nullptr);
109 
110         case PropertyType::MAT3X3_T:
111             return PropertyType::MetaDataFrom<Math::Mat3X3>(nullptr);
112         case PropertyType::MAT4X4_T:
113             return PropertyType::MetaDataFrom<Math::Mat4X4>(nullptr);
114     }
115     return {};
116 }
117 } // namespace
118 
CustomPropertyPodContainer(size_t reserveByteSize)119 CustomPropertyPodContainer::CustomPropertyPodContainer(size_t reserveByteSize)
120 {
121     data_.reserve(reserveByteSize);
122 }
123 
PropertyCount() const124 size_t CustomPropertyPodContainer::PropertyCount() const
125 {
126     return metaData_.size();
127 }
128 
MetaData(size_t index) const129 const Property* CustomPropertyPodContainer::MetaData(size_t index) const
130 {
131     if (index < metaData_.size()) {
132         return &metaData_[index];
133     }
134 
135     return nullptr;
136 }
137 
MetaData() const138 array_view<const Property> CustomPropertyPodContainer::MetaData() const
139 {
140     return { metaData_ };
141 }
142 
Type() const143 uint64_t CustomPropertyPodContainer::Type() const
144 {
145     return 0;
146 }
147 
Create() const148 IPropertyHandle* CustomPropertyPodContainer::Create() const
149 {
150     return nullptr;
151 }
152 
Clone(const IPropertyHandle * src) const153 IPropertyHandle* CustomPropertyPodContainer::Clone(const IPropertyHandle* src) const
154 {
155     return nullptr;
156 }
157 
Release(IPropertyHandle * handle) const158 void CustomPropertyPodContainer::Release(IPropertyHandle* handle) const {}
159 
Reset()160 void CustomPropertyPodContainer::Reset()
161 {
162     metaStrings_.clear();
163     metaData_.clear();
164     data_.clear();
165 }
166 
ReservePropertyCount(size_t propertyCount)167 void CustomPropertyPodContainer::ReservePropertyCount(size_t propertyCount)
168 {
169     reservePropertyCount_ = propertyCount;
170     metaStrings_.reserve(reservePropertyCount_);
171     metaData_.reserve(reservePropertyCount_);
172 }
173 
174 // CustomProperties IPropertyHandle
Owner() const175 const IPropertyApi* CustomPropertyPodContainer::Owner() const
176 {
177     return this;
178 }
179 
Size() const180 size_t CustomPropertyPodContainer::Size() const
181 {
182     return data_.size();
183 }
184 
RLock() const185 const void* CustomPropertyPodContainer::RLock() const
186 {
187     return data_.data();
188 }
189 
RUnlock() const190 void CustomPropertyPodContainer::RUnlock() const {}
191 
WLock()192 void* CustomPropertyPodContainer::WLock()
193 {
194     return data_.data();
195 }
196 
WUnlock()197 void CustomPropertyPodContainer::WUnlock() {}
198 
199 //
200 
AddOffsetProperty(const string_view propertyName,const string_view displayName,const uintptr_t offset,const PropertyTypeDecl & typeDecl)201 void CustomPropertyPodContainer::AddOffsetProperty(const string_view propertyName, const string_view displayName,
202     const uintptr_t offset, const PropertyTypeDecl& typeDecl)
203 {
204     const size_t byteSize = GetPropertyTypeByteSize(typeDecl);
205     const bool reserved = (metaStrings_.size() < reservePropertyCount_);
206     if ((byteSize > 0) && reserved) {
207         metaStrings_.push_back({ string { propertyName }, string { displayName } });
208         const auto& strings = metaStrings_.back();
209         const Property meta {
210             strings.name,                                        // name
211             FNV1aHash(strings.name.data(), strings.name.size()), // hash
212             typeDecl,                                            // type
213             1U,                                                  // count
214             byteSize,                                            // size
215             offset,                                              // offset
216             strings.displayName,                                 // displayName
217             0U,                                                  // flags
218             GetMetaData(typeDecl),                               // metaData
219         };
220         metaData_.push_back(meta);
221         data_.resize(Math::max(data_.size(), meta.offset + meta.size));
222     } else {
223         CORE_LOG_W("unsupported property addition for custom property POD container");
224     }
225 }
226 
AddOffsetProperty(const string_view propertyName,const string_view displayName,const uintptr_t offset,const PropertyTypeDecl & typeDecl,const array_view<const uint8_t> data)227 void CustomPropertyPodContainer::AddOffsetProperty(const string_view propertyName, const string_view displayName,
228     const uintptr_t offset, const PropertyTypeDecl& typeDecl, const array_view<const uint8_t> data)
229 {
230     const size_t byteSize = GetPropertyTypeByteSize(typeDecl);
231     const bool reserved = (metaStrings_.size() < reservePropertyCount_);
232     if ((byteSize > 0) && reserved) {
233         metaStrings_.push_back({ string { propertyName }, string { displayName } });
234         const auto& strings = metaStrings_.back();
235         const Property meta {
236             strings.name,                                        // name
237             FNV1aHash(strings.name.data(), strings.name.size()), // hash
238             typeDecl,                                            // type
239             1U,                                                  // count
240             byteSize,                                            // size
241             offset,                                              // offset
242             strings.displayName,                                 // displayName
243             0U,                                                  // flags
244             GetMetaData(typeDecl),                               // metaData
245         };
246         metaData_.push_back(meta);
247         data_.resize(data_.size() + meta.size);
248         if (data.size_bytes() == byteSize) {
249             CloneData(data_.data() + offset, data_.size_in_bytes(), data.data(), data.size_bytes());
250         }
251     } else {
252         CORE_LOG_W("unsupported property addition for custom property POD container");
253     }
254 }
255 
SetValue(const string_view propertyName,const array_view<uint8_t> data)256 bool CustomPropertyPodContainer::SetValue(const string_view propertyName, const array_view<uint8_t> data)
257 {
258     for (const auto& metaRef : metaData_) {
259         if ((metaRef.displayName == propertyName) && (metaRef.size == data.size_bytes())) {
260             const size_t endData = metaRef.offset + metaRef.size;
261             if (endData <= data_.size_in_bytes()) {
262                 CloneData(data_.data() + metaRef.offset, data_.size_in_bytes(), data.data(), data.size_bytes());
263                 return true;
264             }
265         }
266     }
267     return false;
268 }
269 
SetValue(const size_t byteOffset,const array_view<uint8_t> data)270 bool CustomPropertyPodContainer::SetValue(const size_t byteOffset, const array_view<uint8_t> data)
271 {
272     const size_t endData = byteOffset + data.size_bytes();
273     if (endData <= data_.size_in_bytes()) {
274         CloneData(data_.data() + byteOffset, data_.size_in_bytes(), data.data(), data.size_bytes());
275         return true;
276     }
277     return false;
278 }
279 
GetValue(const string_view propertyName) const280 array_view<const uint8_t> CustomPropertyPodContainer::GetValue(const string_view propertyName) const
281 {
282     for (const auto& metaRef : metaData_) {
283         if (metaRef.displayName == propertyName) {
284             const size_t endData = metaRef.offset + metaRef.size;
285             if (endData <= data_.size_in_bytes()) {
286                 return { data_.data() + metaRef.offset, metaRef.size };
287             }
288         }
289     }
290     return {};
291 }
292 
GetByteSize() const293 size_t CustomPropertyPodContainer::GetByteSize() const
294 {
295     return data_.size_in_bytes();
296 }
297 
GetData() const298 BASE_NS::array_view<const uint8_t> CustomPropertyPodContainer::GetData() const
299 {
300     return data_;
301 }
302 
303 //
304 
GetPropertyTypeDeclaration(const string_view type)305 PropertyTypeDecl CustomPropertyPodHelper::GetPropertyTypeDeclaration(const string_view type)
306 {
307     if (type == "vec4") {
308         return PropertyType::VEC4_T;
309     } else if (type == "uvec4") {
310         return PropertyType::UVEC4_T;
311     } else if (type == "ivec4") {
312         return PropertyType::IVEC4_T;
313     } else if (type == "vec3") {
314         return PropertyType::VEC3_T;
315     } else if (type == "uvec3") {
316         return PropertyType::UVEC3_T;
317     } else if (type == "ivec3") {
318         return PropertyType::IVEC3_T;
319     } else if (type == "vec2") {
320         return PropertyType::VEC2_T;
321     } else if (type == "uvec2") {
322         return PropertyType::UVEC2_T;
323     } else if (type == "ivec2") {
324         return PropertyType::IVEC2_T;
325     } else if (type == "float") {
326         return PropertyType::FLOAT_T;
327     } else if (type == "uint") {
328         return PropertyType::UINT32_T;
329     } else if (type == "int") {
330         return PropertyType::INT32_T;
331     } else if (type == "bool") {
332         return PropertyType::BOOL_T;
333     } else if (type == "mat3x3") {
334         return PropertyType::MAT3X3_T;
335     } else if (type == "mat4x4") {
336         return PropertyType::MAT4X4_T;
337     } else {
338         CORE_LOG_W("RENDER_VALIDATION: Invalid property type only int, uint, float, bool, and XvecX variants, and "
339                    "mat3x3 and mat4x4 are supported");
340     }
341     // NOTE: does not handle invalid types
342     return PropertyType::INVALID;
343 }
344 
GetPropertyTypeAlignment(const PropertyTypeDecl & propertyType)345 size_t CustomPropertyPodHelper::GetPropertyTypeAlignment(const PropertyTypeDecl& propertyType)
346 {
347     size_t align = 1U;
348     static_assert(sizeof(float) == sizeof(uint32_t) && sizeof(float) == sizeof(int32_t));
349     switch (propertyType) {
350         case PropertyType::FLOAT_T:
351             [[fallthrough]];
352         case PropertyType::UINT32_T:
353             [[fallthrough]];
354         case PropertyType::INT32_T:
355             [[fallthrough]];
356         case PropertyType::BOOL_T:
357             align = sizeof(float);
358             break;
359         case PropertyType::VEC2_T:
360             [[fallthrough]];
361         case PropertyType::UVEC2_T:
362             [[fallthrough]];
363         case PropertyType::IVEC2_T:
364             align = sizeof(float) * 2U;
365             break;
366         case PropertyType::VEC3_T:
367             [[fallthrough]];
368         case PropertyType::UVEC3_T:
369             [[fallthrough]];
370         case PropertyType::IVEC3_T:
371             [[fallthrough]];
372         case PropertyType::VEC4_T:
373             [[fallthrough]];
374         case PropertyType::UVEC4_T:
375             [[fallthrough]];
376         case PropertyType::IVEC4_T:
377             align = sizeof(float) * 4U;
378             break;
379         case PropertyType::MAT3X3_T:
380             align = sizeof(float) * 4U * 3U;
381             break;
382         case PropertyType::MAT4X4_T:
383             align = sizeof(float) * 4U * 4U;
384             break;
385     }
386     return align;
387 }
388 
SetCustomPropertyBlobValue(const PropertyTypeDecl & propertyType,const json::value * value,CustomPropertyPodContainer & customProperties,const size_t offset)389 void CustomPropertyPodHelper::SetCustomPropertyBlobValue(const PropertyTypeDecl& propertyType, const json::value* value,
390     CustomPropertyPodContainer& customProperties, const size_t offset)
391 {
392     if (propertyType == PropertyType::VEC4_T) {
393         Math::Vec4 val;
394         FromJson(*value, val);
395         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec4) });
396     } else if (propertyType == PropertyType::UVEC4_T) {
397         Math::UVec4 val;
398         FromJson(*value, val);
399         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec4) });
400     } else if (propertyType == PropertyType::IVEC4_T) {
401         Math::IVec4 val;
402         FromJson(*value, val);
403         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec4) });
404     } else if (propertyType == PropertyType::VEC3_T) {
405         Math::Vec3 val;
406         FromJson(*value, val);
407         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec3) });
408     } else if (propertyType == PropertyType::UVEC3_T) {
409         Math::UVec3 val;
410         FromJson(*value, val);
411         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec3) });
412     } else if (propertyType == PropertyType::IVEC3_T) {
413         Math::IVec3 val;
414         FromJson(*value, val);
415         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec3) });
416     } else if (propertyType == PropertyType::VEC2_T) {
417         Math::Vec2 val;
418         FromJson(*value, val);
419         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec2) });
420     } else if (propertyType == PropertyType::UVEC2_T) {
421         Math::UVec2 val;
422         FromJson(*value, val);
423         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec2) });
424     } else if (propertyType == PropertyType::IVEC2_T) {
425         Math::IVec2 val;
426         FromJson(*value, val);
427         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec2) });
428     } else if (propertyType == PropertyType::FLOAT_T) {
429         float val;
430         FromJson(*value, val);
431         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(float) });
432     } else if (propertyType == PropertyType::UINT32_T) {
433         uint32_t val;
434         FromJson(*value, val);
435         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(float) });
436     } else if (propertyType == PropertyType::INT32_T) {
437         int32_t val;
438         FromJson(*value, val);
439         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(float) });
440     } else if (propertyType == PropertyType::BOOL_T) {
441         bool tmpVal;
442         FromJson(*value, tmpVal);
443         uint32_t val = tmpVal;
444         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(float) });
445     } else if (propertyType == PropertyType::MAT3X3_T) {
446         Math::Mat3X3 val;
447         FromJson(*value, val);
448         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Mat3X3) });
449     } else if (propertyType == PropertyType::MAT4X4_T) {
450         Math::Mat4X4 val;
451         FromJson(*value, val);
452         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Mat4X4) });
453     } else {
454         CORE_LOG_W("RENDER_VALIDATION: Invalid property type only int, uint, float, and XvecX variants supported");
455     }
456     // NOTE: does not handle invalid types
457 }
458 
459 // bindings
460 
461 template<typename T>
DestroyHelper(T & t)462 inline void DestroyHelper(T& t)
463 {
464     {
465         t.~T();
466     }
467 }
468 
CustomPropertyBindingContainer(CustomPropertyWriteSignal & writeSignal)469 CustomPropertyBindingContainer::CustomPropertyBindingContainer(CustomPropertyWriteSignal& writeSignal)
470     : writeSignal_(writeSignal)
471 {}
472 
~CustomPropertyBindingContainer()473 CustomPropertyBindingContainer::~CustomPropertyBindingContainer()
474 {
475     if (!data_.empty()) {
476         const uint32_t tmp = MAX_STRUCT_HANDLE_REF_BYTE_SIZE;
477         PLUGIN_ASSERT(metaData_.size() <= data_.size());
478         for (size_t idx = 0; idx < metaData_.size(); ++idx) {
479             const auto& meta = metaData_[idx];
480             CORE_ASSERT(meta.offset < data_.size_in_bytes());
481             switch (meta.type) {
482                 case PropertyType::BINDABLE_BUFFER_WITH_HANDLE_REFERENCE_T: {
483                     PLUGIN_ASSERT(meta.size == BUFFER_HANDLE_REF_BYTE_SIZE);
484                     if (BindableBufferWithHandleReference* resource =
485                             (BindableBufferWithHandleReference*)(data_.data() + meta.offset);
486                         resource) {
487                         DestroyHelper(*resource);
488                     }
489                 }
490                     break;
491                 case PropertyType::BINDABLE_IMAGE_WITH_HANDLE_REFERENCE_T: {
492                     PLUGIN_ASSERT(meta.size == IMAGE_HANDLE_REF_BYTE_SIZE);
493                     if (BindableImageWithHandleReference* resource =
494                             (BindableImageWithHandleReference*)(data_.data() + meta.offset);
495                         resource) {
496                         DestroyHelper(*resource);
497                     }
498                 }
499                     break;
500                 case PropertyType::BINDABLE_SAMPLER_WITH_HANDLE_REFERENCE_T: {
501                     PLUGIN_ASSERT(meta.size == SAMPLER_HANDLE_REF_BYTE_SIZE);
502                     if (BindableSamplerWithHandleReference* resource =
503                             (BindableSamplerWithHandleReference*)(data_.data() + meta.offset);
504                         resource) {
505                         DestroyHelper(*resource);
506                     }
507                 }
508                     break;
509                 default: {
510                     CORE_LOG_E("custom property binding destruction error");
511                 }
512                     break;
513             }
514         }
515     }
516 }
517 
PropertyCount() const518 size_t CustomPropertyBindingContainer::PropertyCount() const
519 {
520     return metaData_.size();
521 }
522 
MetaData(size_t index) const523 const Property* CustomPropertyBindingContainer::MetaData(size_t index) const
524 {
525     if (index < metaData_.size()) {
526         return &metaData_[index];
527     }
528 
529     return nullptr;
530 }
531 
MetaData() const532 array_view<const Property> CustomPropertyBindingContainer::MetaData() const
533 {
534     return { metaData_ };
535 }
536 
Type() const537 uint64_t CustomPropertyBindingContainer::Type() const
538 {
539     return 0;
540 }
541 
Create() const542 IPropertyHandle* CustomPropertyBindingContainer::Create() const
543 {
544     return nullptr;
545 }
546 
Clone(const IPropertyHandle * src) const547 IPropertyHandle* CustomPropertyBindingContainer::Clone(const IPropertyHandle* src) const
548 {
549     return nullptr;
550 }
551 
Release(IPropertyHandle * handle) const552 void CustomPropertyBindingContainer::Release(IPropertyHandle* handle) const {}
553 
ReservePropertyCount(size_t propertyCount)554 void CustomPropertyBindingContainer::ReservePropertyCount(size_t propertyCount)
555 {
556     reservePropertyCount_ = propertyCount;
557     metaStrings_.reserve(reservePropertyCount_);
558     metaData_.reserve(reservePropertyCount_);
559     // max size
560     data_.reserve(reservePropertyCount_ * MAX_STRUCT_HANDLE_REF_BYTE_SIZE);
561 }
562 
563 // CustomProperties IPropertyHandle
Owner() const564 const IPropertyApi* CustomPropertyBindingContainer::Owner() const
565 {
566     return this;
567 }
568 
Size() const569 size_t CustomPropertyBindingContainer::Size() const
570 {
571     return data_.size();
572 }
573 
RLock() const574 const void* CustomPropertyBindingContainer::RLock() const
575 {
576     return data_.data();
577 }
578 
RUnlock() const579 void CustomPropertyBindingContainer::RUnlock() const {}
580 
WLock()581 void* CustomPropertyBindingContainer::WLock()
582 {
583     return data_.data();
584 }
585 
WUnlock()586 void CustomPropertyBindingContainer::WUnlock()
587 {
588     // signal that properties have been written
589     writeSignal_.Signal();
590 }
591 
592 //
593 
AddOffsetProperty(const string_view propertyName,const string_view displayName,const uintptr_t offset,const PropertyTypeDecl & typeDecl)594 void CustomPropertyBindingContainer::AddOffsetProperty(const string_view propertyName, const string_view displayName,
595     const uintptr_t offset, const PropertyTypeDecl& typeDecl)
596 {
597     const bool reserved = (metaStrings_.size() < reservePropertyCount_);
598     size_t byteSize = 0;
599     switch (typeDecl) {
600         case PropertyType::BINDABLE_BUFFER_WITH_HANDLE_REFERENCE_T: {
601             byteSize = BUFFER_HANDLE_REF_BYTE_SIZE;
602         }
603             break;
604         case PropertyType::BINDABLE_IMAGE_WITH_HANDLE_REFERENCE_T: {
605             byteSize = IMAGE_HANDLE_REF_BYTE_SIZE;
606         }
607             break;
608         case PropertyType::BINDABLE_SAMPLER_WITH_HANDLE_REFERENCE_T: {
609             byteSize = SAMPLER_HANDLE_REF_BYTE_SIZE;
610         }
611             break;
612     }
613     if ((byteSize > 0) && reserved) {
614         metaStrings_.push_back({ string { propertyName }, string { displayName } });
615         const auto& strings = metaStrings_.back();
616         const Property meta {
617             strings.name,                                        // name
618             FNV1aHash(strings.name.data(), strings.name.size()), // hash
619             typeDecl,                                            // type
620             1U,                                                  // count
621             byteSize,                                            // size
622             offset,                                              // offset
623             strings.displayName,                                 // displayName
624             0U,                                                  // flags
625             GetMetaData(typeDecl),                               // metaData
626         };
627         metaData_.push_back(meta);
628         // the data has already been reserved in ReservePropertyCount()
629         data_.resize(Math::max(data_.size(), meta.offset + meta.size));
630         switch (meta.type) {
631             case PropertyType::BINDABLE_BUFFER_WITH_HANDLE_REFERENCE_T: {
632                 new (data_.data() + meta.offset) BindableBufferWithHandleReference;
633             }
634                 break;
635             case PropertyType::BINDABLE_IMAGE_WITH_HANDLE_REFERENCE_T: {
636                 new (data_.data() + meta.offset) BindableImageWithHandleReference;
637             }
638                 break;
639             case PropertyType::BINDABLE_SAMPLER_WITH_HANDLE_REFERENCE_T: {
640                 new (data_.data() + meta.offset) BindableSamplerWithHandleReference;
641             }
642                 break;
643         }
644     } else {
645         CORE_LOG_W("unsupported property addition for custom property binding container");
646     }
647 }
648 
GetByteSize() const649 size_t CustomPropertyBindingContainer::GetByteSize() const
650 {
651     return data_.size_in_bytes();
652 }
653 
654 // CustomPropertyBindingHelper
655 
GetPropertyTypeDeclaration(const string_view type)656 PropertyTypeDecl CustomPropertyBindingHelper::GetPropertyTypeDeclaration(const string_view type)
657 {
658     if (type == "buffer") {
659         return PropertyType::BINDABLE_BUFFER_WITH_HANDLE_REFERENCE_T;
660     } else if (type == "image") {
661         return PropertyType::BINDABLE_IMAGE_WITH_HANDLE_REFERENCE_T;
662     } else if (type == "sampler") {
663         return PropertyType::BINDABLE_SAMPLER_WITH_HANDLE_REFERENCE_T;
664     } else {
665         CORE_LOG_W("RENDER_VALIDATION: Invalid property type only buffer, image, and sampler supported");
666     }
667     // NOTE: does not handle invalid types
668     return PropertyType::INVALID;
669 }
670 
GetPropertyTypeAlignment(const PropertyTypeDecl & propertyType)671 size_t CustomPropertyBindingHelper::GetPropertyTypeAlignment(const PropertyTypeDecl& propertyType)
672 {
673     size_t align = 1U;
674     switch (propertyType) {
675         case PropertyType::BINDABLE_BUFFER_WITH_HANDLE_REFERENCE_T:
676             align = sizeof(BindableBufferWithHandleReference);
677             break;
678         case PropertyType::BINDABLE_IMAGE_WITH_HANDLE_REFERENCE_T:
679             align = sizeof(BindableImageWithHandleReference);
680             break;
681         case PropertyType::BINDABLE_SAMPLER_WITH_HANDLE_REFERENCE_T:
682             align = sizeof(BindableSamplerWithHandleReference);
683             break;
684     }
685     return align;
686 }
687 RENDER_END_NAMESPACE()