stage/schema/schema.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-License-Identifier: BSD-3-Clause | ||
| 2 | #pragma once | ||
| 3 | |||
| 4 | #include "chrono_batch_render/stage/schema/types.h" | ||
| 5 | |||
| 6 | #ifndef __SLANG__ | ||
| 7 | |||
| 8 | #include <array> | ||
| 9 | #include <cstdint> | ||
| 10 | #include <string> | ||
| 11 | #include <string_view> | ||
| 12 | #include <variant> | ||
| 13 | #include <vector> | ||
| 14 | |||
| 15 | #include "chrono_batch_render/export.h" | ||
| 16 | #include "chrono_batch_render/util/span.h" | ||
| 17 | |||
| 18 | namespace chrono::batch_render { | ||
| 19 | |||
| 20 | enum class SchemaId : uint32_t; | ||
| 21 | |||
| 22 | enum class SchemaKind : uint8_t { Abstract, Concrete, Api }; | ||
| 23 | |||
| 24 | enum class ColumnType : uint8_t { | ||
| 25 | Bool, | ||
| 26 | Int, | ||
| 27 | Uint, | ||
| 28 | Uint64, | ||
| 29 | Float, | ||
| 30 | Float2, | ||
| 31 | Uint2, | ||
| 32 | Float3, | ||
| 33 | Double3, | ||
| 34 | Quatd, | ||
| 35 | WorldTransform, | ||
| 36 | Enum, | ||
| 37 | Token, | ||
| 38 | IntArray, | ||
| 39 | Float3Array, | ||
| 40 | PrimArray, | ||
| 41 | Asset, | ||
| 42 | Float4, | ||
| 43 | TokenArray, | ||
| 44 | Float4Array, | ||
| 45 | Float2Array, | ||
| 46 | FloatArray, | ||
| 47 | Int64Array, | ||
| 48 | }; | ||
| 49 | |||
| 50 | enum class ColumnRole : uint8_t { None, Color, Point, Normal, Vector }; | ||
| 51 | |||
| 52 | enum class Unit : uint8_t { | ||
| 53 | None, | ||
| 54 | Meters, | ||
| 55 | Millimeters, | ||
| 56 | Degrees, | ||
| 57 | Radians, | ||
| 58 | Kelvin, | ||
| 59 | Seconds, | ||
| 60 | Nits, | ||
| 61 | Lux, | ||
| 62 | Watts, | ||
| 63 | Hertz, | ||
| 64 | }; | ||
| 65 | |||
| 66 | enum class ColumnFlags : uint8_t { | ||
| 67 | None = 0, | ||
| 68 | Internal = 1 << 0, | ||
| 69 | }; | ||
| 70 | |||
| 71 | constexpr ColumnFlags operator|(ColumnFlags a, ColumnFlags b) { | ||
| 72 | return ColumnFlags(uint8_t(a) | uint8_t(b)); | ||
| 73 | } | ||
| 74 | |||
| 75 | 43291 | constexpr bool Has(ColumnFlags flags, ColumnFlags bits) { | |
| 76 | 43291 | return (uint8_t(flags) & uint8_t(bits)) != 0; | |
| 77 | } | ||
| 78 | |||
| 79 | 823828 | constexpr bool IsArray(ColumnType type) { | |
| 80 | 823828 | return type == ColumnType::IntArray || type == ColumnType::Float3Array || | |
| 81 | 823828 | type == ColumnType::Float4Array || type == ColumnType::Float2Array || | |
| 82 | type == ColumnType::FloatArray || type == ColumnType::PrimArray || | ||
| 83 | 823828 | type == ColumnType::TokenArray || type == ColumnType::Int64Array; | |
| 84 | } | ||
| 85 | |||
| 86 | 270752 | constexpr uint32_t ElementBytes(ColumnType type) { | |
| 87 | 270752 | switch (type) { | |
| 88 | case ColumnType::Uint64: | ||
| 89 | return sizeof(uint64_t); | ||
| 90 | case ColumnType::Float2: | ||
| 91 | return sizeof(Float2); | ||
| 92 | case ColumnType::Uint2: | ||
| 93 | return sizeof(Uint2); | ||
| 94 | 18100 | case ColumnType::Float3: | |
| 95 | 18100 | return sizeof(Float3); | |
| 96 | 2561 | case ColumnType::Float4: | |
| 97 | 2561 | return sizeof(Float4); | |
| 98 | 914 | case ColumnType::Double3: | |
| 99 | 914 | return sizeof(Double3); | |
| 100 | 1024 | case ColumnType::Quatd: | |
| 101 | 1024 | return sizeof(Quatd); | |
| 102 | ✗ | case ColumnType::WorldTransform: | |
| 103 | ✗ | return sizeof(WorldTransform); | |
| 104 | 30927 | case ColumnType::IntArray: | |
| 105 | 30927 | case ColumnType::Float3Array: | |
| 106 | 30927 | case ColumnType::Float4Array: | |
| 107 | 30927 | case ColumnType::Float2Array: | |
| 108 | 30927 | case ColumnType::FloatArray: | |
| 109 | 30927 | case ColumnType::PrimArray: | |
| 110 | 30927 | case ColumnType::TokenArray: | |
| 111 | 30927 | case ColumnType::Int64Array: | |
| 112 | 30927 | return sizeof(ArrayRef); | |
| 113 | 207427 | default: | |
| 114 | 207427 | return 4; | |
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | 9823 | constexpr uint32_t ItemBytes(ColumnType type) { | |
| 119 | 9823 | switch (type) { | |
| 120 | case ColumnType::IntArray: | ||
| 121 | case ColumnType::FloatArray: | ||
| 122 | case ColumnType::PrimArray: | ||
| 123 | case ColumnType::TokenArray: | ||
| 124 | return 4; | ||
| 125 | 1173 | case ColumnType::Float3Array: | |
| 126 | 1173 | return sizeof(Float3); | |
| 127 | 9 | case ColumnType::Float4Array: | |
| 128 | 9 | return sizeof(Float4); | |
| 129 | 27 | case ColumnType::Float2Array: | |
| 130 | 27 | return sizeof(Float2); | |
| 131 | 28 | case ColumnType::Int64Array: | |
| 132 | 28 | return 8; | |
| 133 | ✗ | default: | |
| 134 | ✗ | return 0; | |
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | struct ColumnInfo { | ||
| 139 | std::string_view field; | ||
| 140 | std::string_view name; | ||
| 141 | ColumnType type; | ||
| 142 | ColumnRole role; | ||
| 143 | ColumnFlags flags; | ||
| 144 | uint32_t offset; | ||
| 145 | SchemaId api; | ||
| 146 | std::string_view doc; | ||
| 147 | Unit unit; | ||
| 148 | Span<const std::string_view> tokens{}; | ||
| 149 | std::string_view group{}; | ||
| 150 | std::string_view displayName{}; | ||
| 151 | float minimum = 0; | ||
| 152 | float maximum = 0; | ||
| 153 | std::string_view enabledBy{}; | ||
| 154 | }; | ||
| 155 | |||
| 156 | struct SchemaInfo { | ||
| 157 | std::string_view name; | ||
| 158 | SchemaId base; | ||
| 159 | SchemaKind kind; | ||
| 160 | uint32_t firstApi; | ||
| 161 | uint32_t apiCount; | ||
| 162 | uint32_t firstColumn; | ||
| 163 | uint32_t columnCount; | ||
| 164 | uint32_t dataBytes; | ||
| 165 | uint32_t firstSlot; | ||
| 166 | uint32_t slotCount; | ||
| 167 | uint32_t api; | ||
| 168 | uint64_t apis; | ||
| 169 | uint32_t firstTarget; | ||
| 170 | uint32_t targetCount; | ||
| 171 | std::string_view doc; | ||
| 172 | }; | ||
| 173 | |||
| 174 | inline constexpr uint32_t kNoApi = 0xFFFFFFFF; | ||
| 175 | |||
| 176 | struct BuiltinInstanceInfo { | ||
| 177 | SchemaId schema; | ||
| 178 | SchemaId api; | ||
| 179 | std::string_view instance; | ||
| 180 | }; | ||
| 181 | |||
| 182 | struct ColumnRef; | ||
| 183 | |||
| 184 | template <class T> struct Field { | ||
| 185 | SchemaId owner; | ||
| 186 | uint32_t index; | ||
| 187 | |||
| 188 | constexpr ColumnRef Column() const; | ||
| 189 | }; | ||
| 190 | |||
| 191 | using RuntimeValue = std::variant<bool, int32_t, float, Float2, Float3, Float4, std::string>; | ||
| 192 | |||
| 193 | CHRONO_BATCH_RENDER_API uint32_t SchemaCount(); | ||
| 194 | CHRONO_BATCH_RENDER_API const SchemaInfo& RuntimeInfo(SchemaId schema); | ||
| 195 | CHRONO_BATCH_RENDER_API Span<const ColumnInfo> RuntimeColumns(SchemaId schema); | ||
| 196 | CHRONO_BATCH_RENDER_API Span<const SchemaId> RuntimeSlots(SchemaId schema); | ||
| 197 | CHRONO_BATCH_RENDER_API const RuntimeValue& RuntimeFallback(SchemaId schema, uint32_t column); | ||
| 198 | |||
| 199 | 185 | struct RuntimeInheritance { | |
| 200 | SchemaId owner; | ||
| 201 | uint32_t index; | ||
| 202 | RuntimeValue value; | ||
| 203 | }; | ||
| 204 | |||
| 205 | CHRONO_BATCH_RENDER_API Span<const RuntimeInheritance> RuntimeInherited(SchemaId schema); | ||
| 206 | |||
| 207 | } | ||
| 208 | |||
| 209 | #endif | ||
| 210 | |||
| 211 | #include "chrono_batch_render/scene/schema/registry.h" | ||
| 212 | |||
| 213 | #ifndef __SLANG__ | ||
| 214 | |||
| 215 | namespace chrono::batch_render { | ||
| 216 | |||
| 217 | 1 | constexpr bool IsRuntime(SchemaId schema) { | |
| 218 | 1 | return uint32_t(schema) >= uint32_t(SchemaId::Count); | |
| 219 | } | ||
| 220 | |||
| 221 | 4083843 | constexpr const SchemaInfo& Info(SchemaId schema) { | |
| 222 | 4084136 | return IsRuntime(schema) ? RuntimeInfo(schema) : kSchemaInfo[uint32_t(schema)]; | |
| 223 | } | ||
| 224 | |||
| 225 | 665 | constexpr Span<const SchemaId> Apis(SchemaId schema) { | |
| 226 | 1330 | return Span<const SchemaId>(kSchemaApis).subspan(Info(schema).firstApi, Info(schema).apiCount); | |
| 227 | 665 | } | |
| 228 | |||
| 229 | 538832 | constexpr Span<const ColumnInfo> Columns(SchemaId schema) { | |
| 230 | 538832 | if (IsRuntime(schema)) { | |
| 231 | 1937 | return RuntimeColumns(schema); | |
| 232 | } | ||
| 233 | 1073790 | return Span<const ColumnInfo>(kColumns).subspan(Info(schema).firstColumn, | |
| 234 | 536895 | Info(schema).columnCount); | |
| 235 | 536895 | } | |
| 236 | |||
| 237 | inline constexpr uint32_t kNoSlot = 0xFFFFFFFF; | ||
| 238 | |||
| 239 | 110613 | constexpr Span<const SchemaId> Slots(SchemaId schema) { | |
| 240 | 110613 | if (IsRuntime(schema)) { | |
| 241 | 415 | return RuntimeSlots(schema); | |
| 242 | } | ||
| 243 | 220396 | return Span<const SchemaId>(kSchemaSlots) | |
| 244 | 220396 | .subspan(Info(schema).firstSlot, Info(schema).slotCount); | |
| 245 | 110198 | } | |
| 246 | |||
| 247 | 79742 | constexpr uint32_t Slot(SchemaId schema, SchemaId table) { | |
| 248 | 79742 | const Span<const SchemaId> slots = Slots(schema); | |
| 249 | 237440 | for (uint32_t slot = 0; slot < slots.size(); ++slot) { | |
| 250 | 236542 | if (slots[slot] == table) { | |
| 251 | return slot; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | return kNoSlot; | ||
| 255 | } | ||
| 256 | |||
| 257 | 376431 | constexpr bool IsA(SchemaId schema, SchemaId base) { | |
| 258 | 2285231 | for (; schema != SchemaId::None; schema = Info(schema).base) { | |
| 259 | 1164849 | if (schema == base) { | |
| 260 | return true; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | return false; | ||
| 264 | } | ||
| 265 | |||
| 266 | 269289 | constexpr bool IsApi(SchemaId schema) { | |
| 267 | 269289 | return Info(schema).api != kNoApi; | |
| 268 | } | ||
| 269 | |||
| 270 | 804098 | constexpr uint64_t ApiBit(SchemaId api) { | |
| 271 | 804098 | return uint64_t(1) << Info(api).api; | |
| 272 | } | ||
| 273 | |||
| 274 | 67311 | constexpr bool IsMultipleApi(SchemaId schema) { | |
| 275 | 67311 | return IsApi(schema) && (kMultipleApis & ApiBit(schema)) != 0; | |
| 276 | } | ||
| 277 | |||
| 278 | ✗ | constexpr bool BuiltinInstance(SchemaId schema, SchemaId api, std::string_view instance) { | |
| 279 | ✗ | for (const BuiltinInstanceInfo& entry : kBuiltinInstances) { | |
| 280 | ✗ | if (entry.schema == schema && entry.api == api && entry.instance == instance) { | |
| 281 | return true; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | return false; | ||
| 285 | } | ||
| 286 | |||
| 287 | 105517 | constexpr bool HasApi(uint64_t apis, SchemaId api) { | |
| 288 | 105517 | return IsApi(api) && (apis & ApiBit(api)) != 0; | |
| 289 | } | ||
| 290 | |||
| 291 | 3396 | constexpr bool Includes(SchemaId schema, SchemaId api) { | |
| 292 | 6792 | return HasApi(Info(schema).apis, api); | |
| 293 | } | ||
| 294 | |||
| 295 | 60 | constexpr Span<const SchemaId> ApiTargets(SchemaId api) { | |
| 296 | 120 | return Span<const SchemaId>(kApiTargets).subspan(Info(api).firstTarget, Info(api).targetCount); | |
| 297 | 60 | } | |
| 298 | |||
| 299 | 60 | constexpr bool AppliesTo(SchemaId api, SchemaId schema) { | |
| 300 | 120 | if (!IsApi(api) || Info(schema).kind == SchemaKind::Api) { | |
| 301 | ✗ | return false; | |
| 302 | } | ||
| 303 | 60 | const Span<const SchemaId> targets = ApiTargets(api); | |
| 304 | 60 | if (targets.empty()) { | |
| 305 | return true; | ||
| 306 | } | ||
| 307 | 87 | for (const SchemaId target : targets) { | |
| 308 | 85 | if (IsA(schema, target)) { | |
| 309 | return true; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | return false; | ||
| 313 | } | ||
| 314 | |||
| 315 | 9474 | constexpr uint32_t ApiSlot(SchemaId schema, uint64_t apis, SchemaId api) { | |
| 316 | 9474 | if (!HasApi(apis, api)) { | |
| 317 | return kNoSlot; | ||
| 318 | } | ||
| 319 | 9135 | uint32_t below = 0; | |
| 320 | 19272 | for (uint64_t bits = apis & (ApiBit(api) - 1); bits != 0; bits &= bits - 1) { | |
| 321 | 10137 | ++below; | |
| 322 | } | ||
| 323 | 18270 | return Info(schema).slotCount + below; | |
| 324 | } | ||
| 325 | |||
| 326 | 89134 | constexpr uint32_t PrimSlot(SchemaId schema, uint64_t apis, SchemaId table) { | |
| 327 | 89134 | return IsApi(table) ? ApiSlot(schema, apis, table) : Slot(schema, table); | |
| 328 | } | ||
| 329 | |||
| 330 | 269 | inline SchemaId ShaderSchema(std::string_view id) { | |
| 331 | 8373 | for (uint32_t index = SchemaCount(); index-- > 0;) { | |
| 332 | 8363 | const SchemaId schema = SchemaId(index); | |
| 333 | 17245 | if (Info(schema).name == id && Info(schema).kind == SchemaKind::Concrete && | |
| 334 | 259 | IsA(schema, SchemaId::Shader)) { | |
| 335 | return schema; | ||
| 336 | } | ||
| 337 | } | ||
| 338 | return SchemaId::None; | ||
| 339 | } | ||
| 340 | |||
| 341 | 30844 | inline std::vector<SchemaId> PrimTables(SchemaId schema, uint64_t apis) { | |
| 342 | 30844 | const Span<const SchemaId> typed = Slots(schema); | |
| 343 | 30844 | std::vector<SchemaId> tables(typed.begin(), typed.end()); | |
| 344 | 709412 | for (const SchemaId api : kApiSchemas) { | |
| 345 | 678568 | if ((apis & ApiBit(api)) != 0) { | |
| 346 | 33063 | tables.push_back(api); | |
| 347 | } | ||
| 348 | } | ||
| 349 | 30844 | return tables; | |
| 350 | ✗ | } | |
| 351 | |||
| 352 | 34 | struct ColumnRef { | |
| 353 | SchemaId schema = SchemaId::None; | ||
| 354 | const ColumnInfo* column = nullptr; | ||
| 355 | uint32_t index = 0; | ||
| 356 | |||
| 357 | 420836 | explicit constexpr operator bool() const { | |
| 358 | 254685 | return column != nullptr; | |
| 359 | } | ||
| 360 | }; | ||
| 361 | |||
| 362 | 14361 | template <class T> constexpr ColumnRef Field<T>::Column() const { | |
| 363 | 14361 | return {owner, &Columns(owner)[index], index}; | |
| 364 | } | ||
| 365 | |||
| 366 | 83856 | constexpr ColumnRef FindOwnColumn(SchemaId schema, std::string_view field) { | |
| 367 | 83856 | const Span<const ColumnInfo> columns = Columns(schema); | |
| 368 | 87655 | for (uint32_t index = 0; index < columns.size(); ++index) { | |
| 369 | 86971 | if (columns[index].field == field) { | |
| 370 | 83172 | return {schema, &columns[index], index}; | |
| 371 | } | ||
| 372 | } | ||
| 373 | 684 | return {}; | |
| 374 | } | ||
| 375 | |||
| 376 | 82862 | constexpr ColumnRef FindColumn(SchemaId schema, std::string_view field) { | |
| 377 | 84146 | for (; schema != SchemaId::None; schema = Info(schema).base) { | |
| 378 | 83443 | if (const ColumnRef own = FindOwnColumn(schema, field)) { | |
| 379 | 82778 | return own; | |
| 380 | } | ||
| 381 | 684 | for (const SchemaId api : Apis(schema)) { | |
| 382 | 42 | if (const ColumnRef builtin = FindOwnColumn(api, field)) { | |
| 383 | 23 | return builtin; | |
| 384 | } | ||
| 385 | } | ||
| 386 | } | ||
| 387 | 61 | return {}; | |
| 388 | } | ||
| 389 | |||
| 390 | 82666 | constexpr ColumnRef FindColumn(SchemaId schema, uint64_t apis, std::string_view field) { | |
| 391 | 82666 | if (const ColumnRef found = FindColumn(schema, field)) { | |
| 392 | 82666 | return found; | |
| 393 | } | ||
| 394 | ✗ | for (const SchemaId api : kApiSchemas) { | |
| 395 | ✗ | if ((apis & ApiBit(api)) != 0) { | |
| 396 | ✗ | if (const ColumnRef applied = FindOwnColumn(api, field)) { | |
| 397 | ✗ | return applied; | |
| 398 | } | ||
| 399 | } | ||
| 400 | } | ||
| 401 | ✗ | return {}; | |
| 402 | } | ||
| 403 | |||
| 404 | 28 | template <class W> void WriteRuntimeFallbacks(SchemaId schema, W& w) { | |
| 405 | 28 | if (!IsRuntime(schema)) { | |
| 406 | return; | ||
| 407 | } | ||
| 408 | 56 | WriteFallbacks(Info(schema).base, w); | |
| 409 | 28 | if (IsA(schema, SchemaId::Shader)) { | |
| 410 | 28 | w.Set(SchemaId::Shader, FindOwnColumn(SchemaId::Shader, "id").index, | |
| 411 | 84 | std::string(Info(schema).name)); | |
| 412 | } | ||
| 413 | 91 | for (const RuntimeInheritance& inherited : RuntimeInherited(schema)) { | |
| 414 | 63 | std::visit([&](const auto& value) { w.Set(inherited.owner, inherited.index, value); }, | |
| 415 | 63 | inherited.value); | |
| 416 | } | ||
| 417 | 164 | for (uint32_t column = 0; column < Info(schema).columnCount; ++column) { | |
| 418 | 54 | std::visit([&](const auto& value) { w.Set(schema, column, value); }, | |
| 419 | 54 | RuntimeFallback(schema, column)); | |
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | } | ||
| 424 | |||
| 425 | #endif | ||
| 426 |