1 // Copyright 2008-present Contributors to the OpenImageIO project.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // https://github.com/OpenImageIO/oiio/blob/master/LICENSE.md
4 
5 // clang-format off
6 
7 #pragma once
8 
9 #include <functional>
10 
11 #include <OpenImageIO/parallel.h>
12 #include <OpenImageIO/imagebufalgo.h>
13 
14 
15 
16 OIIO_NAMESPACE_BEGIN
17 
18 using std::bind;
19 using std::ref;
20 using std::cref;
21 using namespace std::placeholders;
22 using std::placeholders::_1;
23 
24 
25 namespace ImageBufAlgo {
26 
27 
28 
29 /// Helper template for generalized multithreading for image processing
30 /// functions.  Some function/functor f is applied to every pixel the
31 /// region of interest roi, dividing the region into multiple threads if
32 /// threads != 1.  Note that threads == 0 indicates that the number of
33 /// threads should be as set by the global OIIO "threads" attribute.
34 ///
35 /// The optional splitdir determines along which axis the split will be
36 /// made. The default is Split_Y (vertical splits), which generally seems
37 /// the fastest (due to cache layout issues?), but perhaps there are
38 /// algorithms where it's better to split in X, Z, or along the longest
39 /// axis.
40 ///
41 /// Most image operations will require additional arguments, including
42 /// additional input and output images or other parameters.  The
43 /// parallel_image template can still be used by employing the
44 /// std::bind. For example, suppose you have an image operation defined as:
45 ///     void my_image_op (ImageBuf &out, const ImageBuf &in,
46 ///                       float scale, ROI roi);
47 /// Then you can parallelize it as follows:
48 ///     ImageBuf R, A;   // result, input
49 ///     ROI roi = get_roi (R.spec());
50 ///     parallel_image (bind(my_image_op,ref(R), cref(A),3.14,_1), roi);
51 inline void
parallel_image(ROI roi,parallel_image_options opt,std::function<void (ROI)> f)52 parallel_image (ROI roi, parallel_image_options opt,
53                 std::function<void(ROI)> f)
54 {
55     opt.resolve ();
56     // Try not to assign a thread less than 16k pixels, or it's not worth
57     // the thread startup/teardown cost.
58     opt.maxthreads = std::min (opt.maxthreads, 1 + int(roi.npixels() / opt.minitems));
59     if (opt.singlethread()) {
60         // Just one thread, or a small image region, or if recursive use of
61         // parallel_image is disallowed: use this thread only
62         f (roi);
63         return;
64     }
65 
66     // If splitdir was not explicit, find the longest edge.
67     SplitDir splitdir = opt.splitdir;
68     if (splitdir == Split_Biggest)
69         splitdir = roi.width() > roi.height() ? Split_X : Split_Y;
70 
71     int64_t xchunk = 0, ychunk = 0;
72     if (splitdir == Split_Y) {
73         xchunk = roi.width();
74         // ychunk = std::max (64, minitems/xchunk);
75     } else if (splitdir == Split_X) {
76         ychunk = roi.height();
77         // ychunk = std::max (64, minitems/xchunk);
78     } else if (splitdir == Split_Tile) {
79         int64_t n = std::min<imagesize_t>(opt.minitems, roi.npixels());
80         xchunk = ychunk = std::max (1, int(std::sqrt(n))/4);
81     } else {
82         xchunk = ychunk = std::max (int64_t(1), int64_t(std::sqrt(opt.maxthreads))/2);
83     }
84 
85     auto task = [&](int /*id*/, int64_t xbegin, int64_t xend,
86                     int64_t ybegin, int64_t yend) {
87         f (ROI (xbegin, xend, ybegin, yend, roi.zbegin, roi.zend,
88                 roi.chbegin, roi.chend));
89     };
90     parallel_for_chunked_2D (roi.xbegin, roi.xend, xchunk,
91                              roi.ybegin, roi.yend, ychunk, task, opt);
92 }
93 
94 
95 inline void
parallel_image(ROI roi,std::function<void (ROI)> f)96 parallel_image (ROI roi, std::function<void(ROI)> f)
97 {
98     parallel_image (roi, parallel_image_options(), f);
99 }
100 
101 
102 
103 // DEPRECATED(1.8) -- eventually enable the OIIO_DEPRECATION
104 template <class Func>
105 // OIIO_DEPRECATED("switch to new parallel_image (1.8)")
106 void
107 parallel_image (Func f, ROI roi, int nthreads=0, SplitDir splitdir=Split_Y)
108 {
109     parallel_image (roi, parallel_image_options (nthreads, splitdir), f);
110 }
111 
112 
113 
114 /// Common preparation for IBA functions: Given an ROI (which may or may not
115 /// be the default ROI::All()), destination image (which may or may not yet
116 /// be allocated), and optional input images, adjust roi if necessary and
117 /// allocate pixels for dst if necessary.  If dst is already initialized, it
118 /// will keep its "full" (aka display) window, otherwise its full/display
119 /// window will be set to the union of A's and B's full/display windows.  If
120 /// dst is uninitialized and  force_spec is not NULL, use *force_spec as
121 /// dst's new spec rather than using A's.  Also, if A or B inputs are
122 /// specified but not initialized or broken, it's an error so return false.
123 /// If all is ok, return true.  Some additional checks and behaviors may be
124 /// specified by the 'prepflags', which is a bit field defined by
125 /// IBAprep_flags.
126 bool OIIO_API IBAprep (ROI &roi, ImageBuf *dst, const ImageBuf *A=NULL,
127                        const ImageBuf *B=NULL, const ImageBuf *C=NULL,
128                        ImageSpec *force_spec=NULL, int prepflags=0);
129 inline bool IBAprep (ROI &roi, ImageBuf *dst, const ImageBuf *A,
130                      const ImageBuf *B, ImageSpec *force_spec,
131                      int prepflags=0) {
132     return IBAprep (roi, dst, A, B, NULL, force_spec, prepflags);
133 }
IBAprep(ROI & roi,ImageBuf * dst,const ImageBuf * A,const ImageBuf * B,int prepflags)134 inline bool IBAprep (ROI &roi, ImageBuf *dst,
135                      const ImageBuf *A, const ImageBuf *B, int prepflags) {
136     return IBAprep (roi, dst, A, B, NULL, NULL, prepflags);
137 }
IBAprep(ROI & roi,ImageBuf * dst,const ImageBuf * A,int prepflags)138 inline bool IBAprep (ROI &roi, ImageBuf *dst,
139                      const ImageBuf *A, int prepflags) {
140     return IBAprep (roi, dst, A, NULL, NULL, NULL, prepflags);
141 }
142 
143 enum IBAprep_flags {
144     IBAprep_DEFAULT = 0,
145     IBAprep_REQUIRE_ALPHA = 1<<0,
146     IBAprep_REQUIRE_Z = 1<<1,
147     IBAprep_REQUIRE_SAME_NCHANNELS = 1<<2,
148     IBAprep_NO_COPY_ROI_FULL = 1<<3,    // Don't copy the src's roi_full
149     IBAprep_NO_SUPPORT_VOLUME = 1<<4,   // Don't know how to do volumes
150     IBAprep_NO_COPY_METADATA = 1<<8,    // N.B. default copies all metadata
151     IBAprep_COPY_ALL_METADATA = 1<<9,   // Even unsafe things
152     IBAprep_CLAMP_MUTUAL_NCHANNELS = 1<<10, // Clamp roi.chend to min of inputs
153     IBAprep_SUPPORT_DEEP = 1<<11,       // Operation allows deep images
154     IBAprep_DEEP_MIXED = 1<<12,         // Allow deep & non-deep combinations
155     IBAprep_DST_FLOAT_PIXELS = 1<<13,   // If dst is uninit, make it float
156     IBAprep_MINIMIZE_NCHANNELS = 1<<14, // Multi-inputs get min(nchannels)
157     IBAprep_REQUIRE_MATCHING_CHANNELS = 1<<15, // Channel names must match
158     IBAprep_MERGE_METADATA = 1 << 16,   // Merge all inputs' metadata
159 };
160 
161 
162 
163 // DEPRECATED(2.3): Prefer TypeDesc::basetype_merge().
164 TypeDesc::BASETYPE OIIO_API type_merge (TypeDesc::BASETYPE a, TypeDesc::BASETYPE b);
165 
166 // DEPRECATED(2.3): Prefer TypeDesc::basetype_merge().
type_merge(TypeDesc a,TypeDesc b)167 inline TypeDesc type_merge (TypeDesc a, TypeDesc b) {
168     return TypeDesc::basetype_merge(a, b);
169 }
170 
171 // DEPRECATED(2.3): Prefer TypeDesc::basetype_merge().
type_merge(TypeDesc a,TypeDesc b,TypeDesc c)172 inline TypeDesc type_merge (TypeDesc a, TypeDesc b, TypeDesc c)
173 {
174     return TypeDesc::basetype_merge(TypeDesc::basetype_merge(a,b), c);
175 }
176 
177 
178 
179 // Macro to call a type-specialzed version func<type>(R,...)
180 #define OIIO_DISPATCH_TYPES(ret,name,func,type,R,...)                   \
181     switch (type.basetype) {                                            \
182     case TypeDesc::FLOAT :                                              \
183         ret = func<float> (R, __VA_ARGS__); break;                      \
184     case TypeDesc::UINT8 :                                              \
185         ret = func<unsigned char> (R, __VA_ARGS__); break;              \
186     case TypeDesc::HALF  :                                              \
187         ret = func<half> (R, __VA_ARGS__); break;                       \
188     case TypeDesc::UINT16:                                              \
189         ret = func<unsigned short> (R, __VA_ARGS__); break;             \
190     case TypeDesc::INT8  :                                              \
191         ret = func<char> (R, __VA_ARGS__); break;                       \
192     case TypeDesc::INT16 :                                              \
193         ret = func<short> (R, __VA_ARGS__); break;                      \
194     case TypeDesc::UINT  :                                              \
195         ret = func<unsigned int> (R, __VA_ARGS__); break;               \
196     case TypeDesc::INT   :                                              \
197         ret = func<int> (R, __VA_ARGS__); break;                        \
198     case TypeDesc::DOUBLE:                                              \
199         ret = func<double> (R, __VA_ARGS__); break;                     \
200     default:                                                            \
201         (R).errorf("%s: Unsupported pixel data format '%s'", name, type); \
202         ret = false;                                                    \
203     }
204 
205 // Helper, do not call from the outside world.
206 #define OIIO_DISPATCH_TYPES2_HELP(ret,name,func,Rtype,Atype,R,...)      \
207     switch (Atype.basetype) {                                           \
208     case TypeDesc::FLOAT :                                              \
209         ret = func<Rtype,float> (R, __VA_ARGS__); break;                \
210     case TypeDesc::UINT8 :                                              \
211         ret = func<Rtype,unsigned char> (R, __VA_ARGS__); break;        \
212     case TypeDesc::HALF  :                                              \
213         ret = func<Rtype,half> (R, __VA_ARGS__); break;                 \
214     case TypeDesc::UINT16:                                              \
215         ret = func<Rtype,unsigned short> (R, __VA_ARGS__); break;       \
216     case TypeDesc::INT8 :                                               \
217         ret = func<Rtype,char> (R, __VA_ARGS__); break;                 \
218     case TypeDesc::INT16 :                                              \
219         ret = func<Rtype,short> (R, __VA_ARGS__); break;                \
220     case TypeDesc::UINT :                                               \
221         ret = func<Rtype,unsigned int> (R, __VA_ARGS__); break;         \
222     case TypeDesc::INT :                                                \
223         ret = func<Rtype,int> (R, __VA_ARGS__); break;                  \
224     case TypeDesc::DOUBLE :                                             \
225         ret = func<Rtype,double> (R, __VA_ARGS__); break;               \
226     default:                                                            \
227         (R).errorf("%s: Unsupported pixel data format '%s'", name, Atype); \
228         ret = false;                                                    \
229     }
230 
231 // Macro to call a type-specialzed version func<Rtype,Atype>(R,...).
232 #define OIIO_DISPATCH_TYPES2(ret,name,func,Rtype,Atype,R,...)           \
233     switch (Rtype.basetype) {                                           \
234     case TypeDesc::FLOAT :                                              \
235         OIIO_DISPATCH_TYPES2_HELP(ret,name,func,float,Atype,R,__VA_ARGS__); \
236         break;                                                          \
237     case TypeDesc::UINT8 :                                              \
238         OIIO_DISPATCH_TYPES2_HELP(ret,name,func,unsigned char,Atype,R,__VA_ARGS__); \
239         break;                                                          \
240     case TypeDesc::HALF  :                                              \
241         OIIO_DISPATCH_TYPES2_HELP(ret,name,func,half,Atype,R,__VA_ARGS__);  \
242         break;                                                          \
243     case TypeDesc::UINT16:                                              \
244         OIIO_DISPATCH_TYPES2_HELP(ret,name,func,unsigned short,Atype,R,__VA_ARGS__); \
245         break;                                                          \
246     case TypeDesc::INT8:                                                \
247         OIIO_DISPATCH_TYPES2_HELP(ret,name,func,char,Atype,R,__VA_ARGS__);  \
248         break;                                                          \
249     case TypeDesc::INT16:                                               \
250         OIIO_DISPATCH_TYPES2_HELP(ret,name,func,short,Atype,R,__VA_ARGS__); \
251         break;                                                          \
252     case TypeDesc::UINT:                                                \
253         OIIO_DISPATCH_TYPES2_HELP(ret,name,func,unsigned int,Atype,R,__VA_ARGS__); \
254         break;                                                          \
255     case TypeDesc::INT:                                                 \
256         OIIO_DISPATCH_TYPES2_HELP(ret,name,func,int,Atype,R,__VA_ARGS__); \
257         break;                                                          \
258     case TypeDesc::DOUBLE:                                              \
259         OIIO_DISPATCH_TYPES2_HELP(ret,name,func,double,Atype,R,__VA_ARGS__);\
260         break;                                                          \
261     default:                                                            \
262         (R).errorf("%s: Unsupported pixel data format '%s'", name, Rtype); \
263         ret = false;                                                    \
264     }
265 
266 
267 // Macro to call a type-specialzed version func<type>(R,...) for
268 // the most common types, will auto-convert the rest to float.
269 #define OIIO_DISPATCH_COMMON_TYPES(ret,name,func,type,R,...)            \
270     switch (type.basetype) {                                            \
271     case TypeDesc::FLOAT :                                              \
272         ret = func<float> (R, __VA_ARGS__); break;                      \
273     case TypeDesc::UINT8 :                                              \
274         ret = func<unsigned char> (R, __VA_ARGS__); break;              \
275     case TypeDesc::HALF  :                                              \
276         ret = func<half> (R, __VA_ARGS__); break;                       \
277     case TypeDesc::UINT16:                                              \
278         ret = func<unsigned short> (R, __VA_ARGS__); break;             \
279     default: {                                                          \
280         /* other types: punt and convert to float, then copy back */    \
281         ImageBuf Rtmp;                                                  \
282         if ((R).initialized())                                          \
283             Rtmp.copy (R, TypeDesc::FLOAT);                             \
284         ret = func<float> (Rtmp, __VA_ARGS__);                          \
285         if (ret)                                                        \
286             (R).copy (Rtmp);                                            \
287         else                                                            \
288             (R).errorf("%s", Rtmp.geterror());                          \
289         }                                                               \
290     }
291 
292 // Helper, do not call from the outside world.
293 #define OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,Rtype,Atype,R,A,...) \
294     switch (Atype.basetype) {                                           \
295     case TypeDesc::FLOAT :                                              \
296         ret = func<Rtype,float> (R, A, __VA_ARGS__); break;             \
297     case TypeDesc::UINT8 :                                              \
298         ret = func<Rtype,unsigned char> (R, A, __VA_ARGS__); break;     \
299     case TypeDesc::HALF  :                                              \
300         ret = func<Rtype,half> (R, A, __VA_ARGS__); break;              \
301     case TypeDesc::UINT16:                                              \
302         ret = func<Rtype,unsigned short> (R, A, __VA_ARGS__); break;    \
303     default: {                                                          \
304         /* other types: punt and convert to float, then copy back */    \
305         ImageBuf Atmp;                                                  \
306         Atmp.copy (A, TypeDesc::FLOAT);                                 \
307         ret = func<Rtype,float> (R, Atmp, __VA_ARGS__);                 \
308         }                                                               \
309     }
310 
311 // Macro to call a type-specialzed version func<Rtype,Atype>(R,A,...) for
312 // the most common types, and even for uncommon types when src and dst types
313 // are identical. It will auto-convert remaining rare cases to float.
314 #define OIIO_DISPATCH_COMMON_TYPES2(ret,name,func,Rtype,Atype,R,A,...)  \
315     if (Rtype == Atype) {                                               \
316         /* All data types, when Rtype == Atype */                       \
317         switch (Atype.basetype) {                                       \
318         case TypeDesc::FLOAT :                                          \
319             ret = func<float,float> (R, A, __VA_ARGS__); break;         \
320         case TypeDesc::UINT8 :                                          \
321             ret = func<uint8_t,uint8_t> (R, A, __VA_ARGS__); break;     \
322         case TypeDesc::UINT16:                                          \
323             ret = func<uint16_t,uint16_t> (R, A, __VA_ARGS__); break;   \
324         case TypeDesc::HALF  :                                          \
325             ret = func<half,half> (R, A, __VA_ARGS__); break;           \
326         case TypeDesc::INT8 :                                           \
327             ret = func<char,char> (R, A, __VA_ARGS__); break;           \
328         case TypeDesc::INT16 :                                          \
329             ret = func<short,short> (R, A, __VA_ARGS__); break;         \
330         case TypeDesc::UINT :                                           \
331             ret = func<uint32_t,uint32_t> (R, A, __VA_ARGS__); break;   \
332         case TypeDesc::INT :                                            \
333             ret = func<int,int> (R, A, __VA_ARGS__); break;             \
334         case TypeDesc::DOUBLE :                                         \
335             ret = func<double,double> (R, A, __VA_ARGS__); break;       \
336         default:                                                        \
337             (R).errorf("%s: Unsupported pixel data format '%s'", name, Atype); \
338             ret = false;                                                \
339         }                                                               \
340     } else {                                                            \
341         /* When Rtype != Atype, handle the common pairs */              \
342         switch (Rtype.basetype) {                                       \
343         case TypeDesc::FLOAT :                                          \
344             OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,float,Atype,R,A,__VA_ARGS__); \
345             break;                                                      \
346         case TypeDesc::UINT8 :                                          \
347             OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,uint8_t,Atype,R,A,__VA_ARGS__); \
348             break;                                                      \
349         case TypeDesc::HALF  :                                          \
350             OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,half,Atype,R,A,__VA_ARGS__); \
351             break;                                                      \
352         case TypeDesc::UINT16:                                          \
353             OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,uint16_t,Atype,R,A,__VA_ARGS__); \
354             break;                                                      \
355         default: {                                                      \
356             /* other combinations: convert to float, then copy back */  \
357             ImageBuf Rtmp;                                              \
358             if ((R).initialized())                                      \
359                 Rtmp.copy (R, TypeDesc::FLOAT);                         \
360             OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,float,Atype,Rtmp,A,__VA_ARGS__); \
361             if (ret)                                                    \
362                 (R).copy (Rtmp);                                        \
363             else                                                        \
364                 (R).errorf("%s", Rtmp.geterror());                      \
365             }                                                           \
366         }                                                               \
367     }
368 
369 
370 // Macro to call a type-specialzed version func<Rtype,Atype>(R,A,...) for
371 // the most common types. It will auto-convert other cases to/from float.
372 // This is the case for when we don't actually write to the read-only R image.
373 #define OIIO_DISPATCH_COMMON_TYPES2_CONST(ret,name,func,Rtype,Atype,R,A,...)  \
374     switch (Rtype.basetype) {                                           \
375     case TypeDesc::FLOAT :                                              \
376         OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,float,Atype,R,A,__VA_ARGS__); \
377         break;                                                          \
378     case TypeDesc::UINT8 :                                              \
379         OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,unsigned char,Atype,R,A,__VA_ARGS__); \
380         break;                                                          \
381     case TypeDesc::HALF  :                                              \
382         OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,half,Atype,R,A,__VA_ARGS__); \
383         break;                                                          \
384     case TypeDesc::UINT16:                                              \
385         OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,unsigned short,Atype,R,A,__VA_ARGS__); \
386         break;                                                          \
387     default: {                                                          \
388         /* other types: punt and convert to float, then copy back */    \
389         ImageBuf Rtmp;                                                  \
390         if ((R).initialized())                                          \
391             Rtmp.copy (R, TypeDesc::FLOAT);                             \
392         OIIO_DISPATCH_COMMON_TYPES2_HELP(ret,name,func,float,Atype,Rtmp,A,__VA_ARGS__); \
393     } }
394 
395 
396 // Helper, do not call from the outside world.
397 #define OIIO_DISPATCH_COMMON_TYPES3_HELP2(ret,name,func,Rtype,Atype,Btype,R,A,B,...) \
398     switch (Rtype.basetype) {                                           \
399     case TypeDesc::FLOAT :                                              \
400         ret = func<float,Atype,Btype> (R,A,B,__VA_ARGS__); break;       \
401     case TypeDesc::UINT8 :                                              \
402         ret = func<unsigned char,Atype,Btype> (R,A,B,__VA_ARGS__); break;  \
403     case TypeDesc::HALF  :                                              \
404         ret = func<half,Atype,Btype> (R,A,B,__VA_ARGS__); break;        \
405     case TypeDesc::UINT16:                                              \
406         ret = func<unsigned short,Atype,Btype> (R,A,B,__VA_ARGS__); break;  \
407     default: {                                                          \
408         /* other types: punt and convert to float, then copy back */    \
409         ImageBuf Rtmp;                                                  \
410         if ((R).initialized())                                          \
411             Rtmp.copy (R, TypeDesc::FLOAT);                             \
412         ret = func<float,Atype,Btype> (R,A,B,__VA_ARGS__);              \
413         if (ret)                                                        \
414             (R).copy (Rtmp);                                            \
415         else                                                            \
416             (R).errorf("%s", Rtmp.geterror());                          \
417         }                                                               \
418     }
419 
420 // Helper, do not call from the outside world.
421 #define OIIO_DISPATCH_COMMON_TYPES3_HELP(ret,name,func,Rtype,Atype,Btype,R,A,B,...) \
422     switch (Btype.basetype) {                                           \
423     case TypeDesc::FLOAT :                                              \
424         OIIO_DISPATCH_COMMON_TYPES3_HELP2(ret,name,func,Rtype,Atype,float,R,A,B,__VA_ARGS__); \
425         break;                                                          \
426     case TypeDesc::UINT8 :                                              \
427         OIIO_DISPATCH_COMMON_TYPES3_HELP2(ret,name,func,Rtype,Atype,unsigned char,R,A,B,__VA_ARGS__); \
428         break;                                                          \
429     case TypeDesc::HALF :                                               \
430         OIIO_DISPATCH_COMMON_TYPES3_HELP2(ret,name,func,Rtype,Atype,half,R,A,B,__VA_ARGS__); \
431         break;                                                          \
432     case TypeDesc::UINT16 :                                             \
433         OIIO_DISPATCH_COMMON_TYPES3_HELP2(ret,name,func,Rtype,Atype,unsigned short,R,A,B,__VA_ARGS__); \
434         break;                                                          \
435     default: {                                                          \
436         /* other types: punt and convert to float */                    \
437         ImageBuf Btmp;                                                  \
438         Btmp.copy (B, TypeDesc::FLOAT);                                 \
439         OIIO_DISPATCH_COMMON_TYPES3_HELP2(ret,name,func,Rtype,Atype,float,R,A,Btmp,__VA_ARGS__); \
440         }                                                               \
441     }
442 
443 // Macro to call a type-specialzed version func<Rtype,Atype,Btype>(R,A,B,...)
444 // the most common types, and for all types when all three images have
445 // the same type. Remaining rare cases will auto-convert to float.
446 #define OIIO_DISPATCH_COMMON_TYPES3(ret,name,func,Rtype,Atype,Btype,R,A,B,...)  \
447     if (Rtype == Atype && Rtype == Btype) {                             \
448         /* All data types, when Rtype == Atype */                       \
449         switch (Atype.basetype) {                                       \
450         case TypeDesc::FLOAT :                                          \
451             ret = func<float,float,float> (R, A, B, __VA_ARGS__); break;\
452         case TypeDesc::UINT8 :                                          \
453             ret = func<uint8_t,uint8_t,uint8_t> (R, A, B, __VA_ARGS__); break; \
454         case TypeDesc::UINT16:                                          \
455             ret = func<uint16_t,uint16_t,uint16_t> (R, A, B, __VA_ARGS__); break; \
456         case TypeDesc::HALF  :                                          \
457             ret = func<half,half,half> (R, A, B, __VA_ARGS__); break;   \
458         case TypeDesc::INT8 :                                           \
459             ret = func<char,char,char> (R, A, B, __VA_ARGS__); break;   \
460         case TypeDesc::INT16 :                                          \
461             ret = func<int16_t,int16_t,int16_t> (R, A, B, __VA_ARGS__); break; \
462         case TypeDesc::UINT :                                           \
463             ret = func<uint32_t,uint32_t,uint32_t> (R, A, B, __VA_ARGS__); break; \
464         case TypeDesc::INT :                                            \
465             ret = func<int,int,int> (R, A, B, __VA_ARGS__); break;      \
466         case TypeDesc::DOUBLE :                                         \
467             ret = func<double,double,double> (R, A, B, __VA_ARGS__); break; \
468         default:                                                        \
469             (R).errorf("%s: Unsupported pixel data format '%s'", name, Atype); \
470             ret = false;                                                \
471         }                                                               \
472     } else {                                                            \
473         switch (Atype.basetype) {                                       \
474         case TypeDesc::FLOAT :                                          \
475             OIIO_DISPATCH_COMMON_TYPES3_HELP(ret,name,func,Rtype,float,Btype,R,A,B,__VA_ARGS__); \
476             break;                                                      \
477         case TypeDesc::UINT8 :                                          \
478             OIIO_DISPATCH_COMMON_TYPES3_HELP(ret,name,func,Rtype,unsigned char,Btype,R,A,B,__VA_ARGS__); \
479             break;                                                      \
480         case TypeDesc::HALF  :                                          \
481             OIIO_DISPATCH_COMMON_TYPES3_HELP(ret,name,func,Rtype,half,Btype,R,A,B,__VA_ARGS__); \
482             break;                                                      \
483         case TypeDesc::UINT16:                                          \
484             OIIO_DISPATCH_COMMON_TYPES3_HELP(ret,name,func,Rtype,unsigned short,Btype,R,A,B,__VA_ARGS__); \
485             break;                                                      \
486         default:                                                        \
487             /* other types: punt and convert to float */                \
488             ImageBuf Atmp;                                              \
489             Atmp.copy (A, TypeDesc::FLOAT);                             \
490             OIIO_DISPATCH_COMMON_TYPES3_HELP(ret,name,func,Rtype,float,Btype,R,Atmp,B,__VA_ARGS__); \
491         }                                                               \
492     }
493 
494 
495 // Utility: for span av, if it had fewer elements than len, alloca a new
496 // copy that's the right length. Use the `missing` value for missing entries
497 // (one or more supplied, but not all), and `zdef` default to use if there
498 // were no entries at all. This is used in many IBA functions that take
499 // constant per-channel values.
500 #define IBA_FIX_PERCHAN_LEN(av,len,missing,zdef)                        \
501     if (av.size() < len) {                                              \
502         int nc = len;                                                   \
503         float *vals = OIIO_ALLOCA(float, nc);                           \
504         for (int i = 0;  i < nc;  ++i)                                  \
505             vals[i] = i < av.size() ? av[i] : (i ? vals[i-1] : zdef);   \
506         av = cspan<float>(vals, nc);                                    \
507     }
508 
509 // Default IBA_FIX_PERCHAN_LEN, with zdef=0.0 and missing = the last value
510 // that was supplied.
511 #define IBA_FIX_PERCHAN_LEN_DEF(av,len)                                 \
512     IBA_FIX_PERCHAN_LEN (av, len, 0.0f, av.size() ? av.back() : 0.0f);
513 
514 
515 }  // end namespace ImageBufAlgo
516 
517 
518 OIIO_NAMESPACE_END
519