Halide 19.0.0
Halide compiler and libraries
Loading...
Searching...
No Matches
BoundaryConditions.h
Go to the documentation of this file.
1#ifndef HALIDE_BOUNDARY_CONDITIONS_H
2#define HALIDE_BOUNDARY_CONDITIONS_H
3
4/** \file
5 * Support for imposing boundary conditions on Halide::Funcs.
6 */
7
8#include <vector>
9
10#include "Expr.h"
11#include "Func.h"
12#include "Lambda.h"
13
14namespace Halide {
15
16/** namespace to hold functions for imposing boundary conditions on
17 * Halide Funcs.
18 *
19 * All functions in this namespace transform a source Func to a
20 * result Func where the result produces the values of the source
21 * within a given region and a different set of values outside the
22 * given region. A region is an N dimensional box specified by
23 * mins and extents.
24 *
25 * Three areas are defined:
26 * The image is the entire set of values in the region.
27 * The edge is the set of pixels in the image but adjacent
28 * to coordinates that are not
29 * The interior is the image minus the edge (and is undefined
30 * if the extent of any region is 1 or less).
31 *
32 * If the source Func has more dimensions than are specified, the extra ones
33 * are unmodified. Additionally, passing an undefined (default constructed)
34 * 'Expr' for the min and extent of a dimension will keep that dimension
35 * unmodified.
36 *
37 * Numerous options for specifing the outside area are provided,
38 * including replacement with an expression, repeating the edge
39 * samples, mirroring over the edge, and repeating or mirroring the
40 * entire image.
41 *
42 * Using these functions to express your boundary conditions is highly
43 * recommended for correctness and performance. Some of these are hard
44 * to get right. The versions here are both understood by bounds
45 * inference, and also judiciously use the 'likely' intrinsic to minimize
46 * runtime overhead.
47 *
48 */
49namespace BoundaryConditions {
50
51namespace Internal {
52
54 const Expr &a1, const Expr &a2) {
55 collected_args.emplace_back(a1, a2);
56}
57
58template<typename... Args>
60 const Expr &a1, const Expr &a2, Args &&...args) {
61 collected_args.emplace_back(a1, a2);
62 collect_region(collected_args, std::forward<Args>(args)...);
63}
64
65inline const Func &func_like_to_func(const Func &func) {
66 return func;
67}
68
69template<typename T>
71 return lambda(_, func_like(_));
72}
73
74} // namespace Internal
75
76/** Impose a boundary condition such that a given expression is returned
77 * everywhere outside the boundary. Generally the expression will be a
78 * constant, though the code currently allows accessing the arguments
79 * of source.
80 *
81 * An ImageParam, Buffer<T>, or similar can be passed instead of a
82 * Func. If this is done and no bounds are given, the boundaries will
83 * be taken from the min and extent methods of the passed
84 * object. Note that objects are taken by mutable ref. Pipelines
85 * capture Buffers via mutable refs, because running a pipeline might
86 * alter the Buffer metadata (e.g. device allocation state).
87 *
88 * (This is similar to setting GL_TEXTURE_WRAP_* to GL_CLAMP_TO_BORDER
89 * and putting value in the border of the texture.)
90 *
91 * You may pass undefined Exprs for dimensions that you do not wish
92 * to bound.
93 */
94// @{
95Func constant_exterior(const Func &source, const Tuple &value,
96 const Region &bounds);
97Func constant_exterior(const Func &source, const Expr &value,
98 const Region &bounds);
99
100template<typename T>
101HALIDE_NO_USER_CODE_INLINE Func constant_exterior(const T &func_like, const Tuple &value, const Region &bounds) {
102 return constant_exterior(Internal::func_like_to_func(func_like), value, bounds);
103}
104
105template<typename T>
106HALIDE_NO_USER_CODE_INLINE Func constant_exterior(const T &func_like, const Expr &value, const Region &bounds) {
107 return constant_exterior(Internal::func_like_to_func(func_like), value, bounds);
108}
109
110template<typename T>
111HALIDE_NO_USER_CODE_INLINE Func constant_exterior(const T &func_like, const Tuple &value) {
112 Region object_bounds;
113 for (int i = 0; i < func_like.dimensions(); i++) {
114 object_bounds.emplace_back(Expr(func_like.dim(i).min()), Expr(func_like.dim(i).extent()));
115 }
116
117 return constant_exterior(Internal::func_like_to_func(func_like), value, object_bounds);
118}
119template<typename T>
120HALIDE_NO_USER_CODE_INLINE Func constant_exterior(const T &func_like, const Expr &value) {
121 return constant_exterior(func_like, Tuple(value));
122}
123
124template<typename T, typename... Bounds,
125 typename std::enable_if<Halide::Internal::all_are_convertible<Expr, Bounds...>::value>::type * = nullptr>
127 Bounds &&...bounds) {
128 Region collected_bounds;
129 Internal::collect_region(collected_bounds, std::forward<Bounds>(bounds)...);
130 return constant_exterior(Internal::func_like_to_func(func_like), value, collected_bounds);
131}
132template<typename T, typename... Bounds,
133 typename std::enable_if<Halide::Internal::all_are_convertible<Expr, Bounds...>::value>::type * = nullptr>
134HALIDE_NO_USER_CODE_INLINE Func constant_exterior(const T &func_like, const Expr &value,
135 Bounds &&...bounds) {
136 return constant_exterior(func_like, Tuple(value), std::forward<Bounds>(bounds)...);
137}
138// @}
139
140/** Impose a boundary condition such that the nearest edge sample is returned
141 * everywhere outside the given region.
142 *
143 * An ImageParam, Buffer<T>, or similar can be passed instead of a Func. If this
144 * is done and no bounds are given, the boundaries will be taken from the
145 * min and extent methods of the passed object.
146 *
147 * (This is similar to setting GL_TEXTURE_WRAP_* to GL_CLAMP_TO_EDGE.)
148 *
149 * You may pass undefined Exprs for dimensions that you do not wish
150 * to bound.
151 */
152// @{
153Func repeat_edge(const Func &source, const Region &bounds);
154
155template<typename T>
156HALIDE_NO_USER_CODE_INLINE Func repeat_edge(const T &func_like, const Region &bounds) {
157 return repeat_edge(Internal::func_like_to_func(func_like), bounds);
158}
159
160template<typename T>
162 Region object_bounds;
163 for (int i = 0; i < func_like.dimensions(); i++) {
164 object_bounds.emplace_back(Expr(func_like.dim(i).min()), Expr(func_like.dim(i).extent()));
165 }
166
167 return repeat_edge(Internal::func_like_to_func(func_like), object_bounds);
168}
169// @}
170
171/** Impose a boundary condition such that the entire coordinate space is
172 * tiled with copies of the image abutted against each other.
173 *
174 * An ImageParam, Buffer<T>, or similar can be passed instead of a Func. If this
175 * is done and no bounds are given, the boundaries will be taken from the
176 * min and extent methods of the passed object.
177 *
178 * (This is similar to setting GL_TEXTURE_WRAP_* to GL_REPEAT.)
179 *
180 * You may pass undefined Exprs for dimensions that you do not wish
181 * to bound.
182 */
183// @{
184Func repeat_image(const Func &source, const Region &bounds);
185
186template<typename T>
187HALIDE_NO_USER_CODE_INLINE Func repeat_image(const T &func_like, const Region &bounds) {
188 return repeat_image(Internal::func_like_to_func(func_like), bounds);
189}
190
191template<typename T>
193 Region object_bounds;
194 for (int i = 0; i < func_like.dimensions(); i++) {
195 object_bounds.emplace_back(Expr(func_like.dim(i).min()), Expr(func_like.dim(i).extent()));
196 }
197
198 return repeat_image(Internal::func_like_to_func(func_like), object_bounds);
199}
200
201/** Impose a boundary condition such that the entire coordinate space is
202 * tiled with copies of the image abutted against each other, but mirror
203 * them such that adjacent edges are the same.
204 *
205 * An ImageParam, Buffer<T>, or similar can be passed instead of a Func. If this
206 * is done and no bounds are given, the boundaries will be taken from the
207 * min and extent methods of the passed object.
208 *
209 * (This is similar to setting GL_TEXTURE_WRAP_* to GL_MIRRORED_REPEAT.)
210 *
211 * You may pass undefined Exprs for dimensions that you do not wish
212 * to bound.
213 */
214// @{
215Func mirror_image(const Func &source, const Region &bounds);
216
217template<typename T>
218HALIDE_NO_USER_CODE_INLINE Func mirror_image(const T &func_like, const Region &bounds) {
219 return mirror_image(Internal::func_like_to_func(func_like), bounds);
220}
221
222template<typename T>
224 Region object_bounds;
225 for (int i = 0; i < func_like.dimensions(); i++) {
226 object_bounds.emplace_back(Expr(func_like.dim(i).min()), Expr(func_like.dim(i).extent()));
227 }
228
229 return mirror_image(Internal::func_like_to_func(func_like), object_bounds);
230}
231
232// @}
233
234/** Impose a boundary condition such that the entire coordinate space is
235 * tiled with copies of the image abutted against each other, but mirror
236 * them such that adjacent edges are the same and then overlap the edges.
237 *
238 * This produces an error if any extent is 1 or less. (TODO: check this.)
239 *
240 * An ImageParam, Buffer<T>, or similar can be passed instead of a Func. If this
241 * is done and no bounds are given, the boundaries will be taken from the
242 * min and extent methods of the passed object.
243 *
244 * (I do not believe there is a direct GL_TEXTURE_WRAP_* equivalent for this.)
245 *
246 * You may pass undefined Exprs for dimensions that you do not wish
247 * to bound.
248 */
249// @{
250Func mirror_interior(const Func &source, const Region &bounds);
251
252template<typename T>
253HALIDE_NO_USER_CODE_INLINE Func mirror_interior(const T &func_like, const Region &bounds) {
254 return mirror_interior(Internal::func_like_to_func(func_like), bounds);
255}
256
257template<typename T>
259 Region object_bounds;
260 for (int i = 0; i < func_like.dimensions(); i++) {
261 object_bounds.emplace_back(Expr(func_like.dim(i).min()), Expr(func_like.dim(i).extent()));
262 }
263
264 return mirror_interior(Internal::func_like_to_func(func_like), object_bounds);
265}
266
267// @}
268
269} // namespace BoundaryConditions
270
271} // namespace Halide
272
273#endif
Base classes for Halide expressions (Halide::Expr) and statements (Halide::Internal::Stmt)
Defines Func - the front-end handle on a halide function, and related classes.
Convenience functions for creating small anonymous Halide functions.
#define HALIDE_NO_USER_CODE_INLINE
Definition Util.h:47
A halide function.
Definition Func.h:700
Create a small array of Exprs for defining and calling functions with multiple outputs.
Definition Tuple.h:18
HALIDE_NO_USER_CODE_INLINE void collect_region(Region &collected_args, const Expr &a1, const Expr &a2)
const Func & func_like_to_func(const Func &func)
Func repeat_edge(const Func &source, const Region &bounds)
Impose a boundary condition such that the nearest edge sample is returned everywhere outside the give...
Func repeat_image(const Func &source, const Region &bounds)
Impose a boundary condition such that the entire coordinate space is tiled with copies of the image a...
Func mirror_interior(const Func &source, const Region &bounds)
Impose a boundary condition such that the entire coordinate space is tiled with copies of the image a...
Func constant_exterior(const Func &source, const Tuple &value, const Region &bounds)
Impose a boundary condition such that a given expression is returned everywhere outside the boundary.
Func mirror_image(const Func &source, const Region &bounds)
Impose a boundary condition such that the entire coordinate space is tiled with copies of the image a...
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
@ Internal
Not visible externally, similar to 'static' linkage in C.
Func lambda(const Expr &e)
Create a zero-dimensional halide function that returns the given expression.
std::vector< Range > Region
A multi-dimensional box.
Definition Expr.h:350
A fragment of Halide syntax.
Definition Expr.h:258