mitsuba-renderer / enoki

Enoki: structured vectorization and differentiation on modern processor architectures
Other
1.26k stars 94 forks source link

DynamicArray of arbitrary data type. #95

Closed k-sheridan closed 4 years ago

k-sheridan commented 4 years ago

In this section of the documentation we are shown an example of enoki::Array<std::string, 2> which is great. I tried something similar out with a toy example, and it worked using an arbitrary struct.

Then, I went one step further and wrapped the array of my struct with an enoki::DynamicArray.

struct MyData {
      float x, y, z;
      double t;
};
enoki::Array<MyData, 4> staticData; // works
enoki::DynamicArray<enoki::Array<MyData, 4>> dynamicData; // does not work

I wind up with this compiler error:

/Users/.../enoki/include/enoki/array_traits.h:495:1: error: no type named 'UInt' in 'enoki::detail::type_chooser<24>'
using uint_array_t = replace_scalar_t<T, typename detail::type_chooser<sizeof(scalar_t<T>)>::UInt, CopyFlags>;
^~~~~
/Users/.../enoki/include/enoki/dynamic.h:63:49: note: in instantiation of template type alias 'uint_array_t' requested here
    using IndexPacket                         = uint_array_t<array_t<Packet_>, false>;
                                                ^
/Users/.../enoki/include/enoki/dynamic.h:967:23: note: in instantiation of template class 'enoki::DynamicArrayImpl<enoki::Array<MyData, 4>, enoki::DynamicArray<enoki::Array<MyData, 4> > >' requested
      here
struct DynamicArray : DynamicArrayImpl<Packet_, DynamicArray<Packet_>> {
                      ^
/Users/.../TestEnoki.cpp:88:48: note: in instantiation of template class 'enoki::DynamicArray<enoki::Array<MyData, 4> >' requested here
  enoki::DynamicArray<enoki::Array<MyData, 4>> dynamicData;

It looks like the root of this problem is that enoki can't find a 24 (sizeof(MyData)) byte "UInt" equivalent for an Index?

I understand that enoki is not meant for this type of application, and in this case, I should be using a SoA layout for MyData, but this is just a toy example.

I would like to do this because there are many thirdparty data types that I use which provide functionality I need with their member functions. A good example is Eigen::Matrix<double, 6, 6> which enoki does not have a replacement for, and is internally stored as a single static array.

I hoped to use enoki to easily get a SoA layout for a struct containing MyData while also applying enoki's vectorized operations on other data types in the struct.

Something like this

template <typename Value>
struct Parent {
using MyDataP = enoki::replace_scalar_t<Value, MyData>;
using FloatP = float32_array_t<Value>;

// I want this struct to be stored as AoS and available via enoki::slice().
MyDataP d;
// I want to apply vectorized operations on these.
FloatP a, b;

ENOKI_STRUCT(Parent, d,a,b )
};
ENOKI_STRUCT_SUPPORT(PARENT, d,a,b)

// Ultimately I'd like this.
using ParentX = Parent<enoki::DynamicArray<enoki::packet<float>>>;

I tried crawling my way through the error, but can't find a good way around this issue other than using 'enoki::DynamicArray<enoki::Array<MyData*, 4>>'. This solution is not ideal because as far as I can tell, I would be expected to handle allocations externally for MyData.

Is this by design, or is there a work around? I really like the design of enoki, and I would love to use it for my project.

k-sheridan commented 4 years ago

Maybe the solution is to make a specialized version of enoki::DynamicArray? After sneaking my way past the type_chooser error and just making enoki::scalar_t<MyData> = float, I wound up finding that set_slices doesn't work because it is using operations for masking and intialization that MyData doesn't support.

Example: https://github.com/mitsuba-renderer/enoki/blob/master/include/enoki/dynamic.h#L810

So, I'll try making a limited version of enoki::DynamicArrayImpl which is enabled if I pass a type that is not supported. All I really want is to have the data laid out contiguously in its own array and available to be through enoki::slice() and enoki::packet.

k-sheridan commented 4 years ago

I got this working in an unclean way (https://github.com/k-sheridan/enoki/pull/1). I would appreciate some suggestions on how to make this work in a nicer way.

From what I can tell, this shouldn't be a problem as long as I just access this array through enoki::slice() or enoki::packet(). Masked operations don't seem like they will work, but that was never my intention.