blob: a3f1f03048dc62ecbd8aa378c3cd99dc92782017 [file] [log] [blame]
#include <iostream>
#include "Halide.h"
#define CHECK(x, message, ...) \
do { \
if (!(x)) { \
fprintf(stderr, "assertion failed: " message ": %s\n", ##__VA_ARGS__, \
#x); \
abort(); \
} \
} while (0)
// This is a Halide "generator". This means it is a binary which generates
// ahead-of-time optimized functions as directed by command-line arguments.
// https://halide-lang.org/tutorials/tutorial_lesson_15_generators.html has an
// introduction to much of the magic in this file.
namespace frc971::orin {
namespace {
template <typename T>
void SetRowMajor(T *buffer_parameter, int cols, int rows, int channels) {
buffer_parameter->dim(0).set_stride(channels);
buffer_parameter->dim(0).set_extent(cols);
buffer_parameter->dim(0).set_min(0);
buffer_parameter->dim(1).set_stride(cols * channels);
buffer_parameter->dim(1).set_extent(rows);
buffer_parameter->dim(1).set_min(0);
buffer_parameter->dim(2).set_stride(1);
buffer_parameter->dim(2).set_extent(channels);
buffer_parameter->dim(2).set_min(0);
}
} // namespace
// Takes an image with y in one plane with a provided stride, and cbcr in
// another with a provided stride and makes a ycbcr output image.
class YCbCr : public Halide::Generator<YCbCr> {
public:
GeneratorParam<int> cols{"cols", 0};
GeneratorParam<int> rows{"rows", 0};
GeneratorParam<int> ystride{"ystride", 0};
GeneratorParam<int> cbcrstride{"cbcrstride", 0};
Input<Buffer<uint8_t, 2>> input_y{"y"};
Input<Buffer<uint8_t, 3>> input_cbcr{"cbcr"};
Output<Buffer<uint8_t, 3>> output{"output"};
Var col{"col"}, row{"row"}, channel{"channel"};
// Everything is indexed as col, row, channel.
void generate() {
CHECK(cols > 0, "Must specify a cols");
CHECK(rows > 0, "Must specify a rows");
input_y.dim(0).set_stride(1);
input_y.dim(0).set_extent(cols);
input_y.dim(0).set_min(0);
input_y.dim(1).set_stride(ystride);
input_y.dim(1).set_extent(rows);
input_y.dim(1).set_min(0);
input_cbcr.dim(0).set_stride(2);
input_cbcr.dim(0).set_extent(cols);
input_cbcr.dim(0).set_min(0);
input_cbcr.dim(1).set_stride(cbcrstride);
input_cbcr.dim(1).set_extent(rows);
input_cbcr.dim(1).set_min(0);
input_cbcr.dim(2).set_stride(1);
input_cbcr.dim(2).set_extent(2);
input_cbcr.dim(2).set_min(0);
output(col, row, channel) =
Halide::select(channel == 0, input_y(col, row),
Halide::select(channel == 1, input_cbcr(col, row, 0),
input_cbcr(col, row, 1)));
output.reorder(channel, col, row);
output.unroll(channel);
output.vectorize(col, 8);
output.unroll(col, 4);
SetRowMajor(&output, cols, rows, 3);
}
};
class YCbCr422 : public Halide::Generator<YCbCr422> {
public:
GeneratorParam<int> cols{"cols", 0};
GeneratorParam<int> rows{"rows", 0};
GeneratorParam<int> ystride{"ystride", 0};
GeneratorParam<int> cbcrstride{"cbcrstride", 0};
Input<Buffer<uint8_t, 2>> input_y{"y"};
Input<Buffer<uint8_t, 3>> input_cbcr{"cbcr"};
Output<Buffer<uint8_t, 3>> output{"output"};
Var col{"col"}, row{"row"}, channel{"channel"};
// Everything is indexed as col, row, channel.
void generate() {
CHECK(cols > 0, "Must specify a cols");
CHECK((cols % 2) == 0, "Must specify a cols with an even number of cols");
CHECK(rows > 0, "Must specify a rows");
input_y.dim(0).set_stride(1);
input_y.dim(0).set_extent(cols);
input_y.dim(0).set_min(0);
input_y.dim(1).set_stride(ystride);
input_y.dim(1).set_extent(rows);
input_y.dim(1).set_min(0);
input_cbcr.dim(0).set_stride(2);
input_cbcr.dim(0).set_extent(cols / 2);
input_cbcr.dim(0).set_min(0);
input_cbcr.dim(1).set_stride(cbcrstride);
input_cbcr.dim(1).set_extent(rows);
input_cbcr.dim(1).set_min(0);
input_cbcr.dim(2).set_stride(1);
input_cbcr.dim(2).set_extent(2);
input_cbcr.dim(2).set_min(0);
output(col, row, channel) = Halide::select(
channel == 0, input_y(col, row), input_cbcr(col / 2, row, col % 2));
output.reorder(channel, col, row);
output.unroll(channel);
output.vectorize(col, 8);
output.unroll(col, 4);
SetRowMajor(&output, cols, rows, 2);
}
};
} // namespace frc971::orin
HALIDE_REGISTER_GENERATOR(frc971::orin::YCbCr, ycbcr)
HALIDE_REGISTER_GENERATOR(frc971::orin::YCbCr422, ycbcr422)