[Bf-blender-cvs] [6acbb085389] compositor-full-frame: Compositor: Full frame Tonemap node

Manuel Castilla noreply at git.blender.org
Thu Jul 29 22:36:40 CEST 2021


Commit: 6acbb08538905a600bd92317969958e9b31debab
Author: Manuel Castilla
Date:   Thu Jul 29 13:25:25 2021 +0200
Branches: compositor-full-frame
https://developer.blender.org/rB6acbb08538905a600bd92317969958e9b31debab

Compositor: Full frame Tonemap node

Adds full frame implementation to this node operations.
No functional changes.

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

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

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

diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cc b/source/blender/compositor/operations/COM_TonemapOperation.cc
index 6bfacb0c75d..4d7e15603a7 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.cc
+++ b/source/blender/compositor/operations/COM_TonemapOperation.cc
@@ -16,12 +16,14 @@
  * Copyright 2011, Blender Foundation.
  */
 
+#include "IMB_colormanagement.h"
+
+#include "COM_ExecutionSystem.h"
 #include "COM_TonemapOperation.h"
+
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 
-#include "IMB_colormanagement.h"
-
 namespace blender::compositor {
 
 TonemapOperation::TonemapOperation()
@@ -153,4 +155,125 @@ void TonemapOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
   /* pass */
 }
 
+void TonemapOperation::get_area_of_interest(const int input_idx,
+                                            const rcti &UNUSED(output_area),
+                                            rcti &r_input_area)
+{
+  BLI_assert(input_idx == 0);
+  NodeOperation *operation = getInputOperation(input_idx);
+  r_input_area.xmin = 0;
+  r_input_area.ymin = 0;
+  r_input_area.xmax = operation->getWidth();
+  r_input_area.ymax = operation->getHeight();
+}
+
+struct Luminance {
+  float sum;
+  float color_sum[3];
+  float log_sum;
+  float min;
+  float max;
+  int num_pixels;
+};
+
+static Luminance calc_area_luminance(const MemoryBuffer *input, const rcti &area)
+{
+  Luminance lum = {0};
+  for (const float *elem : input->get_buffer_area(area)) {
+    const float lu = IMB_colormanagement_get_luminance(elem);
+    lum.sum += lu;
+    add_v3_v3(lum.color_sum, elem);
+    lum.log_sum += logf(MAX2(lu, 0.0f) + 1e-5f);
+    lum.max = MAX2(lu, lum.max);
+    lum.min = MIN2(lu, lum.min);
+    lum.num_pixels++;
+  }
+  return lum;
+}
+
+void TonemapOperation::update_memory_buffer_started(MemoryBuffer *UNUSED(output),
+                                                    const rcti &UNUSED(area),
+                                                    Span<MemoryBuffer *> inputs)
+{
+  if (this->m_cachedInstance == nullptr) {
+    Luminance lum = {0};
+    const MemoryBuffer *input = inputs[0];
+    exec_system_->execute_work<Luminance>(
+        input->get_rect(),
+        [=](const rcti &split) { return calc_area_luminance(input, split); },
+        lum,
+        [](Luminance &join, const Luminance &chunk) {
+          join.sum += chunk.sum;
+          add_v3_v3(join.color_sum, chunk.color_sum);
+          join.log_sum += chunk.log_sum;
+          join.max = MAX2(join.max, chunk.max);
+          join.min = MIN2(join.min, chunk.min);
+          join.num_pixels += chunk.num_pixels;
+        });
+
+    AvgLogLum *avg = new AvgLogLum();
+    avg->lav = lum.sum / lum.num_pixels;
+    mul_v3_v3fl(avg->cav, lum.color_sum, 1.0f / lum.num_pixels);
+    const float max_log = log((double)lum.max + 1e-5);
+    const float min_log = log((double)lum.min + 1e-5);
+    const float avg_log = lum.log_sum / lum.num_pixels;
+    avg->auto_key = (max_log > min_log) ? ((max_log - avg_log) / (max_log - min_log)) : 1.0f;
+    const float al = exp((double)avg_log);
+    avg->al = (al == 0.0f) ? 0.0f : (this->m_data->key / al);
+    avg->igm = (this->m_data->gamma == 0.0f) ? 1 : (1.0f / this->m_data->gamma);
+    this->m_cachedInstance = avg;
+  }
+}
+
+void TonemapOperation::update_memory_buffer_partial(MemoryBuffer *output,
+                                                    const rcti &area,
+                                                    Span<MemoryBuffer *> inputs)
+{
+  AvgLogLum *avg = m_cachedInstance;
+  const float igm = avg->igm;
+  for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+    copy_v4_v4(it.out, it.in(0));
+    mul_v3_fl(it.out, avg->al);
+    float dr = it.out[0] + this->m_data->offset;
+    float dg = it.out[1] + this->m_data->offset;
+    float db = it.out[2] + this->m_data->offset;
+    it.out[0] /= ((dr == 0.0f) ? 1.0f : dr);
+    it.out[1] /= ((dg == 0.0f) ? 1.0f : dg);
+    it.out[2] /= ((db == 0.0f) ? 1.0f : db);
+    if (igm != 0.0f) {
+      it.out[0] = powf(MAX2(it.out[0], 0.0f), igm);
+      it.out[1] = powf(MAX2(it.out[1], 0.0f), igm);
+      it.out[2] = powf(MAX2(it.out[2], 0.0f), igm);
+    }
+  }
+}
+
+void PhotoreceptorTonemapOperation::update_memory_buffer_partial(MemoryBuffer *output,
+                                                                 const rcti &area,
+                                                                 Span<MemoryBuffer *> inputs)
+{
+  AvgLogLum *avg = m_cachedInstance;
+  NodeTonemap *ntm = this->m_data;
+  const float f = expf(-this->m_data->f);
+  const float m = (ntm->m > 0.0f) ? ntm->m : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
+  const float ic = 1.0f - ntm->c;
+  const float ia = 1.0f - ntm->a;
+  for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+    copy_v4_v4(it.out, it.in(0));
+    const float L = IMB_colormanagement_get_luminance(it.out);
+    float I_l = it.out[0] + ic * (L - it.out[0]);
+    float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
+    float I_a = I_l + ia * (I_g - I_l);
+    it.out[0] /= (it.out[0] + powf(f * I_a, m));
+    I_l = it.out[1] + ic * (L - it.out[1]);
+    I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
+    I_a = I_l + ia * (I_g - I_l);
+    it.out[1] /= (it.out[1] + powf(f * I_a, m));
+    I_l = it.out[2] + ic * (L - it.out[2]);
+    I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
+    I_a = I_l + ia * (I_g - I_l);
+    it.out[2] /= (it.out[2] + powf(f * I_a, m));
+  }
+}
+
 }  // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.h b/source/blender/compositor/operations/COM_TonemapOperation.h
index 7ecb179504d..56b57730ec1 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.h
+++ b/source/blender/compositor/operations/COM_TonemapOperation.h
@@ -18,7 +18,7 @@
 
 #pragma once
 
-#include "COM_NodeOperation.h"
+#include "COM_MultiThreadedOperation.h"
 #include "DNA_node_types.h"
 
 namespace blender::compositor {
@@ -39,7 +39,7 @@ typedef struct AvgLogLum {
  * \brief base class of tonemap, implementing the simple tonemap
  * \ingroup operation
  */
-class TonemapOperation : public NodeOperation {
+class TonemapOperation : public MultiThreadedOperation {
  protected:
   /**
    * \brief Cached reference to the reader
@@ -85,6 +85,14 @@ class TonemapOperation : public NodeOperation {
   bool determineDependingAreaOfInterest(rcti *input,
                                         ReadBufferOperation *readOperation,
                                         rcti *output) override;
+
+  void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
+  void update_memory_buffer_started(MemoryBuffer *output,
+                                    const rcti &area,
+                                    Span<MemoryBuffer *> inputs) override;
+  virtual void update_memory_buffer_partial(MemoryBuffer *output,
+                                            const rcti &area,
+                                            Span<MemoryBuffer *> inputs) override;
 };
 
 /**
@@ -99,6 +107,10 @@ class PhotoreceptorTonemapOperation : public TonemapOperation {
    * The inner loop of this operation.
    */
   void executePixel(float output[4], int x, int y, void *data) override;
+
+  void update_memory_buffer_partial(MemoryBuffer *output,
+                                    const rcti &area,
+                                    Span<MemoryBuffer *> inputs) override;
 };
 
 }  // namespace blender::compositor



More information about the Bf-blender-cvs mailing list