Cleanup: Move multi-layer view logic to the operation

There are a couple of goals achieved with this change:

- The logic itself is de-duplicated between the Image and Cryptomatte
  nodes.

- The logic which accesses render results, images, etc is more local
  to the place where it needs to be used. Currently it does not matter
  too much, but it allows to properly guard the access to be thread
  safe.

Ref #118337, #121761
This commit is contained in:
Sergey Sharybin 2024-05-17 09:43:15 +02:00 committed by Sergey Sharybin
parent 9f28189c28
commit def1e8154e
5 changed files with 47 additions and 58 deletions

@ -157,22 +157,6 @@ void CryptomatteNode::input_operations_from_image_source(
ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
if (image->rr) {
int view = 0;
if (BLI_listbase_count_at_most(&image->rr->views, 2) > 1) {
if (iuser->view == 0) {
/* Heuristic to match image name with scene names, check if the view name exists in the
* image. */
view = BLI_findstringindex(
&image->rr->views, context.get_view_name(), offsetof(RenderView, name));
if (view == -1) {
view = 0;
}
}
else {
view = iuser->view - 1;
}
}
const std::string prefix = prefix_from_node(context, node);
int layer_index;
LISTBASE_FOREACH_INDEX (RenderLayer *, render_layer, &image->rr->layers, layer_index) {
@ -184,12 +168,12 @@ void CryptomatteNode::input_operations_from_image_source(
LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
const std::string combined_name = combined_layer_pass_name(render_layer, render_pass);
if (combined_name != prefix && blender::StringRef(combined_name).startswith(prefix)) {
MultilayerColorOperation *op = new MultilayerColorOperation(
render_layer, render_pass, view);
MultilayerColorOperation *op = new MultilayerColorOperation(render_layer, render_pass);
iuser->layer = layer_index;
op->set_image(image);
op->set_image_user(*iuser);
op->set_framenumber(context.get_framenumber());
op->set_view_name(context.get_view_name());
r_input_operations.append(op);
}
}

@ -19,26 +19,26 @@ ImageNode::ImageNode(bNode *editor_node) : Node(editor_node)
/* pass */
}
NodeOperation *ImageNode::do_multilayer_check(NodeConverter &converter,
const CompositorContext &context,
RenderLayer *render_layer,
RenderPass *render_pass,
Image *image,
ImageUser *user,
int framenumber,
int outputsocket_index,
int view,
DataType datatype) const
{
NodeOutput *output_socket = this->get_output_socket(outputsocket_index);
MultilayerBaseOperation *operation = nullptr;
switch (datatype) {
case DataType::Value:
operation = new MultilayerValueOperation(render_layer, render_pass, view);
operation = new MultilayerValueOperation(render_layer, render_pass);
break;
case DataType::Vector:
operation = new MultilayerVectorOperation(render_layer, render_pass, view);
operation = new MultilayerVectorOperation(render_layer, render_pass);
break;
case DataType::Color:
operation = new MultilayerColorOperation(render_layer, render_pass, view);
operation = new MultilayerColorOperation(render_layer, render_pass);
break;
default:
break;
@ -46,6 +46,7 @@ NodeOperation *ImageNode::do_multilayer_check(NodeConverter &converter,
operation->set_image(image);
operation->set_image_user(*user);
operation->set_framenumber(framenumber);
operation->set_view_name(context.get_view_name());
converter.add_operation(operation);
converter.map_output_socket(output_socket, operation->get_output_socket());
@ -80,7 +81,6 @@ void ImageNode::convert_to_operations(NodeConverter &converter,
NodeImageLayer *storage = (NodeImageLayer *)bnode_socket->storage;
RenderPass *rpass = (RenderPass *)BLI_findstring(
&rl->passes, storage->pass_name, offsetof(RenderPass, name));
int view = 0;
if (STREQ(storage->pass_name, RE_PASSNAME_COMBINED) &&
STREQ(bnode_socket->name, "Alpha"))
@ -89,60 +89,41 @@ void ImageNode::convert_to_operations(NodeConverter &converter,
continue;
}
/* returns the image view to use for the current active view */
if (BLI_listbase_count_at_most(&image->rr->views, 2) > 1) {
const int view_image = imageuser->view;
const bool is_allview = (view_image == 0); /* if view selected == All (0) */
if (is_allview) {
/* heuristic to match image name with scene names
* check if the view name exists in the image */
view = BLI_findstringindex(
&image->rr->views, context.get_view_name(), offsetof(RenderView, name));
if (view == -1) {
view = 0;
}
}
else {
view = view_image - 1;
}
}
if (rpass) {
switch (rpass->channels) {
case 1:
operation = do_multilayer_check(converter,
context,
rl,
rpass,
image,
imageuser,
framenumber,
index,
view,
DataType::Value);
break;
/* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
/* XXX any way to detect actual vector images? */
case 3:
operation = do_multilayer_check(converter,
context,
rl,
rpass,
image,
imageuser,
framenumber,
index,
view,
DataType::Vector);
break;
case 4:
operation = do_multilayer_check(converter,
context,
rl,
rpass,
image,
imageuser,
framenumber,
index,
view,
DataType::Color);
break;
default:

@ -21,13 +21,13 @@ namespace blender::compositor {
class ImageNode : public Node {
private:
NodeOperation *do_multilayer_check(NodeConverter &converter,
const CompositorContext &context,
RenderLayer *render_layer,
RenderPass *render_pass,
Image *image,
ImageUser *user,
int framenumber,
int outputsocket_index,
int view,
DataType datatype) const;
public:

@ -11,18 +11,39 @@
namespace blender::compositor {
MultilayerBaseOperation::MultilayerBaseOperation(RenderLayer *render_layer,
RenderPass *render_pass,
int view)
RenderPass *render_pass)
{
pass_id_ = BLI_findindex(&render_layer->passes, render_pass);
view_ = view;
render_layer_ = render_layer;
render_pass_ = render_pass;
}
int MultilayerBaseOperation::get_view_index() const
{
if (BLI_listbase_count_at_most(&image_->rr->views, 2) <= 1) {
return 0;
}
const int view_image = image_user_.view;
const bool is_allview = (view_image == 0); /* if view selected == All (0) */
if (is_allview) {
/* Heuristic to match image name with scene names check if the view name exists in the image.
*/
const int view = BLI_findstringindex(
&image_->rr->views, view_name_, offsetof(RenderView, name));
if (view == -1) {
return 0;
}
return view;
}
return view_image - 1;
}
ImBuf *MultilayerBaseOperation::get_im_buf()
{
image_user_.view = view_;
image_user_.view = get_view_index();
image_user_.pass = pass_id_;
if (BKE_image_multilayer_index(image_->rr, &image_user_)) {

@ -11,18 +11,21 @@ namespace blender::compositor {
class MultilayerBaseOperation : public BaseImageOperation {
private:
int pass_id_;
int view_;
protected:
RenderLayer *render_layer_;
RenderPass *render_pass_;
/* Returns the image view to use for the current active view. */
int get_view_index() const;
ImBuf *get_im_buf() override;
public:
/**
* Constructor
*/
MultilayerBaseOperation(RenderLayer *render_layer, RenderPass *render_pass, int view);
MultilayerBaseOperation(RenderLayer *render_layer, RenderPass *render_pass);
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
@ -31,8 +34,8 @@ class MultilayerBaseOperation : public BaseImageOperation {
class MultilayerColorOperation : public MultilayerBaseOperation {
public:
MultilayerColorOperation(RenderLayer *render_layer, RenderPass *render_pass, int view)
: MultilayerBaseOperation(render_layer, render_pass, view)
MultilayerColorOperation(RenderLayer *render_layer, RenderPass *render_pass)
: MultilayerBaseOperation(render_layer, render_pass)
{
this->add_output_socket(DataType::Color);
}
@ -41,8 +44,8 @@ class MultilayerColorOperation : public MultilayerBaseOperation {
class MultilayerValueOperation : public MultilayerBaseOperation {
public:
MultilayerValueOperation(RenderLayer *render_layer, RenderPass *render_pass, int view)
: MultilayerBaseOperation(render_layer, render_pass, view)
MultilayerValueOperation(RenderLayer *render_layer, RenderPass *render_pass)
: MultilayerBaseOperation(render_layer, render_pass)
{
this->add_output_socket(DataType::Value);
}
@ -50,8 +53,8 @@ class MultilayerValueOperation : public MultilayerBaseOperation {
class MultilayerVectorOperation : public MultilayerBaseOperation {
public:
MultilayerVectorOperation(RenderLayer *render_layer, RenderPass *render_pass, int view)
: MultilayerBaseOperation(render_layer, render_pass, view)
MultilayerVectorOperation(RenderLayer *render_layer, RenderPass *render_pass)
: MultilayerBaseOperation(render_layer, render_pass)
{
this->add_output_socket(DataType::Vector);
}