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 2008-present Contributors to the OpenImageIO project.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // https://github.com/OpenImageIO/oiio
4 
5 // clang-format off
6 
7 #pragma once
8 
9 #include <functional>
10 
11 #include <OpenImageIO/parallel.h>
13 
14 
15 
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
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
96 parallel_image (ROI roi, std::function<void(ROI)> f)
97 {
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_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 }
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 }
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 
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().
165 
166 // DEPRECATED(2.3): Prefer TypeDesc::basetype_merge().
168  return TypeDesc::basetype_merge(a, b);
169 }
170 
171 // DEPRECATED(2.3): Prefer TypeDesc::basetype_merge().
173 {
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).errorfmt("{}: Unsupported pixel data format '{}'", 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).errorfmt("{}: Unsupported pixel data format '{}'", 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).errorfmt("{}: Unsupported pixel data format '{}'", 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).errorfmt("{}", 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).errorfmt("{}: Unsupported pixel data format '{}'", 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).errorfmt("{}", 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).errorfmt("{}", 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).errorfmt("{}: Unsupported pixel data format '{}'", 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 
int chend
Definition: imageio.h:100
static BASETYPE basetype_merge(TypeDesc a, TypeDesc b)
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)
Encapsulation of options that control parallel_image().
Definition: parallel.h:28
void resolve()
Definition: parallel.h:51
OIIO_API void parallel_for_chunked_2D(int64_t xstart, int64_t xend, int64_t xchunksize, int64_t ystart, int64_t yend, int64_t ychunksize, std::function< void(int id, int64_t, int64_t, int64_t, int64_t)> &&task, parallel_options opt=0)
vfloat4 sqrt(const vfloat4 &a)
Definition: simd.h:7481
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:458
int zend
Definition: imageio.h:99
bool singlethread() const
Definition: parallel.h:61
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, const ImageBuf *A, int prepflags)
size_t minitems
Definition: parallel.h:66
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
SplitDir splitdir
Definition: parallel.h:64
SplitDir
Split strategies.
Definition: parallel.h:24
GLenum GLenum dst
Definition: glcorearb.h:1793
Definition: imageio.h:85
constexpr int width() const noexcept
Height.
Definition: imageio.h:123
int xbegin
Definition: imageio.h:97
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:94
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:93
#define OIIO_API
Definition: export.h:65