Search code examples
c++halide

How can I write a Generator with an ImageParam that has a type specified as a GeneratorParam?


I would like to implement an image pipeline for various image data types. I am defining a Generator class containing the build() method describing the pipeline, a GeneratorParam<type> to specify the data type parameter and an ImageParam member to specify the input image. If I specify the type of the ImageParam to be the GeneratorParam<Type> that I have defined above, then no matter what type I specify when I execute the generator, the type of the input image is always the default type. If I copy the declaration of the ImageParam inside the body of the build() method, then it seems to be working fine. Is this the correct way to define a pipeline with an input image that can have different types?

Here is the class as I originally wrote it:

#include "Halide.h"

using namespace Halide;

class myGenerator : public Generator<myGenerator>
{
public:
    // Image data type as a parameter of the generator; default: float
    GeneratorParam<Type> datatype{"datatype", Float(32)};

    // Input image to the pipeline
    ImageParam input{datatype, 3, "input"}; // datatype=Float(32) always

    // Pipeline
    Func build()
    {
        // ...
    }
};

If I compile the generator and run it to generate a pipeline for a datatype different from the default:

$ ./myGenerator -f pipeline_uint8 -o . datatype=uint8

Then everything seems fine, but the pipeline crashes at runtime because the buffer that I pass to it is uint8, but it was expecting an image of type float (the default I have specified in the generator class):

Error: Input buffer input has type float32 but elem_size of the buffer passed in is 1 instead of 4

I have fixed the issue by copying the declaration of the ImageParam inside the build() block, but that seems a little bit dirty to me. Is there a better way? Here is the class now:

#include "Halide.h"

using namespace Halide;

class myGenerator : public Generator<myGenerator>
{
public:
    // Image data type as a parameter of the generator; default: float
    GeneratorParam<Type> datatype{"datatype", Float(32)};

    // Input image to the pipeline
    ImageParam input{datatype, 3, "input"};

    // Pipeline
    Func build()
    {
        // Copy declaration. This time, it picks up datatype
        // as being the type inputted when executing the
        // generator instead of using the default.
        ImageParam input{datatype, 3, "input"};

        // ...
    }
};

Thanks.


Solution

  • It is indeed dirty. The current best known solution is reinitializing input with the correct type at the top of build, rather than shadowing it with another ImageParam with the same name:

    Func build() 
    {
        input = ImageParam{datatype, 3, "input"};
        ...
    }