diff options
author | Manuel Castilla <manzanillawork@gmail.com> | 2021-07-29 14:25:25 +0300 |
---|---|---|
committer | Manuel Castilla <manzanillawork@gmail.com> | 2021-07-29 14:25:25 +0300 |
commit | 6acbb08538905a600bd92317969958e9b31debab (patch) | |
tree | 1ad69af291618f8ae4cd9cfb2ec8bf602bfcdb6c /source/blender/compositor/operations | |
parent | 417262e8f8461b7cfa4f9336c890e46a5a0b94a9 (diff) |
Compositor: Full frame Tonemap node
Adds full frame implementation to this node operations.
No functional changes.
Diffstat (limited to 'source/blender/compositor/operations')
-rw-r--r-- | source/blender/compositor/operations/COM_TonemapOperation.cc | 127 | ||||
-rw-r--r-- | source/blender/compositor/operations/COM_TonemapOperation.h | 16 |
2 files changed, 139 insertions, 4 deletions
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 |