stage/views/attribute.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-License-Identifier: BSD-3-Clause | ||
| 2 | #pragma once | ||
| 3 | |||
| 4 | #include <cstddef> | ||
| 5 | #include <cstdint> | ||
| 6 | #include <functional> | ||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | #include <type_traits> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include <dlpack/dlpack.h> | ||
| 13 | |||
| 14 | #include "chrono_batch_render/device/operation.h" | ||
| 15 | #include "chrono_batch_render/device/ref.h" | ||
| 16 | #include "chrono_batch_render/device/stream.h" | ||
| 17 | #include "chrono_batch_render/device/tensor.h" | ||
| 18 | #include "chrono_batch_render/export.h" | ||
| 19 | #include "chrono_batch_render/stage/primvar.h" | ||
| 20 | #include "chrono_batch_render/stage/schema/schema.h" | ||
| 21 | #include "chrono_batch_render/stage/structure/tokens.h" | ||
| 22 | #include "chrono_batch_render/stage/views/mapping.h" | ||
| 23 | #include "chrono_batch_render/stage/views/view.h" | ||
| 24 | #include "chrono_batch_render/util/error.h" | ||
| 25 | #include "chrono_batch_render/util/span.h" | ||
| 26 | |||
| 27 | namespace chrono::batch_render { | ||
| 28 | |||
| 29 | namespace device { | ||
| 30 | class Buffer; | ||
| 31 | } | ||
| 32 | |||
| 33 | class ColumnStore; | ||
| 34 | class ColumnTable; | ||
| 35 | struct Attachment; | ||
| 36 | struct ViewRows; | ||
| 37 | |||
| 38 | enum class AttachFrom : uint8_t { Tensor, Scene }; | ||
| 39 | |||
| 40 | 178680 | class CHRONO_BATCH_RENDER_API UntypedAttribute { | |
| 41 | public: | ||
| 42 | UntypedAttribute(std::shared_ptr<ViewState> view, ColumnRef column); | ||
| 43 | |||
| 44 | 123388 | ColumnRef Reference() const { | |
| 45 | 123388 | return m_column; | |
| 46 | } | ||
| 47 | |||
| 48 | uint32_t Size() const; | ||
| 49 | bool Dense() const; | ||
| 50 | uint32_t CellBytes() const; | ||
| 51 | |||
| 52 | void Fill(Span<const std::byte> cell); | ||
| 53 | void Write(Span<const std::byte> cells); | ||
| 54 | device::Operation Write(const DLTensor& source, Stream producer = Stream::None(), | ||
| 55 | const DLTensor* mask = nullptr); | ||
| 56 | device::Operation Write(const device::Tensor& source, Stream producer = Stream::None(), | ||
| 57 | const device::Tensor& mask = {}); | ||
| 58 | |||
| 59 | device::Download ReadHostAsync() const; | ||
| 60 | std::vector<std::byte> ReadHost() const; | ||
| 61 | device::Tensor Read(Stream consumer = Stream::Host()) const; | ||
| 62 | |||
| 63 | Mapping Map(MapAccess access, Stream consumer = Stream::None()); | ||
| 64 | Mapping MapPrimvar(std::string_view name, MapAccess access, Stream consumer = Stream::None()); | ||
| 65 | device::Operation MarkChanged(Stream producer = Stream::None(), const DLTensor* mask = nullptr); | ||
| 66 | |||
| 67 | device::Operation Attach(DLManagedTensor* tensor, Stream producer = Stream::None(), | ||
| 68 | AttachFrom from = AttachFrom::Tensor); | ||
| 69 | device::Operation Attach(DLManagedTensorVersioned* tensor, Stream producer = Stream::None(), | ||
| 70 | AttachFrom from = AttachFrom::Tensor); | ||
| 71 | device::Operation Detach(Stream consumer = Stream::None()); | ||
| 72 | device::Operation WaitForReads(Stream consumer = Stream::Host()) const; | ||
| 73 | bool Attached() const; | ||
| 74 | |||
| 75 | void SetArray(uint32_t index, Span<const std::byte> items); | ||
| 76 | std::vector<std::byte> GetArray(uint32_t index) const; | ||
| 77 | |||
| 78 | void SetTargets(uint32_t index, const std::vector<std::string>& paths); | ||
| 79 | std::vector<std::string> GetTargets(uint32_t index) const; | ||
| 80 | void SetTokens(uint32_t index, const std::vector<std::string>& texts); | ||
| 81 | std::vector<std::string> GetTokens(uint32_t index) const; | ||
| 82 | void SetPrimvars(uint32_t index, const std::vector<Primvar>& primvars); | ||
| 83 | std::vector<Primvar> GetPrimvars(uint32_t index) const; | ||
| 84 | |||
| 85 | protected: | ||
| 86 | void CheckValues(size_t count) const; | ||
| 87 | static ColumnRef Checked(ColumnRef column, bool held, bool arrays); | ||
| 88 | |||
| 89 | private: | ||
| 90 | friend class Mapping; | ||
| 91 | friend class Poses; | ||
| 92 | |||
| 93 | 35160 | struct Mask { | |
| 94 | uint64_t address = 0; | ||
| 95 | Ref<device::Buffer> buffer; | ||
| 96 | }; | ||
| 97 | |||
| 98 | const ViewRows& Rows() const; | ||
| 99 | ColumnStore& GetColumnStore() const; | ||
| 100 | ColumnTable& GetTable() const; | ||
| 101 | void CheckWritable(bool arrays = false) const; | ||
| 102 | void CheckNotAttached() const; | ||
| 103 | void CheckArrayType(ColumnType type) const; | ||
| 104 | void StageCells(Span<const std::byte> cells); | ||
| 105 | void Retype(Span<const SchemaId> nodes); | ||
| 106 | device::Operation WriteTensor(const DLTensor& source, Stream producer, const DLTensor* mask); | ||
| 107 | using Owner = std::function<std::shared_ptr<const DLTensor>()>; | ||
| 108 | device::Operation AttachTensor(const DLTensor* source, Stream producer, AttachFrom from, | ||
| 109 | const Owner& own); | ||
| 110 | device::Operation AttachArrays(const Attachment& attachment, const DLTensor& source, | ||
| 111 | Stream producer, AttachFrom from); | ||
| 112 | device::Operation CopyArrays(const DLTensor& source, Stream producer, const DLTensor* mask); | ||
| 113 | void ReleaseArrays(); | ||
| 114 | void MapArray(Mapping& mapping); | ||
| 115 | void StampWorlds() const; | ||
| 116 | Mask Upload(const DLTensor* mask, Stream producer) const; | ||
| 117 | Mask Upload(const device::Tensor& mask) const; | ||
| 118 | Ref<device::Buffer> GatherCells() const; | ||
| 119 | device::Operation Scatter(uint64_t cells, Stream producer, const Mask& selected); | ||
| 120 | device::Operation Stamp(Stream producer, const DLTensor* mask); | ||
| 121 | |||
| 122 | std::shared_ptr<ViewState> m_view; | ||
| 123 | ColumnRef m_column; | ||
| 124 | }; | ||
| 125 | |||
| 126 | template <class T, class = void> struct HasItems : std::false_type {}; | ||
| 127 | |||
| 128 | template <class T> struct HasItems<T, std::void_t<typename T::value_type>> : std::true_type {}; | ||
| 129 | |||
| 130 | template <class T> struct Identity { | ||
| 131 | using Type = T; | ||
| 132 | }; | ||
| 133 | |||
| 134 | template <class T> using AttributeCell = std::conditional_t<std::is_same_v<T, bool>, uint32_t, T>; | ||
| 135 | |||
| 136 | template <class T, class = void> struct AttributeValue; | ||
| 137 | |||
| 138 | template <class T> struct AttributeValue<T, std::enable_if_t<std::is_enum_v<T>>> { | ||
| 139 | static constexpr ColumnType kType = ColumnType::Enum; | ||
| 140 | }; | ||
| 141 | |||
| 142 | template <> struct AttributeValue<Token> { | ||
| 143 | static constexpr ColumnType kType = ColumnType::Token; | ||
| 144 | }; | ||
| 145 | |||
| 146 | template <> struct AttributeValue<bool> { | ||
| 147 | static constexpr ColumnType kType = ColumnType::Bool; | ||
| 148 | }; | ||
| 149 | |||
| 150 | template <> struct AttributeValue<int32_t> { | ||
| 151 | static constexpr ColumnType kType = ColumnType::Int; | ||
| 152 | }; | ||
| 153 | |||
| 154 | template <> struct AttributeValue<uint32_t> { | ||
| 155 | static constexpr ColumnType kType = ColumnType::Uint; | ||
| 156 | }; | ||
| 157 | |||
| 158 | template <> struct AttributeValue<uint64_t> { | ||
| 159 | static constexpr ColumnType kType = ColumnType::Uint64; | ||
| 160 | }; | ||
| 161 | |||
| 162 | template <> struct AttributeValue<float> { | ||
| 163 | static constexpr ColumnType kType = ColumnType::Float; | ||
| 164 | }; | ||
| 165 | |||
| 166 | template <> struct AttributeValue<Float2> { | ||
| 167 | static constexpr ColumnType kType = ColumnType::Float2; | ||
| 168 | }; | ||
| 169 | |||
| 170 | template <> struct AttributeValue<Float3> { | ||
| 171 | static constexpr ColumnType kType = ColumnType::Float3; | ||
| 172 | }; | ||
| 173 | |||
| 174 | template <> struct AttributeValue<Float4> { | ||
| 175 | static constexpr ColumnType kType = ColumnType::Float4; | ||
| 176 | }; | ||
| 177 | |||
| 178 | template <> struct AttributeValue<Uint2> { | ||
| 179 | static constexpr ColumnType kType = ColumnType::Uint2; | ||
| 180 | }; | ||
| 181 | |||
| 182 | template <> struct AttributeValue<Double3> { | ||
| 183 | static constexpr ColumnType kType = ColumnType::Double3; | ||
| 184 | }; | ||
| 185 | |||
| 186 | template <> struct AttributeValue<Quatd> { | ||
| 187 | static constexpr ColumnType kType = ColumnType::Quatd; | ||
| 188 | }; | ||
| 189 | |||
| 190 | template <> struct AttributeValue<WorldTransform> { | ||
| 191 | static constexpr ColumnType kType = ColumnType::WorldTransform; | ||
| 192 | }; | ||
| 193 | |||
| 194 | 13587 | template <class T> constexpr bool HeldAs(ColumnType type) { | |
| 195 | if constexpr (std::is_same_v<T, Token>) { | ||
| 196 | 1603 | return type == ColumnType::Token || type == ColumnType::Asset; | |
| 197 | } else { | ||
| 198 | 11984 | return type == AttributeValue<T>::kType; | |
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | 27167 | template <class T> class Attribute : public UntypedAttribute { | |
| 203 | public: | ||
| 204 | 13587 | Attribute(std::shared_ptr<ViewState> view, ColumnRef column) | |
| 205 | 27171 | : UntypedAttribute(std::move(view), Check(column)) {} | |
| 206 | |||
| 207 | 981 | void Set(const T& value) { | |
| 208 | 981 | const Cell cell = Cell(value); | |
| 209 | 981 | Fill(AsBytes(Span<const Cell>(&cell, 1))); | |
| 210 | 979 | } | |
| 211 | |||
| 212 | 9 | void Set(Span<const T> values) { | |
| 213 | 9 | if (values.size() != Size()) { | |
| 214 | ✗ | CheckValues(values.size()); | |
| 215 | } | ||
| 216 | if constexpr (std::is_same_v<T, bool>) { | ||
| 217 | const std::vector<uint32_t> cells(values.begin(), values.end()); | ||
| 218 | Write(AsBytes(Span<const uint32_t>(cells))); | ||
| 219 | } else { | ||
| 220 | 9 | Write(AsBytes(values)); | |
| 221 | } | ||
| 222 | 9 | } | |
| 223 | |||
| 224 | 9 | void Set(const std::vector<T>& values) { | |
| 225 | if constexpr (std::is_same_v<T, bool>) { | ||
| 226 | const std::vector<uint32_t> cells(values.begin(), values.end()); | ||
| 227 | CheckValues(cells.size()); | ||
| 228 | Write(AsBytes(Span<const uint32_t>(cells))); | ||
| 229 | } else { | ||
| 230 | 9 | Set(Span<const T>(values)); | |
| 231 | } | ||
| 232 | 9 | } | |
| 233 | |||
| 234 | 12489 | std::vector<T> Get() const { | |
| 235 | 25807 | const std::vector<Cell> cells = Items<Cell>(ReadHost()); | |
| 236 | if constexpr (std::is_same_v<T, Cell>) { | ||
| 237 | 11660 | return cells; | |
| 238 | } else { | ||
| 239 | 1021 | return std::vector<T>(cells.begin(), cells.end()); | |
| 240 | } | ||
| 241 | 829 | } | |
| 242 | |||
| 243 | private: | ||
| 244 | using Cell = AttributeCell<T>; | ||
| 245 | |||
| 246 | 13587 | static ColumnRef Check(ColumnRef column) { | |
| 247 | 13587 | return Checked(column, HeldAs<T>(column.column->type), false); | |
| 248 | } | ||
| 249 | }; | ||
| 250 | |||
| 251 | 5320 | template <class T> class ArrayAttribute : public UntypedAttribute { | |
| 252 | public: | ||
| 253 | 2662 | ArrayAttribute(std::shared_ptr<ViewState> view, ColumnRef column) | |
| 254 | 5322 | : UntypedAttribute(std::move(view), Check(column)) {} | |
| 255 | |||
| 256 | 180 | void Set(uint32_t index, Span<const T> items) { | |
| 257 | 180 | SetArray(index, AsBytes(items)); | |
| 258 | 179 | } | |
| 259 | |||
| 260 | 18 | void Set(uint32_t index, const std::vector<T>& items) { | |
| 261 | 18 | Set(index, Span<const T>(items)); | |
| 262 | 17 | } | |
| 263 | |||
| 264 | 2494 | std::vector<T> Get(uint32_t index) const { | |
| 265 | 7482 | return Items<T>(GetArray(index)); | |
| 266 | } | ||
| 267 | |||
| 268 | private: | ||
| 269 | 2662 | static ColumnRef Check(ColumnRef column) { | |
| 270 | 2662 | return Checked(column, | |
| 271 | 2662 | IsArray(column.column->type) && ItemBytes(column.column->type) == sizeof(T), | |
| 272 | 2661 | true); | |
| 273 | } | ||
| 274 | }; | ||
| 275 | |||
| 276 | 2662 | template <class T> ArrayAttribute<T> View::GetArray(ColumnRef column) const { | |
| 277 | 2662 | if (!m_state) { | |
| 278 | ✗ | throw Error("An empty view has no attributes"); | |
| 279 | } | ||
| 280 | 7984 | return ArrayAttribute<T>(m_state, column); | |
| 281 | } | ||
| 282 | |||
| 283 | 13587 | template <class T> Attribute<T> View::Get(ColumnRef column) const { | |
| 284 | 13587 | if (!m_state) { | |
| 285 | ✗ | throw Error("An empty view has no attributes"); | |
| 286 | } | ||
| 287 | 40758 | return Attribute<T>(m_state, column); | |
| 288 | } | ||
| 289 | |||
| 290 | 123 | template <class T> auto View::Get(Field<T> field) const { | |
| 291 | 123 | const ColumnRef column = field.Column(); | |
| 292 | if constexpr (std::is_same_v<T, std::string>) { | ||
| 293 | return Get<Token>(column); | ||
| 294 | } else if constexpr (std::is_same_v<T, std::vector<std::string>> || | ||
| 295 | std::is_same_v<T, std::vector<Primvar>>) { | ||
| 296 | 1 | return Get(column); | |
| 297 | } else if constexpr (HasItems<T>::value) { | ||
| 298 | 1 | return GetArray<typename T::value_type>(column); | |
| 299 | } else { | ||
| 300 | 121 | return Get<T>(column); | |
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | } | ||
| 305 |