Compositor: Implement Tone Map for new CPU compositor

Reference #125968.
This commit is contained in:
Omar Emara
2024-11-07 15:25:59 +02:00
parent 8464d95c4c
commit ece5f08852

View File

@@ -84,17 +84,6 @@ class ToneMapOperation : public NodeOperation {
void execute() override
{
/* Not yet supported on CPU. */
if (!context().use_gpu()) {
for (const bNodeSocket *output : this->node()->output_sockets()) {
Result &output_result = get_result(output->identifier);
if (output_result.should_compute()) {
output_result.allocate_invalid();
}
}
return;
}
Result &input_image = get_input("Image");
Result &output_image = get_result("Image");
if (input_image.is_single_value()) {
@@ -119,6 +108,16 @@ class ToneMapOperation : public NodeOperation {
* for digital images." Proceedings of the 29th annual conference on Computer graphics and
* interactive techniques. 2002. */
void execute_simple()
{
if (this->context().use_gpu()) {
execute_simple_gpu();
}
else {
execute_simple_cpu();
}
}
void execute_simple_gpu()
{
const float luminance_scale = compute_luminance_scale();
const float luminance_scale_blend_factor = compute_luminance_scale_blend_factor();
@@ -147,6 +146,38 @@ class ToneMapOperation : public NodeOperation {
input_image.unbind_as_texture();
}
void execute_simple_cpu()
{
const float luminance_scale = compute_luminance_scale();
const float luminance_scale_blend_factor = compute_luminance_scale_blend_factor();
const float gamma = node_storage(bnode()).gamma;
const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f;
const Result &image = get_input("Image");
const Domain domain = compute_domain();
Result &output = get_result("Image");
output.allocate_texture(domain);
parallel_for(domain.size, [&](const int2 texel) {
float4 input_color = image.load_pixel(texel);
/* Equation (2) from Reinhard's 2002 paper. */
float4 scaled_color = input_color * luminance_scale;
/* Equation (3) from Reinhard's 2002 paper, but with the 1 replaced with the blend factor for
* more flexibility. See ToneMapOperation::compute_luminance_scale_blend_factor. */
float4 denominator = luminance_scale_blend_factor + scaled_color;
float4 tone_mapped_color = math::safe_divide(scaled_color, denominator);
if (inverse_gamma != 0.0f) {
tone_mapped_color = math::pow(math::max(tone_mapped_color, float4(0.0f)), inverse_gamma);
}
output.store_pixel(texel, float4(tone_mapped_color.xyz(), input_color.w));
});
}
/* Computes the scaling factor in equation (2) from Reinhard's 2002 paper. */
float compute_luminance_scale()
{
@@ -179,6 +210,16 @@ class ToneMapOperation : public NodeOperation {
* (7) from Reinhard, Erik, and Kate Devlin. "Dynamic range reduction inspired by photoreceptor
* physiology." IEEE transactions on visualization and computer graphics 11.1 (2005): 13-24. */
void execute_photoreceptor()
{
if (this->context().use_gpu()) {
execute_photoreceptor_gpu();
}
else {
execute_photoreceptor_cpu();
}
}
void execute_photoreceptor_gpu()
{
const float4 global_adaptation_level = compute_global_adaptation_level();
const float contrast = compute_contrast();
@@ -214,6 +255,41 @@ class ToneMapOperation : public NodeOperation {
input_image.unbind_as_texture();
}
void execute_photoreceptor_cpu()
{
const float4 global_adaptation_level = compute_global_adaptation_level();
const float contrast = compute_contrast();
const float intensity = compute_intensity();
const float chromatic_adaptation = get_chromatic_adaptation();
const float light_adaptation = get_light_adaptation();
float3 luminance_coefficients;
IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
const Result &input = get_input("Image");
const Domain domain = compute_domain();
Result &output = get_result("Image");
output.allocate_texture(domain);
parallel_for(domain.size, [&](const int2 texel) {
float4 input_color = input.load_pixel(texel);
float input_luminance = math::dot(input_color.xyz(), luminance_coefficients);
/* Trilinear interpolation between equations (6) and (7) from Reinhard's 2005 paper. */
float4 local_adaptation_level = math::interpolate(
float4(input_luminance), input_color, chromatic_adaptation);
float4 adaptation_level = math::interpolate(
global_adaptation_level, local_adaptation_level, light_adaptation);
/* Equation (1) from Reinhard's 2005 paper, assuming Vmax is 1. */
float4 semi_saturation = math::pow(intensity * adaptation_level, contrast);
float4 tone_mapped_color = input_color / (input_color + semi_saturation);
output.store_pixel(texel, float4(tone_mapped_color.xyz(), input_color.w));
});
}
/* Computes the global adaptation level from the trilinear interpolation equations constructed
* from equations (6) and (7) in Reinhard's 2005 paper. */
float4 compute_global_adaptation_level()