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