// Halide tutorial lesson 6: Realizing Funcs over arbitrary domains
// This lesson demonstrates how to evaluate a Func over a domain that
// does not start at (0, 0).
// On linux, you can compile and run it like so:
// g++ lesson_06*.cpp -g -I <path/to/Halide.h> -L <path/to/libHalide.so> -lHalide -lpthread -ldl -o lesson_06 -std=c++17
// LD_LIBRARY_PATH=<path/to/libHalide.so> ./lesson_06
// On os x:
// g++ lesson_06*.cpp -g -I <path/to/Halide.h> -L <path/to/libHalide.so> -lHalide -o lesson_06 -std=c++17
// DYLD_LIBRARY_PATH=<path/to/libHalide.dylib> ./lesson_06
// If you have the entire Halide source tree, you can also build it by
// running:
// make tutorial_lesson_06_realizing_over_shifted_domains
// in a shell with the current directory at the top of the halide
// source tree.
#include "Halide.h"
#include <stdio.h>
using namespace Halide;
int main(int argc, char **argv) {
// The last lesson was quite involved, and scheduling complex
// multi-stage pipelines is ahead of us. As an interlude, let's
// consider something easy: evaluating funcs over rectangular
// domains that do not start at the origin.
// We define our familiar gradient function.
Func gradient("gradient");
Var x("x"), y("y");
gradient(x, y) = x + y;
// And turn on tracing so we can see how it is being evaluated.
// Previously we've realized gradient like so:
// gradient.realize({8, 8});
// This does three things internally:
// 1) Generates code that can evaluate gradient over an arbitrary
// rectangle.
// 2) Allocates a new 8 x 8 image.
// 3) Runs the generated code to evaluate gradient for all x, y
// from (0, 0) to (7, 7) and puts the result into the image.
// 4) Returns the new image as the result of the realize call.
// What if we're managing memory carefully and don't want Halide
// to allocate a new image for us? We can call realize another
// way. We can pass it an image we would like it to fill in. The
// following evaluates our Func into an existing image:
printf("Evaluating gradient from (0, 0) to (7, 7)\n");
Buffer<int> result(8, 8);
// Let's check it did what we expect:
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
if (result(x, y) != x + y) {
printf("Something went wrong!\n");
return -1;
// Now let's evaluate gradient over a 5 x 7 rectangle that starts
// somewhere else -- at position (100, 50). So x and y will run
// from (100, 50) to (104, 56) inclusive.
// We start by creating an image that represents that rectangle:
Buffer<int> shifted(5, 7); // In the constructor we tell it the size.
shifted.set_min(100, 50); // Then we tell it the top-left corner.
printf("Evaluating gradient from (100, 50) to (104, 56)\n");
// Note that this won't need to compile any new code, because when
// we realized it the first time, we generated code capable of
// evaluating gradient over an arbitrary rectangle.
// From C++, we also access the image object using coordinates
// that start at (100, 50).
for (int y = 50; y < 57; y++) {
for (int x = 100; x < 105; x++) {
if (shifted(x, y) != x + y) {
printf("Something went wrong!\n");
return -1;
// The image 'shifted' stores the value of our Func over a domain
// that starts at (100, 50), so asking for shifted(0, 0) would in
// fact read out-of-bounds and probably crash.
// What if we want to evaluate our Func over some region that
// isn't rectangular? Too bad. Halide only does rectangles :)
return 0;
A Halide variable, to be used when defining functions.
Definition: Var.h:19
Realization realize(std::vector< int32_t > sizes={}, const Target &target=Target(), const ParamMap &param_map=ParamMap::empty_map())
Evaluate this function over some rectangular domain and return the resulting buffer or buffers.
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
A Halide::Buffer is a named shared reference to a Halide::Runtime::Buffer.
Definition: Argument.h:16
A halide function.
Definition: Func.h:687
Func & trace_stores()
Trace all stores to the buffer backing this Func by emitting calls to halide_trace.