2222#include < tev/Common.h>
2323#include < tev/Task.h>
2424
25- #include < nanogui/vector.h>
26-
25+ #include < gch/small_vector.hpp>
2726#include < half.h>
27+ #include < nanogui/vector.h>
2828
2929#include < memory>
3030#include < ranges>
3131#include < span>
3232#include < string>
3333#include < type_traits>
34- #include < vector>
3534
3635namespace tev {
3736
@@ -62,7 +61,7 @@ template <typename T> class ChannelView {
6261public:
6362 ChannelView (const ChannelView<std::remove_const_t <T>>& other)
6463 requires (!std::is_same_v<T, std::remove_const_t <T>>)
65- : ChannelView(other.data(), other.dataStride(), other.dataOffset() , other.size()) {}
64+ : ChannelView(other.data(), other.dataStride(), 0 , other.size()) {}
6665
6766 ChannelView (const ChannelView&) = default ;
6867 ChannelView& operator =(const ChannelView&) = default ;
@@ -71,14 +70,14 @@ template <typename T> class ChannelView {
7170 ChannelView& operator =(ChannelView&&) = default ;
7271
7372 ChannelView (T* data, size_t dataStride, size_t dataOffset, nanogui::Vector2i size) :
74- mData {data}, mDataOffset { dataOffset}, mDataStride {dataStride}, mSize {size} {}
73+ mData {data + dataOffset}, mDataStride {dataStride}, mSize {size} {}
7574
7675 std::conditional_t <std::is_same_v<T, float >, float &, float > operator [](size_t i) const & {
7776 if constexpr (std::is_integral_v<T>) {
78- const auto v = mData [mDataOffset + i * mDataStride ];
77+ const auto v = mData [i * mDataStride ];
7978 return (float )v / (float )std::numeric_limits<T>::max ();
8079 } else {
81- return mData [mDataOffset + i * mDataStride ];
80+ return mData [i * mDataStride ];
8281 }
8382 }
8483
@@ -90,7 +89,7 @@ template <typename T> class ChannelView {
9089 float operator [](int x, int y) const && { return this ->operator [](x, y); }
9190
9291 void setAt (size_t i, float value) const {
93- T& val = mData [mDataOffset + i * mDataStride ];
92+ T& val = mData [i * mDataStride ];
9493 if constexpr (std::is_integral_v<T>) {
9594 if constexpr (std::is_signed_v<T>) {
9695 val = (T)(std::clamp (value, -1 .0f , 1 .0f ) * (float )std::numeric_limits<T>::max () + copysignf (0 .5f , value));
@@ -108,12 +107,10 @@ template <typename T> class ChannelView {
108107
109108 T* data () const & { return mData ; }
110109
111- size_t dataOffset () const { return mDataOffset ; }
112110 size_t dataStride () const { return mDataStride ; }
113111
114112private:
115113 T* mData = nullptr ;
116- size_t mDataOffset = 0 ;
117114 size_t mDataStride = 1 ;
118115 nanogui::Vector2i mSize = {0 };
119116};
@@ -345,6 +342,9 @@ class Channel {
345342 size_t mDataStride ;
346343};
347344
345+ template <typename T> using SmallRgbaVector = gch::small_vector<T, 4 >; // Up to 4 channels should be stored on the stack
346+ inline constexpr detail::to_vector_fn<SmallRgbaVector> toSmallRgbaVector{};
347+
348348template <typename T> class MultiChannelView {
349349public:
350350 MultiChannelView () = delete ;
@@ -354,7 +354,10 @@ template <typename T> class MultiChannelView {
354354 numChannels = dataStride;
355355 }
356356
357- mSize = size;
357+ if (numChannels == 0 ) {
358+ throw std::runtime_error{" MultiChannelView(ptr) must have at least one channel." };
359+ }
360+
358361 for (size_t c = 0 ; c < numChannels; ++c) {
359362 mChannelViews .emplace_back (data, dataStride, c, size);
360363 }
@@ -367,20 +370,20 @@ template <typename T> class MultiChannelView {
367370
368371 MultiChannelView (std::span<Channel> channels)
369372 requires (!std::is_const_v<T>)
370- : MultiChannelView{channels | std::views::transform ([](Channel& c) { return c.view <T>(); }) | to_vector } {}
373+ : MultiChannelView{channels | std::views::transform ([](Channel& c) { return c.view <T>(); }) | toSmallRgbaVector } {}
371374
372375 MultiChannelView (std::span<const Channel> channels)
373376 requires (std::is_const_v<T>)
374- : MultiChannelView{channels | std::views::transform ([](const Channel& c) { return c.view <T>(); }) | to_vector } {}
377+ : MultiChannelView{channels | std::views::transform ([](const Channel& c) { return c.view <T>(); }) | toSmallRgbaVector } {}
375378
376379 MultiChannelView (std::span<const ChannelView<T>> views) : mChannelViews {views.begin (), views.end ()} {
377380 if (mChannelViews .empty ()) {
378- throw std::runtime_error{" MultiChannelView must have at least one channel." };
381+ throw std::runtime_error{" MultiChannelView(span) must have at least one channel." };
379382 }
380383
381- mSize = mChannelViews .front ().size ();
384+ const auto s = mChannelViews .front ().size ();
382385 for (const auto & channel : mChannelViews ) {
383- if (channel.size () != mSize ) {
386+ if (channel.size () != s ) {
384387 throw std::runtime_error{" All channels in a MultiChannelView must have the same size." };
385388 }
386389 }
@@ -392,8 +395,8 @@ template <typename T> class MultiChannelView {
392395 decltype (auto ) operator [](int c, size_t i) const & { return mChannelViews [channelIdx (c)][i]; }
393396 decltype (auto ) operator [](int c, int x, int y) const & { return mChannelViews [channelIdx (c)][x, y]; }
394397
395- float operator [](int c, size_t i) const && { return mChannelViews [channelIdx (c)][i]; }
396- float operator [](int c, int x, int y) const && { return mChannelViews [channelIdx (c)][x, y]; }
398+ auto operator [](int c, size_t i) const && { return mChannelViews [channelIdx (c)][i]; }
399+ auto operator [](int c, int x, int y) const && { return mChannelViews [channelIdx (c)][x, y]; }
397400
398401 void setAt (int c, size_t i, float value) const { mChannelViews [channelIdx (c)].setAt (i, value); }
399402 void setAt (int c, int x, int y, float value) const { mChannelViews [channelIdx (c)].setAt (x, y, value); }
@@ -402,7 +405,8 @@ template <typename T> class MultiChannelView {
402405 const auto & front = mChannelViews .front ();
403406 for (size_t i = 0 ; i < mChannelViews .size (); ++i) {
404407 const auto & channel = mChannelViews [i];
405- if (channel.data () != front.data () || channel.dataOffset () != i || channel.dataStride () != front.dataStride ()) {
408+ const auto offset = channel.data () - front.data ();
409+ if (channel.data () != front.data () || offset != (ptrdiff_t )i || channel.dataStride () != front.dataStride ()) {
406410 return std::nullopt ;
407411 }
408412 }
@@ -420,12 +424,11 @@ template <typename T> class MultiChannelView {
420424 return mChannelViews .front ().data ();
421425 }
422426
423- nanogui::Vector2i size () const { return mSize ; }
427+ nanogui::Vector2i size () const { return mChannelViews . front (). size () ; }
424428 size_t nChannels () const { return mChannelViews .size (); }
425429
426430private:
427- std::vector<ChannelView<T>> mChannelViews ;
428- nanogui::Vector2i mSize = {0 };
431+ SmallRgbaVector<ChannelView<T>> mChannelViews ;
429432};
430433
431434} // namespace tev
0 commit comments