Compositor: Port GLSL SMAA to CPU compositor
This patch ports the GLSL SMAA library to the CPU compositor in order to unify the anti-aliasing behavior between the CPU and GPU compositor. Additionally, the SMAA texture generator was removed since it is now unused. Previously, we used an external C++ library for SMAA anti-aliasing, which is itself a port of the GLSL SMAA library. However, the code structure and results of the library were different, which made it quite difficult to match results between CPU and GPU, hence the decision to port the library ourselves. The port was performed through a complete copy of the library to C++, retaining the same function and variable names, even if they are different from Blender's naming conversions. The necessary code changes were done to make it work in C++, including manually doing swizzling which changes the code structure a bit. Even after porting the library, there were still major differences between CPU and GPU, due to different arithmetic precision. To fix this some of the bilinear samplers used in branches and selections were carefully changed to use point samplers to avoid discontinuities around branches, also resulting in a nice performance improvement. Some slight differences still exist due to different bilinear interpolation, but they shall be looked into later once we have a baseline implementation. The new implementation is slower than the existing implementation, most likely due to the liberal use of bilinear interpolation, since it is quite cheap on GPUs and the code even does more work to use bilinear interpolation to avoid multiple texture fetches, except this causes a slow down on CPUs. Some of those were alleviated as mentioned in the previous section, but we can probably look into optimizing it further. Pull Request: https://projects.blender.org/blender/blender/pulls/119414
This commit is contained in:
parent
9d88fa483c
commit
fa3e47523e
|
@ -104,10 +104,6 @@ if(WITH_MOD_FLUID)
|
|||
add_subdirectory(mantaflow)
|
||||
endif()
|
||||
|
||||
if(WITH_COMPOSITOR_CPU)
|
||||
add_subdirectory(smaa_areatex)
|
||||
endif()
|
||||
|
||||
if(WITH_VULKAN_BACKEND)
|
||||
add_subdirectory(vulkan_memory_allocator)
|
||||
endif()
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2017 Blender Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
add_executable(smaa_areatex smaa_areatex.cpp)
|
|
@ -1,5 +0,0 @@
|
|||
Project: smaa-cpp
|
||||
URL: https://github.com/iRi-E/smaa-cpp
|
||||
License: MIT
|
||||
Upstream version: 0.4.0
|
||||
Local modifications:
|
File diff suppressed because it is too large
Load Diff
|
@ -584,20 +584,6 @@ if(WITH_COMPOSITOR_CPU)
|
|||
${CMAKE_CURRENT_BINARY_DIR}/operations
|
||||
)
|
||||
|
||||
set(GENSRC_DIR ${CMAKE_CURRENT_BINARY_DIR}/operations)
|
||||
set(GENSRC ${GENSRC_DIR}/COM_SMAAAreaTexture.h)
|
||||
add_custom_command(
|
||||
OUTPUT ${GENSRC}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${GENSRC_DIR}
|
||||
COMMAND "$<TARGET_FILE:smaa_areatex>" ${GENSRC}
|
||||
DEPENDS smaa_areatex
|
||||
)
|
||||
list(APPEND SRC
|
||||
${GENSRC}
|
||||
)
|
||||
unset(GENSRC)
|
||||
unset(GENSRC_DIR)
|
||||
|
||||
if(WITH_OPENIMAGEDENOISE)
|
||||
add_definitions(-DWITH_OPENIMAGEDENOISE)
|
||||
add_definitions(-DOIDN_STATIC_LIB)
|
||||
|
|
|
@ -7,37 +7,41 @@
|
|||
|
||||
namespace blender::compositor {
|
||||
|
||||
/* Blender encodes the threshold in the [0, 1] range, while the SMAA algorithm expects it in
|
||||
* the [0, 0.5] range. */
|
||||
static float get_threshold(const NodeAntiAliasingData *data)
|
||||
{
|
||||
return data->threshold / 2.0f;
|
||||
}
|
||||
|
||||
/* Blender encodes the local contrast adaptation factor in the [0, 1] range, while the SMAA
|
||||
* algorithm expects it in the [0, 10] range. */
|
||||
static float get_local_contrast_adaptation_factor(const NodeAntiAliasingData *data)
|
||||
{
|
||||
return data->contrast_limit * 10.0f;
|
||||
}
|
||||
|
||||
/* Blender encodes the corner rounding factor in the float [0, 1] range, while the SMAA algorithm
|
||||
* expects it in the integer [0, 100] range. */
|
||||
static int get_corner_rounding(const NodeAntiAliasingData *data)
|
||||
{
|
||||
return int(data->corner_rounding * 100.0f);
|
||||
}
|
||||
|
||||
void AntiAliasingNode::convert_to_operations(NodeConverter &converter,
|
||||
const CompositorContext & /*context*/) const
|
||||
{
|
||||
const bNode *node = this->get_bnode();
|
||||
const NodeAntiAliasingData *data = (const NodeAntiAliasingData *)node->storage;
|
||||
|
||||
/* Edge Detection (First Pass) */
|
||||
SMAAEdgeDetectionOperation *operation1 = nullptr;
|
||||
SMAAOperation *operation = new SMAAOperation();
|
||||
operation->set_threshold(get_threshold(data));
|
||||
operation->set_local_contrast_adaptation_factor(get_local_contrast_adaptation_factor(data));
|
||||
operation->set_corner_rounding(get_corner_rounding(data));
|
||||
converter.add_operation(operation);
|
||||
|
||||
operation1 = new SMAAEdgeDetectionOperation();
|
||||
operation1->set_threshold(data->threshold);
|
||||
operation1->set_local_contrast_adaptation_factor(data->contrast_limit);
|
||||
converter.add_operation(operation1);
|
||||
|
||||
converter.map_input_socket(get_input_socket(0), operation1->get_input_socket(0));
|
||||
|
||||
/* Blending Weight Calculation Pixel Shader (Second Pass) */
|
||||
SMAABlendingWeightCalculationOperation *operation2 =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
operation2->set_corner_rounding(data->corner_rounding);
|
||||
converter.add_operation(operation2);
|
||||
|
||||
converter.add_link(operation1->get_output_socket(), operation2->get_input_socket(0));
|
||||
|
||||
/* Neighborhood Blending Pixel Shader (Third Pass) */
|
||||
SMAANeighborhoodBlendingOperation *operation3 = new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(operation3);
|
||||
|
||||
converter.map_input_socket(get_input_socket(0), operation3->get_input_socket(0));
|
||||
converter.add_link(operation2->get_output_socket(), operation3->get_input_socket(1));
|
||||
converter.map_output_socket(get_output_socket(0), operation3->get_output_socket());
|
||||
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
|
||||
converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -18,28 +18,13 @@ void CornerPinNode::convert_to_operations(NodeConverter &converter,
|
|||
PlaneCornerPinMaskOperation *plane_mask_operation = new PlaneCornerPinMaskOperation();
|
||||
converter.add_operation(plane_mask_operation);
|
||||
|
||||
SMAAEdgeDetectionOperation *smaa_edge_detection = new SMAAEdgeDetectionOperation();
|
||||
converter.add_operation(smaa_edge_detection);
|
||||
SMAAOperation *smaa_operation = new SMAAOperation();
|
||||
converter.add_operation(smaa_operation);
|
||||
|
||||
converter.add_link(plane_mask_operation->get_output_socket(),
|
||||
smaa_edge_detection->get_input_socket(0));
|
||||
smaa_operation->get_input_socket(0));
|
||||
|
||||
SMAABlendingWeightCalculationOperation *smaa_blending_weights =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
converter.add_operation(smaa_blending_weights);
|
||||
|
||||
converter.add_link(smaa_edge_detection->get_output_socket(),
|
||||
smaa_blending_weights->get_input_socket(0));
|
||||
|
||||
SMAANeighborhoodBlendingOperation *smaa_neighborhood = new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(smaa_neighborhood);
|
||||
|
||||
converter.add_link(plane_mask_operation->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(0));
|
||||
converter.add_link(smaa_blending_weights->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(1));
|
||||
|
||||
converter.map_output_socket(this->get_output_socket(1), smaa_neighborhood->get_output_socket());
|
||||
converter.map_output_socket(this->get_output_socket(1), smaa_operation->get_output_socket());
|
||||
|
||||
PlaneCornerPinWarpImageOperation *warp_image_operation = new PlaneCornerPinWarpImageOperation();
|
||||
converter.add_operation(warp_image_operation);
|
||||
|
@ -62,7 +47,7 @@ void CornerPinNode::convert_to_operations(NodeConverter &converter,
|
|||
converter.add_operation(set_alpha_operation);
|
||||
converter.add_link(warp_image_operation->get_output_socket(),
|
||||
set_alpha_operation->get_input_socket(0));
|
||||
converter.add_link(smaa_neighborhood->get_output_socket(),
|
||||
converter.add_link(smaa_operation->get_output_socket(),
|
||||
set_alpha_operation->get_input_socket(1));
|
||||
converter.map_output_socket(this->get_output_socket(0),
|
||||
set_alpha_operation->get_output_socket());
|
||||
|
|
|
@ -37,26 +37,10 @@ void DilateErodeNode::convert_to_operations(NodeConverter &converter,
|
|||
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
|
||||
|
||||
if (editor_node->custom3 < 2.0f) {
|
||||
SMAAEdgeDetectionOperation *smaa_edge_detection = new SMAAEdgeDetectionOperation();
|
||||
converter.add_operation(smaa_edge_detection);
|
||||
|
||||
converter.add_link(operation->get_output_socket(), smaa_edge_detection->get_input_socket(0));
|
||||
|
||||
SMAABlendingWeightCalculationOperation *smaa_blending_weights =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
converter.add_operation(smaa_blending_weights);
|
||||
|
||||
converter.add_link(smaa_edge_detection->get_output_socket(),
|
||||
smaa_blending_weights->get_input_socket(0));
|
||||
|
||||
SMAANeighborhoodBlendingOperation *smaa_neighborhood =
|
||||
new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(smaa_neighborhood);
|
||||
|
||||
converter.add_link(operation->get_output_socket(), smaa_neighborhood->get_input_socket(0));
|
||||
converter.add_link(smaa_blending_weights->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(1));
|
||||
converter.map_output_socket(get_output_socket(0), smaa_neighborhood->get_output_socket());
|
||||
SMAAOperation *smaa_operation = new SMAAOperation();
|
||||
converter.add_operation(smaa_operation);
|
||||
converter.add_link(operation->get_output_socket(), smaa_operation->get_input_socket(0));
|
||||
converter.map_output_socket(get_output_socket(0), smaa_operation->get_output_socket());
|
||||
}
|
||||
else {
|
||||
converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
|
||||
|
|
|
@ -27,27 +27,10 @@ void IDMaskNode::convert_to_operations(NodeConverter &converter,
|
|||
converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
|
||||
}
|
||||
else {
|
||||
SMAAEdgeDetectionOperation *operation1 = nullptr;
|
||||
|
||||
operation1 = new SMAAEdgeDetectionOperation();
|
||||
converter.add_operation(operation1);
|
||||
|
||||
converter.add_link(operation->get_output_socket(0), operation1->get_input_socket(0));
|
||||
|
||||
/* Blending Weight Calculation Pixel Shader (Second Pass). */
|
||||
SMAABlendingWeightCalculationOperation *operation2 =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
converter.add_operation(operation2);
|
||||
|
||||
converter.add_link(operation1->get_output_socket(), operation2->get_input_socket(0));
|
||||
|
||||
/* Neighborhood Blending Pixel Shader (Third Pass). */
|
||||
SMAANeighborhoodBlendingOperation *operation3 = new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(operation3);
|
||||
|
||||
converter.add_link(operation->get_output_socket(0), operation3->get_input_socket(0));
|
||||
converter.add_link(operation2->get_output_socket(), operation3->get_input_socket(1));
|
||||
converter.map_output_socket(get_output_socket(0), operation3->get_output_socket());
|
||||
SMAAOperation *smaa_operation = new SMAAOperation();
|
||||
converter.add_operation(smaa_operation);
|
||||
converter.add_link(operation->get_output_socket(0), smaa_operation->get_input_socket(0));
|
||||
converter.map_output_socket(get_output_socket(0), smaa_operation->get_output_socket());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,28 +35,13 @@ void PlaneTrackDeformNode::convert_to_operations(NodeConverter &converter,
|
|||
}
|
||||
converter.add_operation(plane_mask_operation);
|
||||
|
||||
SMAAEdgeDetectionOperation *smaa_edge_detection = new SMAAEdgeDetectionOperation();
|
||||
converter.add_operation(smaa_edge_detection);
|
||||
SMAAOperation *smaa_operation = new SMAAOperation();
|
||||
converter.add_operation(smaa_operation);
|
||||
|
||||
converter.add_link(plane_mask_operation->get_output_socket(),
|
||||
smaa_edge_detection->get_input_socket(0));
|
||||
smaa_operation->get_input_socket(0));
|
||||
|
||||
SMAABlendingWeightCalculationOperation *smaa_blending_weights =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
converter.add_operation(smaa_blending_weights);
|
||||
|
||||
converter.add_link(smaa_edge_detection->get_output_socket(),
|
||||
smaa_blending_weights->get_input_socket(0));
|
||||
|
||||
SMAANeighborhoodBlendingOperation *smaa_neighborhood = new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(smaa_neighborhood);
|
||||
|
||||
converter.add_link(plane_mask_operation->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(0));
|
||||
converter.add_link(smaa_blending_weights->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(1));
|
||||
|
||||
converter.map_output_socket(this->get_output_socket(1), smaa_neighborhood->get_output_socket());
|
||||
converter.map_output_socket(this->get_output_socket(1), smaa_operation->get_output_socket());
|
||||
|
||||
PlaneTrackWarpImageOperation *warp_image_operation = new PlaneTrackWarpImageOperation();
|
||||
warp_image_operation->set_movie_clip(clip);
|
||||
|
@ -75,7 +60,7 @@ void PlaneTrackDeformNode::convert_to_operations(NodeConverter &converter,
|
|||
converter.add_operation(set_alpha_operation);
|
||||
converter.add_link(warp_image_operation->get_output_socket(),
|
||||
set_alpha_operation->get_input_socket(0));
|
||||
converter.add_link(smaa_neighborhood->get_output_socket(),
|
||||
converter.add_link(smaa_operation->get_output_socket(),
|
||||
set_alpha_operation->get_input_socket(1));
|
||||
converter.map_output_socket(this->get_output_socket(0),
|
||||
set_alpha_operation->get_output_socket());
|
||||
|
|
|
@ -54,25 +54,10 @@ void ZCombineNode::convert_to_operations(NodeConverter &converter,
|
|||
converter.map_input_socket(get_input_socket(3), maskoperation->get_input_socket(1));
|
||||
|
||||
/* Step 2 anti alias mask bit of an expensive operation, but does the trick. */
|
||||
SMAAEdgeDetectionOperation *smaa_edge_detection = new SMAAEdgeDetectionOperation();
|
||||
converter.add_operation(smaa_edge_detection);
|
||||
SMAAOperation *smaa_operation = new SMAAOperation();
|
||||
converter.add_operation(smaa_operation);
|
||||
|
||||
converter.add_link(maskoperation->get_output_socket(),
|
||||
smaa_edge_detection->get_input_socket(0));
|
||||
|
||||
SMAABlendingWeightCalculationOperation *smaa_blending_weights =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
converter.add_operation(smaa_blending_weights);
|
||||
|
||||
converter.add_link(smaa_edge_detection->get_output_socket(),
|
||||
smaa_blending_weights->get_input_socket(0));
|
||||
|
||||
SMAANeighborhoodBlendingOperation *smaa_neighborhood = new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(smaa_neighborhood);
|
||||
|
||||
converter.add_link(maskoperation->get_output_socket(), smaa_neighborhood->get_input_socket(0));
|
||||
converter.add_link(smaa_blending_weights->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(1));
|
||||
converter.add_link(maskoperation->get_output_socket(), smaa_operation->get_input_socket(0));
|
||||
|
||||
/* use mask to blend between the input colors. */
|
||||
ZCombineMaskOperation *zcombineoperation = this->get_bnode()->custom1 ?
|
||||
|
@ -80,7 +65,7 @@ void ZCombineNode::convert_to_operations(NodeConverter &converter,
|
|||
new ZCombineMaskOperation();
|
||||
converter.add_operation(zcombineoperation);
|
||||
|
||||
converter.add_link(smaa_neighborhood->get_output_socket(),
|
||||
converter.add_link(smaa_operation->get_output_socket(),
|
||||
zcombineoperation->get_input_socket(0));
|
||||
converter.map_input_socket(get_input_socket(0), zcombineoperation->get_input_socket(1));
|
||||
converter.map_input_socket(get_input_socket(2), zcombineoperation->get_input_socket(2));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,89 +4,38 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "COM_MultiThreadedOperation.h"
|
||||
#include "COM_NodeOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Edge Detection (First Pass) */
|
||||
|
||||
class SMAAEdgeDetectionOperation : public MultiThreadedOperation {
|
||||
class SMAAOperation : public NodeOperation {
|
||||
protected:
|
||||
float threshold_;
|
||||
float contrast_limit_;
|
||||
float threshold_ = 0.1f;
|
||||
float local_contrast_adaptation_factor_ = 2.0f;
|
||||
int corner_rounding_ = 25;
|
||||
|
||||
public:
|
||||
SMAAEdgeDetectionOperation();
|
||||
SMAAOperation();
|
||||
|
||||
void set_threshold(float threshold);
|
||||
void set_threshold(float threshold)
|
||||
{
|
||||
threshold_ = threshold;
|
||||
}
|
||||
|
||||
void set_local_contrast_adaptation_factor(float factor);
|
||||
void set_local_contrast_adaptation_factor(float factor)
|
||||
{
|
||||
local_contrast_adaptation_factor_ = factor;
|
||||
}
|
||||
|
||||
void set_corner_rounding(int corner_rounding)
|
||||
{
|
||||
corner_rounding_ = corner_rounding;
|
||||
}
|
||||
|
||||
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
|
||||
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Blending Weight Calculation (Second Pass) */
|
||||
|
||||
class SMAABlendingWeightCalculationOperation : public MultiThreadedOperation {
|
||||
private:
|
||||
std::function<void(int x, int y, float *out)> sample_image_fn_;
|
||||
int corner_rounding_;
|
||||
|
||||
public:
|
||||
SMAABlendingWeightCalculationOperation();
|
||||
|
||||
void set_corner_rounding(float rounding);
|
||||
|
||||
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;
|
||||
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
|
||||
private:
|
||||
/* Diagonal Search Functions */
|
||||
/**
|
||||
* These functions allows to perform diagonal pattern searches.
|
||||
*/
|
||||
int search_diag1(int x, int y, int dir, bool *r_found);
|
||||
int search_diag2(int x, int y, int dir, bool *r_found);
|
||||
/**
|
||||
* This searches for diagonal patterns and returns the corresponding weights.
|
||||
*/
|
||||
void calculate_diag_weights(int x, int y, const float edges[2], float weights[2]);
|
||||
bool is_vertical_search_unneeded(int x, int y);
|
||||
|
||||
/* Horizontal/Vertical Search Functions */
|
||||
int search_xleft(int x, int y);
|
||||
int search_xright(int x, int y);
|
||||
int search_yup(int x, int y);
|
||||
int search_ydown(int x, int y);
|
||||
|
||||
/* Corner Detection Functions */
|
||||
void detect_horizontal_corner_pattern(
|
||||
float weights[2], int left, int right, int y, int d1, int d2);
|
||||
void detect_vertical_corner_pattern(
|
||||
float weights[2], int x, int top, int bottom, int d1, int d2);
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Neighborhood Blending (Third Pass) */
|
||||
|
||||
class SMAANeighborhoodBlendingOperation : public MultiThreadedOperation {
|
||||
public:
|
||||
SMAANeighborhoodBlendingOperation();
|
||||
|
||||
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
|
||||
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
void update_memory_buffer(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
Loading…
Reference in New Issue