Blender  V3.3
COM_SMAAOperation.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2017 Blender Foundation. */
3 
4 #include "COM_SMAAOperation.h"
5 #include "BKE_node.h"
6 #include "COM_SMAAAreaTexture.h"
7 
8 extern "C" {
9 #include "IMB_colormanagement.h"
10 }
11 
12 namespace blender::compositor {
13 
14 /*
15  * An implementation of Enhanced Subpixel Morphological Antialiasing (SMAA)
16  *
17  * The algorithm was proposed by:
18  * Jorge Jimenez, Jose I. Echevarria, Tiago Sousa, Diego Gutierrez
19  *
20  * http://www.iryoku.com/smaa/
21  *
22  * This file is based on SMAA-CPP:
23  *
24  * https://github.com/i_ri-E/smaa-cpp
25  *
26  * Currently only SMAA 1x mode is provided, so the operation will be done
27  * with no spatial multi-sampling nor temporal super-sampling.
28  *
29  * NOTE: This program assumes the screen coordinates are DirectX style, so
30  * the vertical direction is upside-down. "top" and "bottom" actually mean
31  * bottom and top, respectively.
32  */
33 
34 /*-----------------------------------------------------------------------------*/
35 /* Non-Configurable Defines */
36 
37 #define SMAA_AREATEX_SIZE 80
38 #define SMAA_AREATEX_MAX_DISTANCE 20
39 #define SMAA_AREATEX_MAX_DISTANCE_DIAG 20
40 #define SMAA_MAX_SEARCH_STEPS 362 /* 362 - 1 = 19^2 */
41 #define SMAA_MAX_SEARCH_STEPS_DIAG 19
42 
43 /*-----------------------------------------------------------------------------*/
44 /* Internal Functions to Sample Pixel Color from Image */
45 
46 /* TODO(manzanilla): to be removed with tiled implementation. Replace it with
47  * #buffer->read_elem_checked. */
48 static inline void sample(SocketReader *reader, int x, int y, float color[4])
49 {
50  if (x < 0 || x >= reader->get_width() || y < 0 || y >= reader->get_height()) {
51  color[0] = color[1] = color[2] = color[3] = 0.0;
52  return;
53  }
54 
55  reader->read(color, x, y, nullptr);
56 }
57 
58 static inline void sample(MemoryBuffer *reader, int x, int y, float color[4])
59 {
60  reader->read_elem_checked(x, y, color);
61 }
62 
63 template<typename T>
64 static void sample_bilinear_vertical(T *reader, int x, int y, float yoffset, float color[4])
65 {
66  float iy = floorf(yoffset);
67  float fy = yoffset - iy;
68  y += (int)iy;
69 
70  float color00[4], color01[4];
71 
72  sample(reader, x + 0, y + 0, color00);
73  sample(reader, x + 0, y + 1, color01);
74 
75  color[0] = interpf(color01[0], color00[0], fy);
76  color[1] = interpf(color01[1], color00[1], fy);
77  color[2] = interpf(color01[2], color00[2], fy);
78  color[3] = interpf(color01[3], color00[3], fy);
79 }
80 
81 template<typename T>
82 static void sample_bilinear_horizontal(T *reader, int x, int y, float xoffset, float color[4])
83 {
84  float ix = floorf(xoffset);
85  float fx = xoffset - ix;
86  x += (int)ix;
87 
88  float color00[4], color10[4];
89 
90  sample(reader, x + 0, y + 0, color00);
91  sample(reader, x + 1, y + 0, color10);
92 
93  color[0] = interpf(color10[0], color00[0], fx);
94  color[1] = interpf(color10[1], color00[1], fx);
95  color[2] = interpf(color10[2], color00[2], fx);
96  color[3] = interpf(color10[3], color00[3], fx);
97 }
98 
99 /*-----------------------------------------------------------------------------*/
100 /* Internal Functions to Sample Blending Weights from AreaTex */
101 
102 static inline const float *areatex_sample_internal(const float *areatex, int x, int y)
103 {
104  return &areatex[(CLAMPIS(x, 0, SMAA_AREATEX_SIZE - 1) +
106  2];
107 }
108 
113 static void area(int d1, int d2, int e1, int e2, float weights[2])
114 {
115  /* The areas texture is compressed quadratically: */
116  float x = (float)(SMAA_AREATEX_MAX_DISTANCE * e1) + sqrtf((float)d1);
117  float y = (float)(SMAA_AREATEX_MAX_DISTANCE * e2) + sqrtf((float)d2);
118 
119  float ix = floorf(x), iy = floorf(y);
120  float fx = x - ix, fy = y - iy;
121  int X = (int)ix, Y = (int)iy;
122 
123  const float *weights00 = areatex_sample_internal(areatex, X + 0, Y + 0);
124  const float *weights10 = areatex_sample_internal(areatex, X + 1, Y + 0);
125  const float *weights01 = areatex_sample_internal(areatex, X + 0, Y + 1);
126  const float *weights11 = areatex_sample_internal(areatex, X + 1, Y + 1);
127 
128  weights[0] = interpf(
129  interpf(weights11[0], weights01[0], fx), interpf(weights10[0], weights00[0], fx), fy);
130  weights[1] = interpf(
131  interpf(weights11[1], weights01[1], fx), interpf(weights10[1], weights00[1], fx), fy);
132 }
133 
138 static void area_diag(int d1, int d2, int e1, int e2, float weights[2])
139 {
140  int x = SMAA_AREATEX_MAX_DISTANCE_DIAG * e1 + d1;
141  int y = SMAA_AREATEX_MAX_DISTANCE_DIAG * e2 + d2;
142 
143  const float *w = areatex_sample_internal(areatex_diag, x, y);
144  copy_v2_v2(weights, w);
145 }
146 
147 /*-----------------------------------------------------------------------------*/
148 /* Edge Detection (First Pass) */
149 /*-----------------------------------------------------------------------------*/
150 
152 {
153  this->add_input_socket(DataType::Color); /* image */
154  this->add_input_socket(DataType::Value); /* Depth, material ID, etc. TODO: currently unused. */
156  flags_.complex = true;
157  image_reader_ = nullptr;
158  value_reader_ = nullptr;
161 }
162 
164 {
167 }
168 
170 {
171  image_reader_ = nullptr;
172  value_reader_ = nullptr;
173 }
174 
176 {
177  /* UI values are between 0 and 1 for simplicity but algorithm expects values between 0 and 0.5 */
178  threshold_ = scalenorm(0, 0.5, threshold);
179 }
180 
182 {
183  /* UI values are between 0 and 1 for simplicity but algorithm expects values between 1 and 10 */
184  contrast_limit_ = scalenorm(1, 10, factor);
185 }
186 
188  rcti *input, ReadBufferOperation *read_operation, rcti *output)
189 {
190  rcti new_input;
191  new_input.xmax = input->xmax + 1;
192  new_input.xmin = input->xmin - 2;
193  new_input.ymax = input->ymax + 1;
194  new_input.ymin = input->ymin - 2;
195 
196  return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
197 }
198 
200  const rcti &output_area,
201  rcti &r_input_area)
202 {
203  r_input_area.xmax = output_area.xmax + 1;
204  r_input_area.xmin = output_area.xmin - 2;
205  r_input_area.ymax = output_area.ymax + 1;
206  r_input_area.ymin = output_area.ymin - 2;
207 }
208 
209 void SMAAEdgeDetectionOperation::execute_pixel(float output[4], int x, int y, void * /*data*/)
210 {
211  float color[4];
212 
213  /* Calculate luma deltas: */
216  sample(image_reader_, x - 1, y, color);
218  sample(image_reader_, x, y - 1, color);
220  float Dleft = fabsf(L - Lleft);
221  float Dtop = fabsf(L - Ltop);
222 
223  /* We do the usual threshold: */
224  output[0] = (x > 0 && Dleft >= threshold_) ? 1.0f : 0.0f;
225  output[1] = (y > 0 && Dtop >= threshold_) ? 1.0f : 0.0f;
226  output[2] = 0.0f;
227  output[3] = 1.0f;
228 
229  /* Then discard if there is no edge: */
230  if (is_zero_v2(output)) {
231  return;
232  }
233 
234  /* Calculate right and bottom deltas: */
235  sample(image_reader_, x + 1, y, color);
237  sample(image_reader_, x, y + 1, color);
238  float Lbottom = IMB_colormanagement_get_luminance(color);
239  float Dright = fabsf(L - Lright);
240  float Dbottom = fabsf(L - Lbottom);
241 
242  /* Calculate the maximum delta in the direct neighborhood: */
243  float max_delta = fmaxf(fmaxf(Dleft, Dright), fmaxf(Dtop, Dbottom));
244 
245  /* Calculate luma used for both left and top edges: */
246  sample(image_reader_, x - 1, y - 1, color);
247  float Llefttop = IMB_colormanagement_get_luminance(color);
248 
249  /* Left edge */
250  if (output[0] != 0.0f) {
251  /* Calculate deltas around the left pixel: */
252  sample(image_reader_, x - 2, y, color);
253  float Lleftleft = IMB_colormanagement_get_luminance(color);
254  sample(image_reader_, x - 1, y + 1, color);
255  float Lleftbottom = IMB_colormanagement_get_luminance(color);
256  float Dleftleft = fabsf(Lleft - Lleftleft);
257  float Dlefttop = fabsf(Lleft - Llefttop);
258  float Dleftbottom = fabsf(Lleft - Lleftbottom);
259 
260  /* Calculate the final maximum delta: */
261  max_delta = fmaxf(max_delta, fmaxf(Dleftleft, fmaxf(Dlefttop, Dleftbottom)));
262 
263  /* Local contrast adaptation: */
264  if (max_delta > contrast_limit_ * Dleft) {
265  output[0] = 0.0f;
266  }
267  }
268 
269  /* Top edge */
270  if (output[1] != 0.0f) {
271  /* Calculate top-top delta: */
272  sample(image_reader_, x, y - 2, color);
273  float Ltoptop = IMB_colormanagement_get_luminance(color);
274  sample(image_reader_, x + 1, y - 1, color);
275  float Ltopright = IMB_colormanagement_get_luminance(color);
276  float Dtoptop = fabsf(Ltop - Ltoptop);
277  float Dtopleft = fabsf(Ltop - Llefttop);
278  float Dtopright = fabsf(Ltop - Ltopright);
279 
280  /* Calculate the final maximum delta: */
281  max_delta = fmaxf(max_delta, fmaxf(Dtoptop, fmaxf(Dtopleft, Dtopright)));
282 
283  /* Local contrast adaptation: */
284  if (max_delta > contrast_limit_ * Dtop) {
285  output[1] = 0.0f;
286  }
287  }
288 }
289 
291  const rcti &area,
293 {
294  const MemoryBuffer *image = inputs[0];
295  for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
296  float color[4];
297  const int x = it.x;
298  const int y = it.y;
299 
300  /* Calculate luma deltas: */
301  image->read_elem_checked(x, y, color);
303  image->read_elem_checked(x - 1, y, color);
304  const float Lleft = IMB_colormanagement_get_luminance(color);
305  image->read_elem_checked(x, y - 1, color);
306  const float Ltop = IMB_colormanagement_get_luminance(color);
307  const float Dleft = fabsf(L - Lleft);
308  const float Dtop = fabsf(L - Ltop);
309 
310  /* We do the usual threshold: */
311  it.out[0] = (x > 0 && Dleft >= threshold_) ? 1.0f : 0.0f;
312  it.out[1] = (y > 0 && Dtop >= threshold_) ? 1.0f : 0.0f;
313  it.out[2] = 0.0f;
314  it.out[3] = 1.0f;
315 
316  /* Then discard if there is no edge: */
317  if (is_zero_v2(it.out)) {
318  continue;
319  }
320 
321  /* Calculate right and bottom deltas: */
322  image->read_elem_checked(x + 1, y, color);
323  const float Lright = IMB_colormanagement_get_luminance(color);
324  image->read_elem_checked(x, y + 1, color);
325  const float Lbottom = IMB_colormanagement_get_luminance(color);
326  const float Dright = fabsf(L - Lright);
327  const float Dbottom = fabsf(L - Lbottom);
328 
329  /* Calculate the maximum delta in the direct neighborhood: */
330  float max_delta = fmaxf(fmaxf(Dleft, Dright), fmaxf(Dtop, Dbottom));
331 
332  /* Calculate luma used for both left and top edges: */
333  image->read_elem_checked(x - 1, y - 1, color);
334  const float Llefttop = IMB_colormanagement_get_luminance(color);
335 
336  /* Left edge */
337  if (it.out[0] != 0.0f) {
338  /* Calculate deltas around the left pixel: */
339  image->read_elem_checked(x - 2, y, color);
340  const float Lleftleft = IMB_colormanagement_get_luminance(color);
341  image->read_elem_checked(x - 1, y + 1, color);
342  const float Lleftbottom = IMB_colormanagement_get_luminance(color);
343  const float Dleftleft = fabsf(Lleft - Lleftleft);
344  const float Dlefttop = fabsf(Lleft - Llefttop);
345  const float Dleftbottom = fabsf(Lleft - Lleftbottom);
346 
347  /* Calculate the final maximum delta: */
348  max_delta = fmaxf(max_delta, fmaxf(Dleftleft, fmaxf(Dlefttop, Dleftbottom)));
349 
350  /* Local contrast adaptation: */
351  if (max_delta > contrast_limit_ * Dleft) {
352  it.out[0] = 0.0f;
353  }
354  }
355 
356  /* Top edge */
357  if (it.out[1] != 0.0f) {
358  /* Calculate top-top delta: */
359  image->read_elem_checked(x, y - 2, color);
360  const float Ltoptop = IMB_colormanagement_get_luminance(color);
361  image->read_elem_checked(x + 1, y - 1, color);
362  const float Ltopright = IMB_colormanagement_get_luminance(color);
363  const float Dtoptop = fabsf(Ltop - Ltoptop);
364  const float Dtopleft = fabsf(Ltop - Llefttop);
365  const float Dtopright = fabsf(Ltop - Ltopright);
366 
367  /* Calculate the final maximum delta: */
368  max_delta = fmaxf(max_delta, fmaxf(Dtoptop, fmaxf(Dtopleft, Dtopright)));
369 
370  /* Local contrast adaptation: */
371  if (max_delta > contrast_limit_ * Dtop) {
372  it.out[1] = 0.0f;
373  }
374  }
375  }
376 }
377 
378 /*-----------------------------------------------------------------------------*/
379 /* Blending Weight Calculation (Second Pass) */
380 /*-----------------------------------------------------------------------------*/
381 
383 {
384  this->add_input_socket(DataType::Color); /* edges */
386  flags_.complex = true;
387  image_reader_ = nullptr;
389 }
390 
392 {
393  return get_input_operation(0)->initialize_tile_data(rect);
394 }
395 
397 {
398  image_reader_ = this->get_input_socket_reader(0);
400  sample_image_fn_ = [=](int x, int y, float *out) { sample(image_reader_, x, y, out); };
401  }
402 }
403 
405 {
406  /* UI values are between 0 and 1 for simplicity but algorithm expects values between 0 and 100 */
407  corner_rounding_ = static_cast<int>(scalenorm(0, 100, rounding));
408 }
409 
411  int x,
412  int y,
413  void * /*data*/)
414 {
415  float edges[4], c[4];
416 
417  zero_v4(output);
418  sample(image_reader_, x, y, edges);
419 
420  /* Edge at north */
421  if (edges[1] > 0.0f) {
422  /* Diagonals have both north and west edges, so calculating weights for them */
423  /* in one of the boundaries is enough. */
424  calculate_diag_weights(x, y, edges, output);
425 
426  /* We give priority to diagonals, so if we find a diagonal we skip. */
427  /* horizontal/vertical processing. */
428  if (!is_zero_v2(output)) {
429  return;
430  }
431 
432  /* Find the distance to the left and the right: */
433  int left = search_xleft(x, y);
434  int right = search_xright(x, y);
435  int d1 = x - left, d2 = right - x;
436 
437  /* Fetch the left and right crossing edges: */
438  int e1 = 0, e2 = 0;
439  sample(image_reader_, left, y - 1, c);
440  if (c[0] > 0.0) {
441  e1 += 1;
442  }
443  sample(image_reader_, left, y, c);
444  if (c[0] > 0.0) {
445  e1 += 2;
446  }
447  sample(image_reader_, right + 1, y - 1, c);
448  if (c[0] > 0.0) {
449  e2 += 1;
450  }
451  sample(image_reader_, right + 1, y, c);
452  if (c[0] > 0.0) {
453  e2 += 2;
454  }
455 
456  /* Ok, we know how this pattern looks like, now it is time for getting */
457  /* the actual area: */
458  area(d1, d2, e1, e2, output); /* R, G */
459 
460  /* Fix corners: */
461  if (corner_rounding_) {
462  detect_horizontal_corner_pattern(output, left, right, y, d1, d2);
463  }
464  }
465 
466  /* Edge at west */
467  if (edges[0] > 0.0f) {
468  /* Did we already do diagonal search for this west edge from the left neighboring pixel? */
469  if (is_vertical_search_unneeded(x, y)) {
470  return;
471  }
472 
473  /* Find the distance to the top and the bottom: */
474  int top = search_yup(x, y);
475  int bottom = search_ydown(x, y);
476  int d1 = y - top, d2 = bottom - y;
477 
478  /* Fetch the top and bottom crossing edges: */
479  int e1 = 0, e2 = 0;
480  sample(image_reader_, x - 1, top, c);
481  if (c[1] > 0.0) {
482  e1 += 1;
483  }
484  sample(image_reader_, x, top, c);
485  if (c[1] > 0.0) {
486  e1 += 2;
487  }
488  sample(image_reader_, x - 1, bottom + 1, c);
489  if (c[1] > 0.0) {
490  e2 += 1;
491  }
492  sample(image_reader_, x, bottom + 1, c);
493  if (c[1] > 0.0) {
494  e2 += 2;
495  }
496 
497  /* Get the area for this direction: */
498  area(d1, d2, e1, e2, output + 2); /* B, A */
499 
500  /* Fix corners: */
501  if (corner_rounding_) {
502  detect_vertical_corner_pattern(output + 2, x, top, bottom, d1, d2);
503  }
504  }
505 }
506 
509 {
510  const MemoryBuffer *image = inputs[0];
511  sample_image_fn_ = [=](int x, int y, float *out) { image->read_elem_checked(x, y, out); };
512 }
513 
516 {
517  for (BuffersIterator<float> it = output->iterate_with({}, out_area); !it.is_end(); ++it) {
518  const int x = it.x;
519  const int y = it.y;
520  zero_v4(it.out);
521 
522  float edges[4];
523  sample_image_fn_(x, y, edges);
524 
525  /* Edge at north */
526  float c[4];
527  if (edges[1] > 0.0f) {
528  /* Diagonals have both north and west edges, so calculating weights for them */
529  /* in one of the boundaries is enough. */
530  calculate_diag_weights(x, y, edges, it.out);
531 
532  /* We give priority to diagonals, so if we find a diagonal we skip. */
533  /* horizontal/vertical processing. */
534  if (!is_zero_v2(it.out)) {
535  continue;
536  }
537 
538  /* Find the distance to the left and the right: */
539  int left = search_xleft(x, y);
540  int right = search_xright(x, y);
541  int d1 = x - left, d2 = right - x;
542 
543  /* Fetch the left and right crossing edges: */
544  int e1 = 0, e2 = 0;
545  sample_image_fn_(left, y - 1, c);
546  if (c[0] > 0.0) {
547  e1 += 1;
548  }
549  sample_image_fn_(left, y, c);
550  if (c[0] > 0.0) {
551  e1 += 2;
552  }
553  sample_image_fn_(right + 1, y - 1, c);
554  if (c[0] > 0.0) {
555  e2 += 1;
556  }
557  sample_image_fn_(right + 1, y, c);
558  if (c[0] > 0.0) {
559  e2 += 2;
560  }
561 
562  /* Ok, we know how this pattern looks like, now it is time for getting */
563  /* the actual area: */
564  area(d1, d2, e1, e2, it.out); /* R, G */
565 
566  /* Fix corners: */
567  if (corner_rounding_) {
568  detect_horizontal_corner_pattern(it.out, left, right, y, d1, d2);
569  }
570  }
571 
572  /* Edge at west */
573  if (edges[0] > 0.0f) {
574  /* Did we already do diagonal search for this west edge from the left neighboring pixel? */
575  if (is_vertical_search_unneeded(x, y)) {
576  continue;
577  }
578 
579  /* Find the distance to the top and the bottom: */
580  int top = search_yup(x, y);
581  int bottom = search_ydown(x, y);
582  int d1 = y - top, d2 = bottom - y;
583 
584  /* Fetch the top and bottom crossing edges: */
585  int e1 = 0, e2 = 0;
586  sample_image_fn_(x - 1, top, c);
587  if (c[1] > 0.0) {
588  e1 += 1;
589  }
590  sample_image_fn_(x, top, c);
591  if (c[1] > 0.0) {
592  e1 += 2;
593  }
594  sample_image_fn_(x - 1, bottom + 1, c);
595  if (c[1] > 0.0) {
596  e2 += 1;
597  }
598  sample_image_fn_(x, bottom + 1, c);
599  if (c[1] > 0.0) {
600  e2 += 2;
601  }
602 
603  /* Get the area for this direction: */
604  area(d1, d2, e1, e2, it.out + 2); /* B, A */
605 
606  /* Fix corners: */
607  if (corner_rounding_) {
608  detect_vertical_corner_pattern(it.out + 2, x, top, bottom, d1, d2);
609  }
610  }
611  }
612 }
613 
615 {
616  image_reader_ = nullptr;
617 }
618 
620  rcti *input, ReadBufferOperation *read_operation, rcti *output)
621 {
622  rcti new_input;
623 
624  new_input.xmax = input->xmax + fmax(SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG + 1);
625  new_input.xmin = input->xmin -
626  fmax(fmax(SMAA_MAX_SEARCH_STEPS - 1, 1), SMAA_MAX_SEARCH_STEPS_DIAG + 1);
627  new_input.ymax = input->ymax + fmax(SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG);
628  new_input.ymin = input->ymin -
630 
631  return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
632 }
633 
635  const rcti &output_area,
636  rcti &r_input_area)
637 {
638  r_input_area.xmax = output_area.xmax +
640  r_input_area.xmin = output_area.xmin -
641  fmax(fmax(SMAA_MAX_SEARCH_STEPS - 1, 1), SMAA_MAX_SEARCH_STEPS_DIAG + 1);
642  r_input_area.ymax = output_area.ymax + fmax(SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG);
643  r_input_area.ymin = output_area.ymin -
645 }
646 
647 /*-----------------------------------------------------------------------------*/
648 /* Diagonal Search Functions */
649 
650 int SMAABlendingWeightCalculationOperation::search_diag1(int x, int y, int dir, bool *found)
651 {
652  float e[4];
653  int end = x + SMAA_MAX_SEARCH_STEPS_DIAG * dir;
654  *found = false;
655 
656  while (x != end) {
657  x += dir;
658  y -= dir;
659  sample_image_fn_(x, y, e);
660  if (e[1] == 0.0f) {
661  *found = true;
662  break;
663  }
664  if (e[0] == 0.0f) {
665  *found = true;
666  return (dir < 0) ? x : x - dir;
667  }
668  }
669 
670  return x - dir;
671 }
672 
673 int SMAABlendingWeightCalculationOperation::search_diag2(int x, int y, int dir, bool *found)
674 {
675  float e[4];
676  int end = x + SMAA_MAX_SEARCH_STEPS_DIAG * dir;
677  *found = false;
678 
679  while (x != end) {
680  x += dir;
681  y += dir;
682  sample_image_fn_(x, y, e);
683  if (e[1] == 0.0f) {
684  *found = true;
685  break;
686  }
687  sample_image_fn_(x + 1, y, e);
688  if (e[0] == 0.0f) {
689  *found = true;
690  return (dir > 0) ? x : x - dir;
691  }
692  }
693 
694  return x - dir;
695 }
696 
697 void SMAABlendingWeightCalculationOperation::calculate_diag_weights(int x,
698  int y,
699  const float edges[2],
700  float weights[2])
701 {
702  int d1, d2;
703  bool d1_found, d2_found;
704  float e[4], c[4];
705 
706  zero_v2(weights);
707 
708  if (SMAA_MAX_SEARCH_STEPS_DIAG <= 0) {
709  return;
710  }
711 
712  /* Search for the line ends: */
713  if (edges[0] > 0.0f) {
714  d1 = x - search_diag1(x, y, -1, &d1_found);
715  }
716  else {
717  d1 = 0;
718  d1_found = true;
719  }
720  d2 = search_diag1(x, y, 1, &d2_found) - x;
721 
722  if (d1 + d2 > 2) { /* d1 + d2 + 1 > 3 */
723  int e1 = 0, e2 = 0;
724 
725  if (d1_found) {
726  /* Fetch the crossing edges: */
727  int left = x - d1, bottom = y + d1;
728 
729  sample_image_fn_(left - 1, bottom, c);
730  if (c[1] > 0.0) {
731  e1 += 2;
732  }
733  sample_image_fn_(left, bottom, c);
734  if (c[0] > 0.0) {
735  e1 += 1;
736  }
737  }
738 
739  if (d2_found) {
740  /* Fetch the crossing edges: */
741  int right = x + d2, top = y - d2;
742 
743  sample_image_fn_(right + 1, top, c);
744  if (c[1] > 0.0) {
745  e2 += 2;
746  }
747  sample_image_fn_(right + 1, top - 1, c);
748  if (c[0] > 0.0) {
749  e2 += 1;
750  }
751  }
752 
753  /* Fetch the areas for this line: */
754  area_diag(d1, d2, e1, e2, weights);
755  }
756 
757  /* Search for the line ends: */
758  d1 = x - search_diag2(x, y, -1, &d1_found);
759  sample_image_fn_(x + 1, y, e);
760  if (e[0] > 0.0f) {
761  d2 = search_diag2(x, y, 1, &d2_found) - x;
762  }
763  else {
764  d2 = 0;
765  d2_found = true;
766  }
767 
768  if (d1 + d2 > 2) { /* d1 + d2 + 1 > 3 */
769  int e1 = 0, e2 = 0;
770 
771  if (d1_found) {
772  /* Fetch the crossing edges: */
773  int left = x - d1, top = y - d1;
774 
775  sample_image_fn_(left - 1, top, c);
776  if (c[1] > 0.0) {
777  e1 += 2;
778  }
779  sample_image_fn_(left, top - 1, c);
780  if (c[0] > 0.0) {
781  e1 += 1;
782  }
783  }
784 
785  if (d2_found) {
786  /* Fetch the crossing edges: */
787  int right = x + d2, bottom = y + d2;
788 
789  sample_image_fn_(right + 1, bottom, c);
790  if (c[1] > 0.0) {
791  e2 += 2;
792  }
793  if (c[0] > 0.0) {
794  e2 += 1;
795  }
796  }
797 
798  /* Fetch the areas for this line: */
799  float w[2];
800  area_diag(d1, d2, e1, e2, w);
801  weights[0] += w[1];
802  weights[1] += w[0];
803  }
804 }
805 
806 bool SMAABlendingWeightCalculationOperation::is_vertical_search_unneeded(int x, int y)
807 {
808  int d1, d2;
809  bool found;
810  float e[4];
811 
812  if (SMAA_MAX_SEARCH_STEPS_DIAG <= 0) {
813  return false;
814  }
815 
816  /* Search for the line ends: */
817  sample_image_fn_(x - 1, y, e);
818  if (e[1] > 0.0f) {
819  d1 = x - search_diag2(x - 1, y, -1, &found);
820  }
821  else {
822  d1 = 0;
823  }
824  d2 = search_diag2(x - 1, y, 1, &found) - x;
825 
826  return (d1 + d2 > 2); /* d1 + d2 + 1 > 3 */
827 }
828 
829 /*-----------------------------------------------------------------------------*/
830 /* Horizontal/Vertical Search Functions */
831 
832 int SMAABlendingWeightCalculationOperation::search_xleft(int x, int y)
833 {
834  int end = x - SMAA_MAX_SEARCH_STEPS;
835  float e[4];
836 
837  while (x > end) {
838  sample_image_fn_(x, y, e);
839  if (e[1] == 0.0f) { /* Is the edge not activated? */
840  break;
841  }
842  if (e[0] != 0.0f) { /* Or is there a crossing edge that breaks the line? */
843  return x;
844  }
845  sample_image_fn_(x, y - 1, e);
846  if (e[0] != 0.0f) { /* Or is there a crossing edge that breaks the line? */
847  return x;
848  }
849  x--;
850  }
851 
852  return x + 1;
853 }
854 
855 int SMAABlendingWeightCalculationOperation::search_xright(int x, int y)
856 {
857  int end = x + SMAA_MAX_SEARCH_STEPS;
858  float e[4];
859 
860  while (x < end) {
861  x++;
862  sample_image_fn_(x, y, e);
863  if (e[1] == 0.0f || /* Is the edge not activated? */
864  e[0] != 0.0f) { /* Or is there a crossing edge that breaks the line? */
865  break;
866  }
867  sample_image_fn_(x, y - 1, e);
868  if (e[0] != 0.0f) { /* Or is there a crossing edge that breaks the line? */
869  break;
870  }
871  }
872 
873  return x - 1;
874 }
875 
876 int SMAABlendingWeightCalculationOperation::search_yup(int x, int y)
877 {
878  int end = y - SMAA_MAX_SEARCH_STEPS;
879  float e[4];
880 
881  while (y > end) {
882  sample_image_fn_(x, y, e);
883  if (e[0] == 0.0f) { /* Is the edge not activated? */
884  break;
885  }
886  if (e[1] != 0.0f) { /* Or is there a crossing edge that breaks the line? */
887  return y;
888  }
889  sample_image_fn_(x - 1, y, e);
890  if (e[1] != 0.0f) { /* Or is there a crossing edge that breaks the line? */
891  return y;
892  }
893  y--;
894  }
895 
896  return y + 1;
897 }
898 
899 int SMAABlendingWeightCalculationOperation::search_ydown(int x, int y)
900 {
901  int end = y + SMAA_MAX_SEARCH_STEPS;
902  float e[4];
903 
904  while (y < end) {
905  y++;
906  sample_image_fn_(x, y, e);
907  if (e[0] == 0.0f || /* Is the edge not activated? */
908  e[1] != 0.0f) { /* Or is there a crossing edge that breaks the line? */
909  break;
910  }
911  sample_image_fn_(x - 1, y, e);
912  if (e[1] != 0.0f) { /* Or is there a crossing edge that breaks the line? */
913  break;
914  }
915  }
916 
917  return y - 1;
918 }
919 
920 /*-----------------------------------------------------------------------------*/
921 /* Corner Detection Functions */
922 
923 void SMAABlendingWeightCalculationOperation::detect_horizontal_corner_pattern(
924  float weights[2], int left, int right, int y, int d1, int d2)
925 {
926  float factor[2] = {1.0f, 1.0f};
927  float rounding = corner_rounding_ / 100.0f;
928  float e[4];
929 
930  /* Reduce blending for pixels in the center of a line. */
931  rounding *= (d1 == d2) ? 0.5f : 1.0f;
932 
933  /* Near the left corner */
934  if (d1 <= d2) {
935  sample_image_fn_(left, y + 1, e);
936  factor[0] -= rounding * e[0];
937  sample_image_fn_(left, y - 2, e);
938  factor[1] -= rounding * e[0];
939  }
940  /* Near the right corner */
941  if (d1 >= d2) {
942  sample_image_fn_(right + 1, y + 1, e);
943  factor[0] -= rounding * e[0];
944  sample_image_fn_(right + 1, y - 2, e);
945  factor[1] -= rounding * e[0];
946  }
947 
948  weights[0] *= CLAMPIS(factor[0], 0.0f, 1.0f);
949  weights[1] *= CLAMPIS(factor[1], 0.0f, 1.0f);
950 }
951 
952 void SMAABlendingWeightCalculationOperation::detect_vertical_corner_pattern(
953  float weights[2], int x, int top, int bottom, int d1, int d2)
954 {
955  float factor[2] = {1.0f, 1.0f};
956  float rounding = corner_rounding_ / 100.0f;
957  float e[4];
958 
959  /* Reduce blending for pixels in the center of a line. */
960  rounding *= (d1 == d2) ? 0.5f : 1.0f;
961 
962  /* Near the top corner */
963  if (d1 <= d2) {
964  sample_image_fn_(x + 1, top, e);
965  factor[0] -= rounding * e[1];
966  sample_image_fn_(x - 2, top, e);
967  factor[1] -= rounding * e[1];
968  }
969  /* Near the bottom corner */
970  if (d1 >= d2) {
971  sample_image_fn_(x + 1, bottom + 1, e);
972  factor[0] -= rounding * e[1];
973  sample_image_fn_(x - 2, bottom + 1, e);
974  factor[1] -= rounding * e[1];
975  }
976 
977  weights[0] *= CLAMPIS(factor[0], 0.0f, 1.0f);
978  weights[1] *= CLAMPIS(factor[1], 0.0f, 1.0f);
979 }
980 
981 /*-----------------------------------------------------------------------------*/
982 /* Neighborhood Blending (Third Pass) */
983 /*-----------------------------------------------------------------------------*/
984 
986 {
987  this->add_input_socket(DataType::Color); /* image */
988  this->add_input_socket(DataType::Color); /* blend */
990  flags_.complex = true;
991  image1Reader_ = nullptr;
992  image2Reader_ = nullptr;
993 }
994 
996 {
997  return get_input_operation(0)->initialize_tile_data(rect);
998 }
999 
1001 {
1002  image1Reader_ = this->get_input_socket_reader(0);
1003  image2Reader_ = this->get_input_socket_reader(1);
1004 }
1005 
1007  int x,
1008  int y,
1009  void * /*data*/)
1010 {
1011  float w[4];
1012 
1013  /* Fetch the blending weights for current pixel: */
1014  sample(image2Reader_, x, y, w);
1015  float left = w[2], top = w[0];
1016  sample(image2Reader_, x + 1, y, w);
1017  float right = w[3];
1018  sample(image2Reader_, x, y + 1, w);
1019  float bottom = w[1];
1020 
1021  /* Is there any blending weight with a value greater than 0.0? */
1022  if (right + bottom + left + top < 1e-5f) {
1023  sample(image1Reader_, x, y, output);
1024  return;
1025  }
1026 
1027  /* Calculate the blending offsets: */
1028  void (*samplefunc)(SocketReader * reader, int x, int y, float xoffset, float color[4]);
1029  float offset1, offset2, weight1, weight2, color1[4], color2[4];
1030 
1031  if (fmaxf(right, left) > fmaxf(bottom, top)) { /* max(horizontal) > max(vertical) */
1032  samplefunc = sample_bilinear_horizontal;
1033  offset1 = right;
1034  offset2 = -left;
1035  weight1 = right / (right + left);
1036  weight2 = left / (right + left);
1037  }
1038  else {
1039  samplefunc = sample_bilinear_vertical;
1040  offset1 = bottom;
1041  offset2 = -top;
1042  weight1 = bottom / (bottom + top);
1043  weight2 = top / (bottom + top);
1044  }
1045 
1046  /* We exploit bilinear filtering to mix current pixel with the chosen neighbor: */
1047  samplefunc(image1Reader_, x, y, offset1, color1);
1048  samplefunc(image1Reader_, x, y, offset2, color2);
1049 
1050  mul_v4_v4fl(output, color1, weight1);
1051  madd_v4_v4fl(output, color2, weight2);
1052 }
1053 
1055  const rcti &out_area,
1057 {
1058  MemoryBuffer *image1 = inputs[0];
1059  MemoryBuffer *image2 = inputs[1];
1060  for (BuffersIterator<float> it = output->iterate_with({}, out_area); !it.is_end(); ++it) {
1061  const float x = it.x;
1062  const float y = it.y;
1063  float w[4];
1064 
1065  /* Fetch the blending weights for current pixel: */
1066  image2->read_elem_checked(x, y, w);
1067  const float left = w[2], top = w[0];
1068  image2->read_elem_checked(x + 1, y, w);
1069  const float right = w[3];
1070  image2->read_elem_checked(x, y + 1, w);
1071  const float bottom = w[1];
1072 
1073  /* Is there any blending weight with a value greater than 0.0? */
1074  if (right + bottom + left + top < 1e-5f) {
1075  image1->read_elem_checked(x, y, it.out);
1076  continue;
1077  }
1078 
1079  /* Calculate the blending offsets: */
1080  void (*sample_fn)(MemoryBuffer * reader, int x, int y, float xoffset, float color[4]);
1081  float offset1, offset2, weight1, weight2, color1[4], color2[4];
1082 
1083  if (fmaxf(right, left) > fmaxf(bottom, top)) { /* `max(horizontal) > max(vertical)` */
1084  sample_fn = sample_bilinear_horizontal;
1085  offset1 = right;
1086  offset2 = -left;
1087  weight1 = right / (right + left);
1088  weight2 = left / (right + left);
1089  }
1090  else {
1091  sample_fn = sample_bilinear_vertical;
1092  offset1 = bottom;
1093  offset2 = -top;
1094  weight1 = bottom / (bottom + top);
1095  weight2 = top / (bottom + top);
1096  }
1097 
1098  /* We exploit bilinear filtering to mix current pixel with the chosen neighbor: */
1099  sample_fn(image1, x, y, offset1, color1);
1100  sample_fn(image1, x, y, offset2, color2);
1101 
1102  mul_v4_v4fl(it.out, color1, weight1);
1103  madd_v4_v4fl(it.out, color2, weight2);
1104  }
1105 }
1106 
1108 {
1109  image1Reader_ = nullptr;
1110  image2Reader_ = nullptr;
1111 }
1112 
1114  rcti *input, ReadBufferOperation *read_operation, rcti *output)
1115 {
1116  rcti new_input;
1117 
1118  new_input.xmax = input->xmax + 1;
1119  new_input.xmin = input->xmin - 1;
1120  new_input.ymax = input->ymax + 1;
1121  new_input.ymin = input->ymin - 1;
1122 
1123  return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
1124 }
1125 
1127  const rcti &output_area,
1128  rcti &r_input_area)
1129 {
1130  r_input_area = output_area;
1132 }
1133 
1134 } // namespace blender::compositor
typedef float(TangentPoint)[2]
#define CMP_DEFAULT_SMAA_CORNER_ROUNDING
Definition: BKE_node.h:1337
#define CMP_DEFAULT_SMAA_CONTRAST_LIMIT
Definition: BKE_node.h:1336
#define CMP_DEFAULT_SMAA_THRESHOLD
Definition: BKE_node.h:1335
MINLINE float scalenorm(float a, float b, float x)
MINLINE float interpf(float a, float b, float t)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f)
MINLINE void zero_v4(float r[4])
MINLINE void zero_v2(float r[2])
MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v4_v4fl(float r[4], const float a[4], float f)
#define CLAMPIS(a, b, c)
#define UNUSED(x)
#define SMAA_AREATEX_MAX_DISTANCE
#define SMAA_AREATEX_MAX_DISTANCE_DIAG
#define SMAA_AREATEX_SIZE
#define SMAA_MAX_SEARCH_STEPS
#define SMAA_MAX_SEARCH_STEPS_DIAG
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble right
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble top
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble bottom
#define X
Definition: GeomUtils.cpp:199
#define Y
Definition: GeomUtils.cpp:200
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
a MemoryBuffer contains access to the data of a chunk
void read_elem_checked(int x, int y, float *out) const
NodeOperation contains calculation logic.
void add_output_socket(DataType datatype)
SocketReader * get_input_socket_reader(unsigned int index)
NodeOperation * get_input_operation(int index)
void read(float result[4], int x, int y, void *chunk_data)
virtual bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output)
void add_input_socket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
virtual void * initialize_tile_data(rcti *)
void update_memory_buffer_started(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output) override
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
void execute_pixel(float output[4], int x, int y, void *data) override
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output) override
virtual void execute_pixel(float output[4], int x, int y, void *data) override
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void execute_pixel(float output[4], int x, int y, void *data) override
bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output) override
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
SyclQueue void void size_t num_bytes void
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
static int left
#define T
#define L
#define fmaxf(x, y)
Definition: metal/compat.h:228
#define floorf(x)
Definition: metal/compat.h:224
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned c
Definition: RandGen.cpp:83
static void area(int d1, int d2, int e1, int e2, float weights[2])
void expand_area_for_sampler(rcti &area, PixelSampler sampler)
Definition: COM_Enums.cc:8
static void sample_bilinear_vertical(T *reader, int x, int y, float yoffset, float color[4])
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
static const float * areatex_sample_internal(const float *areatex, int x, int y)
static void sample(SocketReader *reader, int x, int y, float color[4])
static void sample_bilinear_horizontal(T *reader, int x, int y, float xoffset, float color[4])
static void area_diag(int d1, int d2, int e1, int e2, float weights[2])
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static bNodeSocketTemplate inputs[]
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63