New ("fullframe") CPU compositor backend is being used now, and all the code
related to "tiled" CPU compositor is just never used anymore. The new backend
is faster, uses less memory, better matches GPU compositor, etc.
TL;DR: 20 thousand lines of code gone.
This commit:
- Removes various bits and pieces related to "tiled" compositor (execution
groups, one-pixel-at-a-time node processing, read/write buffer operations
related to node execution groups).
- "GPU" (OpenCL) execution device, that was only used by several nodes of
the tiled compositor.
- With that, remove CLEW external library too, since nothing within Blender
uses OpenCL directly anymore.
Pull Request: https://projects.blender.org/blender/blender/pulls/118819
344 lines
13 KiB
C++
344 lines
13 KiB
C++
/* SPDX-FileCopyrightText: 2012 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "COM_KeyingNode.h"
|
|
|
|
#include "COM_KeyingBlurOperation.h"
|
|
#include "COM_KeyingClipOperation.h"
|
|
#include "COM_KeyingDespillOperation.h"
|
|
#include "COM_KeyingOperation.h"
|
|
|
|
#include "COM_MathBaseOperation.h"
|
|
|
|
#include "COM_ConvertOperation.h"
|
|
#include "COM_SetValueOperation.h"
|
|
|
|
#include "COM_DilateErodeOperation.h"
|
|
|
|
#include "COM_SetAlphaMultiplyOperation.h"
|
|
|
|
#include "COM_GaussianAlphaBlurBaseOperation.h"
|
|
|
|
#include "BLI_math_color.h"
|
|
|
|
namespace blender::compositor {
|
|
|
|
KeyingNode::KeyingNode(bNode *editor_node) : Node(editor_node)
|
|
{
|
|
/* pass */
|
|
}
|
|
|
|
NodeOperationOutput *KeyingNode::setup_pre_blur(NodeConverter &converter,
|
|
NodeInput *input_image,
|
|
int size) const
|
|
{
|
|
ConvertRGBToYCCOperation *convertRGBToYCCOperation = new ConvertRGBToYCCOperation();
|
|
convertRGBToYCCOperation->set_mode(BLI_YCC_ITU_BT709);
|
|
converter.add_operation(convertRGBToYCCOperation);
|
|
|
|
converter.map_input_socket(input_image, convertRGBToYCCOperation->get_input_socket(0));
|
|
|
|
CombineChannelsOperation *combine_operation = new CombineChannelsOperation();
|
|
converter.add_operation(combine_operation);
|
|
|
|
for (int channel = 0; channel < 4; channel++) {
|
|
SeparateChannelOperation *separate_operation = new SeparateChannelOperation();
|
|
separate_operation->set_channel(channel);
|
|
converter.add_operation(separate_operation);
|
|
|
|
converter.add_link(convertRGBToYCCOperation->get_output_socket(0),
|
|
separate_operation->get_input_socket(0));
|
|
|
|
if (ELEM(channel, 0, 3)) {
|
|
converter.add_link(separate_operation->get_output_socket(0),
|
|
combine_operation->get_input_socket(channel));
|
|
}
|
|
else {
|
|
KeyingBlurOperation *blur_xoperation = new KeyingBlurOperation();
|
|
blur_xoperation->set_size(size);
|
|
blur_xoperation->set_axis(KeyingBlurOperation::BLUR_AXIS_X);
|
|
converter.add_operation(blur_xoperation);
|
|
|
|
KeyingBlurOperation *blur_yoperation = new KeyingBlurOperation();
|
|
blur_yoperation->set_size(size);
|
|
blur_yoperation->set_axis(KeyingBlurOperation::BLUR_AXIS_Y);
|
|
converter.add_operation(blur_yoperation);
|
|
|
|
converter.add_link(separate_operation->get_output_socket(),
|
|
blur_xoperation->get_input_socket(0));
|
|
converter.add_link(blur_xoperation->get_output_socket(),
|
|
blur_yoperation->get_input_socket(0));
|
|
converter.add_link(blur_yoperation->get_output_socket(0),
|
|
combine_operation->get_input_socket(channel));
|
|
}
|
|
}
|
|
|
|
ConvertYCCToRGBOperation *convertYCCToRGBOperation = new ConvertYCCToRGBOperation();
|
|
convertYCCToRGBOperation->set_mode(BLI_YCC_ITU_BT709);
|
|
converter.add_operation(convertYCCToRGBOperation);
|
|
|
|
converter.add_link(combine_operation->get_output_socket(0),
|
|
convertYCCToRGBOperation->get_input_socket(0));
|
|
|
|
return convertYCCToRGBOperation->get_output_socket(0);
|
|
}
|
|
|
|
NodeOperationOutput *KeyingNode::setup_post_blur(NodeConverter &converter,
|
|
NodeOperationOutput *post_blur_input,
|
|
int size) const
|
|
{
|
|
KeyingBlurOperation *blur_xoperation = new KeyingBlurOperation();
|
|
blur_xoperation->set_size(size);
|
|
blur_xoperation->set_axis(KeyingBlurOperation::BLUR_AXIS_X);
|
|
converter.add_operation(blur_xoperation);
|
|
|
|
KeyingBlurOperation *blur_yoperation = new KeyingBlurOperation();
|
|
blur_yoperation->set_size(size);
|
|
blur_yoperation->set_axis(KeyingBlurOperation::BLUR_AXIS_Y);
|
|
converter.add_operation(blur_yoperation);
|
|
|
|
converter.add_link(post_blur_input, blur_xoperation->get_input_socket(0));
|
|
converter.add_link(blur_xoperation->get_output_socket(), blur_yoperation->get_input_socket(0));
|
|
|
|
return blur_yoperation->get_output_socket();
|
|
}
|
|
|
|
NodeOperationOutput *KeyingNode::setup_dilate_erode(NodeConverter &converter,
|
|
NodeOperationOutput *dilate_erode_input,
|
|
int distance) const
|
|
{
|
|
DilateDistanceOperation *dilate_erode_operation;
|
|
if (distance > 0) {
|
|
dilate_erode_operation = new DilateDistanceOperation();
|
|
dilate_erode_operation->set_distance(distance);
|
|
}
|
|
else {
|
|
dilate_erode_operation = new ErodeDistanceOperation();
|
|
dilate_erode_operation->set_distance(-distance);
|
|
}
|
|
converter.add_operation(dilate_erode_operation);
|
|
|
|
converter.add_link(dilate_erode_input, dilate_erode_operation->get_input_socket(0));
|
|
|
|
return dilate_erode_operation->get_output_socket(0);
|
|
}
|
|
|
|
NodeOperationOutput *KeyingNode::setup_feather(NodeConverter &converter,
|
|
const CompositorContext &context,
|
|
NodeOperationOutput *feather_input,
|
|
int falloff,
|
|
int distance) const
|
|
{
|
|
/* this uses a modified gaussian blur function otherwise its far too slow */
|
|
eCompositorQuality quality = context.get_quality();
|
|
|
|
/* initialize node data */
|
|
NodeBlurData data;
|
|
memset(&data, 0, sizeof(NodeBlurData));
|
|
data.filtertype = R_FILTER_GAUSS;
|
|
if (distance > 0) {
|
|
data.sizex = data.sizey = distance;
|
|
}
|
|
else {
|
|
data.sizex = data.sizey = -distance;
|
|
}
|
|
|
|
GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation();
|
|
operationx->set_data(&data);
|
|
operationx->set_quality(quality);
|
|
operationx->set_size(1.0f);
|
|
operationx->set_subtract(distance < 0);
|
|
operationx->set_falloff(falloff);
|
|
converter.add_operation(operationx);
|
|
|
|
GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation();
|
|
operationy->set_data(&data);
|
|
operationy->set_quality(quality);
|
|
operationy->set_size(1.0f);
|
|
operationy->set_subtract(distance < 0);
|
|
operationy->set_falloff(falloff);
|
|
converter.add_operation(operationy);
|
|
|
|
converter.add_link(feather_input, operationx->get_input_socket(0));
|
|
converter.add_link(operationx->get_output_socket(), operationy->get_input_socket(0));
|
|
|
|
return operationy->get_output_socket();
|
|
}
|
|
|
|
NodeOperationOutput *KeyingNode::setup_despill(NodeConverter &converter,
|
|
NodeOperationOutput *despill_input,
|
|
NodeInput *input_screen,
|
|
float factor,
|
|
float color_balance) const
|
|
{
|
|
KeyingDespillOperation *despill_operation = new KeyingDespillOperation();
|
|
despill_operation->set_despill_factor(factor);
|
|
despill_operation->set_color_balance(color_balance);
|
|
converter.add_operation(despill_operation);
|
|
|
|
converter.add_link(despill_input, despill_operation->get_input_socket(0));
|
|
converter.map_input_socket(input_screen, despill_operation->get_input_socket(1));
|
|
|
|
return despill_operation->get_output_socket(0);
|
|
}
|
|
|
|
NodeOperationOutput *KeyingNode::setup_clip(NodeConverter &converter,
|
|
NodeOperationOutput *clip_input,
|
|
int kernel_radius,
|
|
float kernel_tolerance,
|
|
float clip_black,
|
|
float clip_white,
|
|
bool edge_matte) const
|
|
{
|
|
KeyingClipOperation *clip_operation = new KeyingClipOperation();
|
|
clip_operation->set_kernel_radius(kernel_radius);
|
|
clip_operation->set_kernel_tolerance(kernel_tolerance);
|
|
clip_operation->set_clip_black(clip_black);
|
|
clip_operation->set_clip_white(clip_white);
|
|
clip_operation->set_is_edge_matte(edge_matte);
|
|
converter.add_operation(clip_operation);
|
|
|
|
converter.add_link(clip_input, clip_operation->get_input_socket(0));
|
|
|
|
return clip_operation->get_output_socket(0);
|
|
}
|
|
|
|
void KeyingNode::convert_to_operations(NodeConverter &converter,
|
|
const CompositorContext &context) const
|
|
{
|
|
const bNode *editor_node = this->get_bnode();
|
|
const NodeKeyingData *keying_data = (const NodeKeyingData *)editor_node->storage;
|
|
|
|
NodeInput *input_image = this->get_input_socket(0);
|
|
NodeInput *input_screen = this->get_input_socket(1);
|
|
NodeInput *input_garbage_matte = this->get_input_socket(2);
|
|
NodeInput *input_core_matte = this->get_input_socket(3);
|
|
NodeOutput *output_image = this->get_output_socket(0);
|
|
NodeOutput *output_matte = this->get_output_socket(1);
|
|
NodeOutput *output_edges = this->get_output_socket(2);
|
|
NodeOperationOutput *postprocessed_matte = nullptr, *postprocessed_image = nullptr,
|
|
*edges_matte = nullptr;
|
|
|
|
/* keying operation */
|
|
KeyingOperation *keying_operation = new KeyingOperation();
|
|
keying_operation->set_screen_balance(keying_data->screen_balance);
|
|
converter.add_operation(keying_operation);
|
|
|
|
converter.map_input_socket(input_screen, keying_operation->get_input_socket(1));
|
|
|
|
if (keying_data->blur_pre) {
|
|
/* Chroma pre-blur operation for input of keying operation. */
|
|
NodeOperationOutput *pre_blurred_image = setup_pre_blur(
|
|
converter, input_image, keying_data->blur_pre);
|
|
converter.add_link(pre_blurred_image, keying_operation->get_input_socket(0));
|
|
}
|
|
else {
|
|
converter.map_input_socket(input_image, keying_operation->get_input_socket(0));
|
|
}
|
|
|
|
postprocessed_matte = keying_operation->get_output_socket();
|
|
|
|
/* black / white clipping */
|
|
if (keying_data->clip_black > 0.0f || keying_data->clip_white < 1.0f) {
|
|
postprocessed_matte = setup_clip(converter,
|
|
postprocessed_matte,
|
|
keying_data->edge_kernel_radius,
|
|
keying_data->edge_kernel_tolerance,
|
|
keying_data->clip_black,
|
|
keying_data->clip_white,
|
|
false);
|
|
}
|
|
|
|
/* output edge matte */
|
|
edges_matte = setup_clip(converter,
|
|
postprocessed_matte,
|
|
keying_data->edge_kernel_radius,
|
|
keying_data->edge_kernel_tolerance,
|
|
keying_data->clip_black,
|
|
keying_data->clip_white,
|
|
true);
|
|
|
|
/* apply garbage matte */
|
|
if (input_garbage_matte->is_linked()) {
|
|
SetValueOperation *value_operation = new SetValueOperation();
|
|
value_operation->set_value(1.0f);
|
|
converter.add_operation(value_operation);
|
|
|
|
MathSubtractOperation *subtract_operation = new MathSubtractOperation();
|
|
converter.add_operation(subtract_operation);
|
|
|
|
MathMinimumOperation *min_operation = new MathMinimumOperation();
|
|
converter.add_operation(min_operation);
|
|
|
|
converter.add_link(value_operation->get_output_socket(),
|
|
subtract_operation->get_input_socket(0));
|
|
converter.map_input_socket(input_garbage_matte, subtract_operation->get_input_socket(1));
|
|
|
|
converter.add_link(subtract_operation->get_output_socket(),
|
|
min_operation->get_input_socket(0));
|
|
converter.add_link(postprocessed_matte, min_operation->get_input_socket(1));
|
|
|
|
postprocessed_matte = min_operation->get_output_socket();
|
|
}
|
|
|
|
/* apply core matte */
|
|
if (input_core_matte->is_linked()) {
|
|
MathMaximumOperation *max_operation = new MathMaximumOperation();
|
|
converter.add_operation(max_operation);
|
|
|
|
converter.map_input_socket(input_core_matte, max_operation->get_input_socket(0));
|
|
converter.add_link(postprocessed_matte, max_operation->get_input_socket(1));
|
|
|
|
postprocessed_matte = max_operation->get_output_socket();
|
|
}
|
|
|
|
/* apply blur on matte if needed */
|
|
if (keying_data->blur_post) {
|
|
postprocessed_matte = setup_post_blur(converter, postprocessed_matte, keying_data->blur_post);
|
|
}
|
|
|
|
/* matte dilate/erode */
|
|
if (keying_data->dilate_distance != 0) {
|
|
postprocessed_matte = setup_dilate_erode(
|
|
converter, postprocessed_matte, keying_data->dilate_distance);
|
|
}
|
|
|
|
/* matte feather */
|
|
if (keying_data->feather_distance != 0) {
|
|
postprocessed_matte = setup_feather(converter,
|
|
context,
|
|
postprocessed_matte,
|
|
keying_data->feather_falloff,
|
|
keying_data->feather_distance);
|
|
}
|
|
|
|
/* set alpha channel to output image */
|
|
SetAlphaMultiplyOperation *alpha_operation = new SetAlphaMultiplyOperation();
|
|
converter.add_operation(alpha_operation);
|
|
|
|
converter.map_input_socket(input_image, alpha_operation->get_input_socket(0));
|
|
converter.add_link(postprocessed_matte, alpha_operation->get_input_socket(1));
|
|
|
|
postprocessed_image = alpha_operation->get_output_socket();
|
|
|
|
/* despill output image */
|
|
if (keying_data->despill_factor > 0.0f) {
|
|
postprocessed_image = setup_despill(converter,
|
|
postprocessed_image,
|
|
input_screen,
|
|
keying_data->despill_factor,
|
|
keying_data->despill_balance);
|
|
}
|
|
|
|
/* connect result to output sockets */
|
|
converter.map_output_socket(output_image, postprocessed_image);
|
|
converter.map_output_socket(output_matte, postprocessed_matte);
|
|
|
|
if (edges_matte) {
|
|
converter.map_output_socket(output_edges, edges_matte);
|
|
}
|
|
}
|
|
|
|
} // namespace blender::compositor
|