Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENOKI_STRUCT_DYNAMIC with mask member #14

Closed
merlinND opened this issue Jan 3, 2018 · 4 comments
Closed

ENOKI_STRUCT_DYNAMIC with mask member #14

merlinND opened this issue Jan 3, 2018 · 4 comments

Comments

@merlinND
Copy link
Member

merlinND commented Jan 3, 2018

Slicing a dynamically-sized mask (mask_t<FloatX>) returns a float & (see Example 1). This makes sense given that masks are stored using their underlying type's registers and slice needs to return a reference.

But then, in the slicing operator defined by ENOKI_STRUCT_DYNAMIC,

template <typename T>                                                  \
static ENOKI_INLINE auto slice(T &&value, size_t index) {              \
    constexpr static bool co_ = std::is_const<                         \
        std::remove_reference_t<T>>::value;                            \
    using Value = Struct<decltype(enoki::slice(std::declval<           \
        std::conditional_t<co_, const Args &, Args &>>(), index))...>; \
    return Value{ ENOKI_MAP_EXPR_F2(enoki::slice, value, index,        \
                                   __VA_ARGS__) };                     \
}

the following becomes problematic:

MyStruct(
    slice(value.arg1, index), ..., 
    // Trying to initialize a `mask_t<Float &>` with a `Float &`
    slice(value.some_mask, index)
)

Would there be a way to initialize the mask with a reference to the underlying storage directly?
This problem occurs in Mitsuba 2, see Example 2.


Example 1

#include <iostream>
#include <vector>
#include <enoki/array.h>

using namespace enoki;

namespace {
constexpr size_t PacketSize = enoki::max_packet_size / sizeof(float);
using Float    = float;
using FloatP   = Packet<Float, 4>;
using FloatX   = DynamicArray<FloatP>;

template <typename T>
ENOKI_NOINLINE void print(const T &val) {
    std::cout << val << std::endl;
}
}  // namespace

int main() {

    mask_t<FloatX> masks;
    set_slices(masks, 4);
    masks = false; masks[1] = true;

    auto mask = slice(masks, 1);

    print(mask);
    print(typeid(mask).name());

    print(masks.coeff(0));
    print(masks.coeff(1));
    print(typeid(masks.coeff(1)).name());

    return 0;
}

Result:

1
f
0
1
f

Example 2

Usage in Mitsuba 2 that triggers this issue:

// records.h
ENOKI_STRUCT_DYNAMIC(mitsuba::PositionSample, ...)

// Example usage that would trigger compilation error
Position3fX pos;
auto p = slice(pos, 1);

// Actual usage: python/records.cpp
bind_slicing_operators<PositionSample<Point3fX>>();
@wjakob
Copy link
Member

wjakob commented May 13, 2018

Is this still an issue?

@merlinND
Copy link
Member Author

It looks like slice is still causing trouble (not on my machine but on the Xeon Phi, at least): mitsuba-renderer/mitsuba2#77 (comment)

@wjakob
Copy link
Member

wjakob commented May 13, 2018

I think the issue is that you just cannot slice a vectorized data structure with K-style register masks on KNL. I don't think there is a clear way to fix it, since we cannot create references to individual bits.

The only workaround that comes to mind is to not use masks but less efficient bool arrays for storage.

@wjakob
Copy link
Member

wjakob commented Nov 20, 2018

I'll close this issue as slicing K mask registers is now allowed in the C++17 version (you will get a wrapper type that knows how to update the original bit values).

@wjakob wjakob closed this as completed Nov 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants