0

that's my first post here so sorry if I do something wrong:). I will try to do my best.

I currently working on my HDR image processing program, and I wonna implement some basing TMO using Halide. Problem is all my images are represented as float array (with order like: b1,g1,r1,a1, b2,g2,r2,a2, ... ). Using Halide to process image require Halide::Image class. Problem is I don't know how to pass those data there.

Anyone can help, or have same problem and know the answer?

Edit:

Finally got it! I need to set stride on input and output buffer in generator. Thx all for help:-)

Edit:

I tried two different ways:

int halideOperations( float data[] , int size, int width,int heighy ) 
{ 
buffer_t input_buf = { 0 }; 
input_buf.host = &data[0]; 
} 

or:

int halideOperations( float data[] , int size, int width,int heighy ) 
{ 
Halide::Image(Halide::Type::Float, x, y, 0, 0, data);
}

I was thinking about editing Halide.h file and changing uint8_t * host to float_t * host but i don't think it's good idea.

Edit:

I tried using code below with my float image (RGBA):

AOT function generation:

int main(int arg, char ** argv)
{
    Halide::ImageParam img(Halide::type_of<float>(), 3);
    Halide::Func f;
    Halide::Var x, y, c;
    f(x, y, c) = Halide::pow(img(x,y,c), 2.f);

    std::vector<Halide::Argument> arguments = { img };
    f.compile_to_file("function", arguments);
    return 0;
}

Proper code calling:

int halideOperations(float data[], int size, int width, int height)
{
    buffer_t  output_buf = { 0 };
    buffer_t buf = { 0 };
    buf.host = (uint8_t *)data; 
    float * output = new float[width * height * 4];
    output_buf.host = (uint8_t*)(output);
    output_buf.extent[0] = buf.extent[0] = width; 
    output_buf.extent[1] = buf.extent[1] = height; 
    output_buf.extent[2] = buf.extent[2] = 4;
    output_buf.stride[0] = buf.stride[0] = 4;
    output_buf.stride[1] = buf.stride[1] = width * 4;
    output_buf.elem_size = buf.elem_size = sizeof(float);

    function(&buf, &output_buf);

    delete output;
    return 1;
}

unfortunately I got crash with msg:

 Error: Constraint violated: f0.stride.0 (4) == 1 (1)

I think something is wrong with this line: output_buf.stride[0] = buf.stride[0] = 4, but I'm not sure what should I change. Any tips?

  • Hi and welcome! Can you please show us the code you have tried? – rhughes Apr 24 '16 at 11:05
  • I was trying to use buffer_t and normal Halide::Image but both of them use uint8 not float data: int halideOperations( float data[] , int size, int x, int y ) { buffer_t input_buf = { 0 }; input_buf.host = &data[0]; } or: Halide::Image(Halide::Type::Float, x, y, 0, 0, data); – Marcin Kołodziejski Apr 24 '16 at 11:15
  • Thanks. Can you please edit your question to show us your code? – rhughes Apr 24 '16 at 12:17

2 Answers2

1

If you are using buffer_t directly, you must cast the pointer assigned to host to a uint8_t * :

buf.host = (uint8_t *)&data[0]; // Often, can be just "(uint8_t *)data"

This is what you want to do if you are using Ahead-Of-Time (AOT) compilation and the data is not being allocated as part of the code which directly calls Halide. (Other methods discussed below control the storage allocation so they cannot take a pointer that is passed to them.)

If you are using either Halide::Image or Halide::Tools::Image, then the type casting is handled internally. The constructor used above for Halide::Image does't exist as Halide::Image is a template class where the underlying data type is a template parameter:

Halide::Image<float> image_storage(width, height, channels);

Note this will store the data in planar layout. Halide::Tools::Image is similar but has an option to do interleaved layout. (Personally, I try not to use either of these outside of small test programs. There is a long term plan to rationalize all of this which will proceed after the arbitrary dimension buffer_t branch is merged. Note also Halide::Image requires libHalide.a to be linked where Halide::Tools::Image does not and is header file only via including common/halide_image.h .)

There is also the Halide::Buffer class which is a wrapper on buffer_t that is useful in Just-In-Time (JIT) compilation. It can reference passed in storage and is not templated. However my guess is you want to use buffer_t directly and simply need the type cast to assign host. Also be sure to set the elem_size field of buffer_t to "sizeof(float)".

For an interleaved float buffer, you'll end up with something like:

buffer_t buf = {0};
buf.host = (uint8_t *)float_data; // Might also need const_cast
// If the buffer doesn't start at (0, 0), then assign mins
buf.extent[0] = width; // In elements, not bytes
buf.extent[1] = height; // In elements, not bytes
buf.extent[2] = 3; // Assuming RGB
// No need to assign additional extents as they were init'ed to zero above
buf.stride[0] = 3; // RGB interleaved
buf.stride[1] = width * 3; // Assuming no line padding
buf.stride[2] = 1; // Channel interleaved
buf.elem_size = sizeof(float);

You will also need to pay attention to the bounds in the Halide code itself. Probably best to look at the set_stride and bound calls in tutorial/lesson_16_rgb_generate.cpp for information on that.

Zalman Stern
  • 3,161
  • 12
  • 18
0

In addition to Zalman's answer above you also have to specify the strides for the inputs and outputs when defining your Halide function like below:

int main(int arg, char ** argv)
{
    Halide::ImageParam img(Halide::type_of<float>(), 3);
    Halide::Func f;
    Halide::Var x, y, c;
    f(x, y, c) = Halide::pow(img(x,y,c), 2.f);

    // You need the following
    f.set_stride(0, f.output_buffer().extent(2));
    f.set_stride(1, f.output_buffer().extent(0) * f.output_buffer().extent(2));
    img.set_stride(0, img.extent(2));
    img.set_stride(1, img.extent(2) *img.extent(0));
    // <- up to here

    std::vector<Halide::Argument> arguments = { img };
    f.compile_to_file("function", arguments);
    return 0;
}

then your code should run.

Herman
  • 1