[Bf-blender-cvs] [dd512e0d3f9] compositor-full-frame: Compositor: Full frame Anti-Aliasing node

Manuel Castilla noreply at git.blender.org
Wed Aug 4 23:03:39 CEST 2021


Commit: dd512e0d3f910a35f6e20ee667ec05cfbbe8e191
Author: Manuel Castilla
Date:   Wed Aug 4 22:48:22 2021 +0200
Branches: compositor-full-frame
https://developer.blender.org/rBdd512e0d3f910a35f6e20ee667ec05cfbbe8e191

Compositor: Full frame Anti-Aliasing node

===================================================================

M	source/blender/compositor/operations/COM_SMAAOperation.cc
M	source/blender/compositor/operations/COM_SMAAOperation.h

===================================================================

diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index b078d85372d..1788a1da408 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -61,6 +61,8 @@ namespace blender::compositor {
 /*-----------------------------------------------------------------------------*/
 /* Internal Functions to Sample Pixel Color from Image */
 
+/* TODO(manzanilla): to be removed with tiled implementation. Replace it with
+ * #buffer->read_elem_checked. */
 static inline void sample(SocketReader *reader, int x, int y, float color[4])
 {
   if (x < 0 || x >= reader->getWidth() || y < 0 || y >= reader->getHeight()) {
@@ -71,8 +73,13 @@ static inline void sample(SocketReader *reader, int x, int y, float color[4])
   reader->read(color, x, y, nullptr);
 }
 
-static void sample_bilinear_vertical(
-    SocketReader *reader, int x, int y, float yoffset, float color[4])
+static inline void sample(MemoryBuffer *reader, int x, int y, float color[4])
+{
+  reader->read_elem_checked(x, y, color);
+}
+
+template<typename T>
+static void sample_bilinear_vertical(T *reader, int x, int y, float yoffset, float color[4])
 {
   float iy = floorf(yoffset);
   float fy = yoffset - iy;
@@ -89,8 +96,8 @@ static void sample_bilinear_vertical(
   color[3] = interpf(color01[3], color00[3], fy);
 }
 
-static void sample_bilinear_horizontal(
-    SocketReader *reader, int x, int y, float xoffset, float color[4])
+template<typename T>
+static void sample_bilinear_horizontal(T *reader, int x, int y, float xoffset, float color[4])
 {
   float ix = floorf(xoffset);
   float fx = xoffset - ix;
@@ -162,7 +169,7 @@ static void area_diag(int d1, int d2, int e1, int e2, float weights[2])
 SMAAEdgeDetectionOperation::SMAAEdgeDetectionOperation()
 {
   this->addInputSocket(DataType::Color); /* image */
-  this->addInputSocket(DataType::Value); /* depth, material ID, etc. */
+  this->addInputSocket(DataType::Value); /* Depth, material ID, etc. TODO: currently unused. */
   this->addOutputSocket(DataType::Color);
   this->flags.complex = true;
   this->m_imageReader = nullptr;
@@ -207,6 +214,16 @@ bool SMAAEdgeDetectionOperation::determineDependingAreaOfInterest(
   return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
 }
 
+void SMAAEdgeDetectionOperation::get_area_of_interest(const int UNUSED(input_idx),
+                                                      const rcti &output_area,
+                                                      rcti &r_input_area)
+{
+  r_input_area.xmax = output_area.xmax + 1;
+  r_input_area.xmin = output_area.xmin - 2;
+  r_input_area.ymax = output_area.ymax + 1;
+  r_input_area.ymin = output_area.ymin - 2;
+}
+
 void SMAAEdgeDetectionOperation::executePixel(float output[4], int x, int y, void * /*data*/)
 {
   float color[4];
@@ -288,6 +305,94 @@ void SMAAEdgeDetectionOperation::executePixel(float output[4], int x, int y, voi
   }
 }
 
+void SMAAEdgeDetectionOperation::update_memory_buffer_partial(MemoryBuffer *output,
+                                                              const rcti &area,
+                                                              Span<MemoryBuffer *> inputs)
+{
+  const MemoryBuffer *image = inputs[0];
+  for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
+    float color[4];
+    const int x = it.x;
+    const int y = it.y;
+
+    /* Calculate luma deltas: */
+    image->read_elem_checked(x, y, color);
+    const float L = IMB_colormanagement_get_luminance(color);
+    image->read_elem_checked(x - 1, y, color);
+    const float Lleft = IMB_colormanagement_get_luminance(color);
+    image->read_elem_checked(x, y - 1, color);
+    const float Ltop = IMB_colormanagement_get_luminance(color);
+    const float Dleft = fabsf(L - Lleft);
+    const float Dtop = fabsf(L - Ltop);
+
+    /* We do the usual threshold: */
+    it.out[0] = (x > 0 && Dleft >= m_threshold) ? 1.0f : 0.0f;
+    it.out[1] = (y > 0 && Dtop >= m_threshold) ? 1.0f : 0.0f;
+    it.out[2] = 0.0f;
+    it.out[3] = 1.0f;
+
+    /* Then discard if there is no edge: */
+    if (is_zero_v2(it.out)) {
+      continue;
+    }
+
+    /* Calculate right and bottom deltas: */
+    image->read_elem_checked(x + 1, y, color);
+    const float Lright = IMB_colormanagement_get_luminance(color);
+    image->read_elem_checked(x, y + 1, color);
+    const float Lbottom = IMB_colormanagement_get_luminance(color);
+    const float Dright = fabsf(L - Lright);
+    const float Dbottom = fabsf(L - Lbottom);
+
+    /* Calculate the maximum delta in the direct neighborhood: */
+    float maxDelta = fmaxf(fmaxf(Dleft, Dright), fmaxf(Dtop, Dbottom));
+
+    /* Calculate luma used for both left and top edges: */
+    image->read_elem_checked(x - 1, y - 1, color);
+    const float Llefttop = IMB_colormanagement_get_luminance(color);
+
+    /* Left edge */
+    if (it.out[0] != 0.0f) {
+      /* Calculate deltas around the left pixel: */
+      image->read_elem_checked(x - 2, y, color);
+      const float Lleftleft = IMB_colormanagement_get_luminance(color);
+      image->read_elem_checked(x - 1, y + 1, color);
+      const float Lleftbottom = IMB_colormanagement_get_luminance(color);
+      const float Dleftleft = fabsf(Lleft - Lleftleft);
+      const float Dlefttop = fabsf(Lleft - Llefttop);
+      const float Dleftbottom = fabsf(Lleft - Lleftbottom);
+
+      /* Calculate the final maximum delta: */
+      maxDelta = fmaxf(maxDelta, fmaxf(Dleftleft, fmaxf(Dlefttop, Dleftbottom)));
+
+      /* Local contrast adaptation: */
+      if (maxDelta > m_contrast_limit * Dleft) {
+        it.out[0] = 0.0f;
+      }
+    }
+
+    /* Top edge */
+    if (it.out[1] != 0.0f) {
+      /* Calculate top-top delta: */
+      image->read_elem_checked(x, y - 2, color);
+      const float Ltoptop = IMB_colormanagement_get_luminance(color);
+      image->read_elem_checked(x + 1, y - 1, color);
+      const float Ltopright = IMB_colormanagement_get_luminance(color);
+      const float Dtoptop = fabsf(Ltop - Ltoptop);
+      const float Dtopleft = fabsf(Ltop - Llefttop);
+      const float Dtopright = fabsf(Ltop - Ltopright);
+
+      /* Calculate the final maximum delta: */
+      maxDelta = fmaxf(maxDelta, fmaxf(Dtoptop, fmaxf(Dtopleft, Dtopright)));
+
+      /* Local contrast adaptation: */
+      if (maxDelta > m_contrast_limit * Dtop) {
+        it.out[1] = 0.0f;
+      }
+    }
+  }
+}
+
 /*-----------------------------------------------------------------------------*/
 /* Blending Weight Calculation (Second Pass) */
 /*-----------------------------------------------------------------------------*/
@@ -309,6 +414,9 @@ void *SMAABlendingWeightCalculationOperation::initializeTileData(rcti *rect)
 void SMAABlendingWeightCalculationOperation::initExecution()
 {
   this->m_imageReader = this->getInputSocketReader(0);
+  if (execution_model_ == eExecutionModel::Tiled) {
+    sample_image_fn_ = [=](int x, int y, float *out) { sample(m_imageReader, x, y, out); };
+  }
 }
 
 void SMAABlendingWeightCalculationOperation::setCornerRounding(float rounding)
@@ -414,6 +522,113 @@ void SMAABlendingWeightCalculationOperation::executePixel(float output[4],
   }
 }
 
+void SMAABlendingWeightCalculationOperation::update_memory_buffer_started(
+    MemoryBuffer *UNUSED(output), const rcti &UNUSED(out_area), Span<MemoryBuffer *> inputs)
+{
+  const MemoryBuffer *image = inputs[0];
+  sample_image_fn_ = [=](int x, int y, float *out) { image->read_elem_checked(x, y, out); };
+}
+
+void SMAABlendingWeightCalculationOperation::update_memory_buffer_partial(
+    MemoryBuffer *output, const rcti &out_area, Span<MemoryBuffer *> inputs)
+{
+  for (BuffersIterator<float> it = output->iterate_with({}, out_area); !it.is_end(); ++it) {
+    const int x = it.x;
+    const int y = it.y;
+    zero_v4(it.out);
+
+    float edges[4];
+    sample_image_fn_(x, y, edges);
+
+    /* Edge at north */
+    float c[4];
+    if (edges[1] > 0.0f) {
+      /* Diagonals have both north and west edges, so calculating weights for them */
+      /* in one of the boundaries is enough. */
+      calculateDiagWeights(x, y, edges, it.out);
+
+      /* We give priority to diagonals, so if we find a diagonal we skip. */
+      /* horizontal/vertical processing. */
+      if (!is_zero_v2(it.out)) {
+        continue;
+      }
+
+      /* Find the distance to the left and the right: */
+      int left = searchXLeft(x, y);
+      int right = searchXRight(x, y);
+      int d1 = x - left, d2 = right - x;
+
+      /* Fetch the left and right crossing edges: */
+      int e1 = 0, e2 = 0;
+      sample_image_fn_(left, y - 1, c);
+      if (c[0] > 0.0) {
+        e1 += 1;
+      }
+      sample_image_fn_(left, y, c);
+      if (c[0] > 0.0) {
+        e1 += 2;
+      }
+      sample_image_fn_(right + 1, y - 1, c);
+      if (c[0] > 0.0) {
+        e2 += 1;
+      }
+      sample_image_fn_(right + 1, y, c);
+      if (c[0] > 0.0) {
+        e2 += 2;
+      }
+
+      /* Ok, we know how this pattern looks like, now it is time for getting */
+      /* the actual area: */
+      area(d1, d2, e1, e2, it.out); /* R, G */
+
+      /* Fix corners: */
+      if (m_corner_rounding) {
+        detectHorizontalCornerPattern(it.out, left, right, y, d1, d2);
+      }
+    }
+
+    /* Edge at west */
+    if (edges[0] > 0.0f) {
+      /* Did we already do diagonal search for this west edge from the left neighboring pixel? */
+      if (isVerticalSearchUnneeded(x, y)) {
+        continue;
+      }
+
+      /* Find the distance to the top and the bottom: */
+      int top = searchYUp(x, y);
+      int bottom = searchYDown(x, y);
+      int d1 = y - top, d2 = bottom - y;
+
+      /* Fetch the top and bottom crossing edges: */
+      int e1 = 0, e2 = 0;
+      sample_image_fn_(x - 1, top, c);
+      if (c[1] > 0.0) {
+        e1 += 1;
+      }
+      sample_image_fn_(x, top, c);
+      if (c[1] > 0.0) {
+        e1 += 2;
+      }
+      sample_image_fn_(x - 1, bottom + 1, c);
+      if (c[1] > 0.0) {
+        e2 += 1;
+      }
+      sample_image_fn_(x, bottom + 1, c);
+      i

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list