File: truncated_pyramid.cpp

package info (click to toggle)
halide 21.0.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 55,752 kB
  • sloc: cpp: 289,334; ansic: 22,751; python: 7,486; makefile: 4,299; sh: 2,508; java: 1,549; javascript: 282; pascal: 207; xml: 127; asm: 9
file content (78 lines) | stat: -rw-r--r-- 2,716 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "Halide.h"

using namespace Halide;

using std::pair;
using std::vector;

int main(int argc, char **argv) {
    Func input;
    Var x, y;
    input(x, y) = random_float();
    input.compute_root();

    const int levels = 20;

    // Make a laplacian pyramid that truncates at a certain size to
    // probe for compile-time issues with skip stages, allocation
    // bounds inference, etc, arising from deeply nested selects in
    // params. Jam in as many types of if statement as we can.

    Func pyr_down[levels];
    Param<int> width, height;
    vector<pair<Expr, Expr>> sizes(levels);
    sizes[0] = {width, height};
    for (int i = 1; i < levels; i++) {
        sizes[i] = {(sizes[i - 1].first + 1) / 2,
                    (sizes[i - 1].second + 1) / 2};
    }
    pyr_down[0] = input;
    for (int i = 1; i < levels; i++) {
        Func bounded = BoundaryConditions::repeat_edge(pyr_down[i - 1],
                                                       {{0, sizes[i].first}, {0, sizes[i].second}});
        // Some simple stencil that acts like a 4x4 kernel for the purpose of bounds inference.
        Func downsampled;
        downsampled(x, y) = bounded(2 * x - 1, 2 * y - 1) +
                            bounded(2 * x + 2, 2 * y + 2);

        // Only compute it if the pyramid level is large enough.
        pyr_down[i](x, y) = select(max(sizes[i].first, sizes[i].second) > 5,
                                   downsampled(x, y),
                                   0.0f);

        // Specialize it, to introduce another type of condition in the params.
        pyr_down[i]
            .compute_root()
            .specialize(max(width, height) > 32)
            .vectorize(x, 16)
            .parallel(y, 16, TailStrategy::GuardWithIf);
    }

    Func pyr_up[levels];
    pyr_up[levels - 1] = pyr_down[levels - 1];
    for (int i = levels - 2; i >= 0; i--) {
        Func upsample;
        upsample(x, y) = pyr_up[i + 1](x / 2 - 1, y / 2 - 1) +
                         pyr_up[i + 1](x / 2 + 1, y / 2 + 1);

        // Mask it with a select
        pyr_up[i](x, y) = select(max(sizes[i].first, sizes[i].second) > 5,
                                 pyr_down[i](x, y) - upsample(x, y),
                                 pyr_down[i](x, y));

        pyr_up[i]
            .compute_root()
            .specialize(max(width, height) > 32)
            .vectorize(x, 16)
            .parallel(y, 16, TailStrategy::GuardWithIf);
    }

    // It's sufficient to just realize this. Compilation will take the
    // age of the universe if anything combinatorial is going on.
    width.set(1000);
    height.set(1000);
    pyr_up[0].realize({1000, 1000});

    printf("Success!\n");
    return 0;
}