[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