Compositor: Improve unsupported passes warning

This patch improves warnings displayed when the user attempts to use
passes in render engines other than EEVEE with the viewport compositor.

Previously, an error icon was always displayed if the viewport
compositor was in use as well as a viewport overlay text. This error
existed even when the render engine was set to EEVEE and even if the
passes are not actually used, which was always confusing for users.

This patch improves this by only displaying the error when a pass is
actually used and when a non-EEVEE render engine is used.

This is implemented internally as an extra info callback for the node.
And the compositor_unsupported_message member hack was removed.

Pull Request: https://projects.blender.org/blender/blender/pulls/144005
This commit is contained in:
Omar Emara
2025-08-07 12:18:06 +02:00
committed by Omar Emara
parent 4a013194dd
commit d84d779661
6 changed files with 85 additions and 54 deletions

View File

@@ -14,6 +14,7 @@
struct Scene;
struct ViewLayer;
struct bContext;
namespace blender::bke::compositor {
@@ -22,4 +23,8 @@ namespace blender::bke::compositor {
* which case, the compositor will return an invalid output and issue a warning. */
Set<std::string> get_used_passes(const Scene &scene, const ViewLayer *view_layer);
/* Checks if the viewport compositor is currently being used. This is similar to
* DRWContext::is_viewport_compositor_enabled but checks all 3D views. */
bool is_viewport_compositor_used(const bContext &context);
} // namespace blender::bke::compositor

View File

@@ -348,11 +348,6 @@ struct bNodeType {
* responsibility of the caller. */
NodeGetCompositorOperationFunction get_compositor_operation = nullptr;
/* A message to display in the node header for unsupported compositor nodes. The message
* is assumed to be static and thus require no memory handling. This field is to be removed when
* all nodes are supported. */
const char *compositor_unsupported_message = nullptr;
/* Build a multi-function for this node. */
NodeMultiFunctionBuildFunction build_multi_function = nullptr;

View File

@@ -7,19 +7,27 @@
#include <fmt/format.h>
#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_base.hh"
#include "BLI_set.hh"
#include "BLI_string_ref.hh"
#include "BKE_compositor.hh"
#include "BKE_context.hh"
#include "BKE_cryptomatte.hh"
#include "BKE_node.hh"
#include "BKE_node_legacy_types.hh"
#include "BKE_node_runtime.hh"
#include "WM_api.hh"
#include "DNA_layer_types.h"
#include "DNA_node_types.h"
#include "DNA_object_enums.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
namespace blender::bke::compositor {
@@ -171,4 +179,35 @@ Set<std::string> get_used_passes(const Scene &scene, const ViewLayer *view_layer
return used_passes;
}
bool is_viewport_compositor_used(const bContext &context)
{
const Scene *scene = CTX_data_scene(&context);
if (!scene->compositing_node_group) {
return false;
}
wmWindowManager *window_manager = CTX_wm_manager(&context);
LISTBASE_FOREACH (const wmWindow *, window, &window_manager->windows) {
const bScreen *screen = WM_window_get_active_screen(window);
LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
const SpaceLink &space = *static_cast<const SpaceLink *>(area->spacedata.first);
if (space.spacetype == SPACE_VIEW3D) {
const View3D &view_3d = reinterpret_cast<const View3D &>(space);
if (view_3d.shading.use_compositor == V3D_SHADING_USE_COMPOSITOR_DISABLED) {
continue;
}
if (!(view_3d.shading.type >= OB_MATERIAL)) {
continue;
}
return true;
}
}
}
return false;
}
} // namespace blender::bke::compositor

View File

@@ -140,10 +140,6 @@ struct TreeDrawContext {
geo_log::ContextualGeoTreeLogs tree_logs;
NestedTreePreviews *nested_group_infos = nullptr;
/**
* True if there is an active compositor using the node tree, false otherwise.
*/
bool used_by_compositor = false;
Map<bNodeInstanceKey, timeit::Nanoseconds> *compositor_per_node_execution_time = nullptr;
@@ -2051,13 +2047,6 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx,
const rctf &rect,
float &icon_offset)
{
if (ntree.type == NTREE_COMPOSIT) {
if (tree_draw_ctx.used_by_compositor && node.typeinfo->compositor_unsupported_message) {
add_error_message_button(
block, rect, ICON_ERROR, icon_offset, node.typeinfo->compositor_unsupported_message);
}
return;
}
if (ntree.type == NTREE_GEOMETRY) {
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
const bNodeTreeZones *zones = node.owner_tree().zones();
@@ -4588,39 +4577,6 @@ static void snode_setup_v2d(SpaceNode &snode, ARegion &region, const float2 &cen
snode.runtime->aspect = BLI_rctf_size_x(&v2d.cur) / float(region.winx);
}
/* Similar to DRW_is_viewport_compositor_enabled() in `draw_manager.cc` but checks all 3D views. */
static bool compositor_is_in_use(const bContext &context)
{
const Scene *scene = CTX_data_scene(&context);
if (!scene->compositing_node_group) {
return false;
}
wmWindowManager *wm = CTX_wm_manager(&context);
LISTBASE_FOREACH (const wmWindow *, win, &wm->windows) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
const SpaceLink &space = *static_cast<const SpaceLink *>(area->spacedata.first);
if (space.spacetype == SPACE_VIEW3D) {
const View3D &view_3d = reinterpret_cast<const View3D &>(space);
if (view_3d.shading.use_compositor == V3D_SHADING_USE_COMPOSITOR_DISABLED) {
continue;
}
if (!(view_3d.shading.type >= OB_MATERIAL)) {
continue;
}
return true;
}
}
}
return false;
}
static void draw_nodetree(const bContext &C,
ARegion &region,
bNodeTree &ntree,
@@ -4658,7 +4614,6 @@ static void draw_nodetree(const bContext &C,
}
else if (ntree.type == NTREE_COMPOSIT) {
const Scene *scene = CTX_data_scene(&C);
tree_draw_ctx.used_by_compositor = compositor_is_in_use(C);
tree_draw_ctx.compositor_per_node_execution_time =
&scene->runtime->compositor.per_node_execution_time;
}

View File

@@ -44,7 +44,6 @@ class GroupInputOperation : public NodeOperation {
if (!pass.is_allocated()) {
/* Pass not rendered yet, or not supported by viewport. */
result.allocate_invalid();
this->context().set_info_message("Viewport compositor setup not fully supported");
return;
}

View File

@@ -17,6 +17,7 @@
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BKE_compositor.hh"
#include "BKE_context.hh"
#include "BKE_global.hh"
#include "BKE_image.hh"
@@ -41,6 +42,8 @@
#include "GPU_shader.hh"
#include "NOD_node_extra_info.hh"
#include "COM_algorithm_extract_alpha.hh"
#include "COM_node_operation.hh"
#include "COM_utilities.hh"
@@ -672,6 +675,43 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
RNA_string_set(&op_ptr, "scene", scene_name);
}
/* Give a warning if passes are used with a render engine that does not support them. */
static void node_extra_info(NodeExtraInfoParams &parameters)
{
const Scene *scene = CTX_data_scene(&parameters.C);
/* EEVEE supports passes. */
if (StringRef(scene->r.engine) == RE_engine_id_BLENDER_EEVEE) {
return;
}
if (!bke::compositor::is_viewport_compositor_used(parameters.C)) {
return;
}
bool is_any_pass_used = false;
for (const bNodeSocket *output : parameters.node.output_sockets()) {
/* Combined pass is always available. */
if (StringRef(output->name) == "Image" || StringRef(output->name) == "Alpha") {
continue;
}
if (output->is_logically_linked()) {
is_any_pass_used = true;
break;
}
}
if (!is_any_pass_used) {
return;
}
NodeExtraInfoRow row;
row.text = RPT_("Passes Not Supported");
row.tooltip = TIP_("Render passes in the Viewport compositor are only supported in EEVEE");
row.icon = ICON_ERROR;
parameters.rows.append(std::move(row));
}
using namespace blender::compositor;
class RenderLayerOperation : public NodeOperation {
@@ -724,7 +764,6 @@ class RenderLayerOperation : public NodeOperation {
if (!pass.is_allocated()) {
/* Pass not rendered yet, or not supported by viewport. */
result.allocate_invalid();
this->context().set_info_message("Viewport compositor setup not fully supported");
return;
}
@@ -854,8 +893,6 @@ static void register_node_type_cmp_rlayers()
ntype.initfunc_api = file_ns::node_composit_init_rlayers;
ntype.poll = file_ns::node_composit_poll_rlayers;
ntype.get_compositor_operation = file_ns::get_compositor_operation;
ntype.compositor_unsupported_message = N_(
"Render passes in the Viewport compositor are only supported in EEVEE");
ntype.flag |= NODE_PREVIEW;
blender::bke::node_type_storage(ntype,
std::nullopt,
@@ -863,6 +900,7 @@ static void register_node_type_cmp_rlayers()
file_ns::node_composit_copy_rlayers);
ntype.updatefunc = file_ns::cmp_node_rlayers_update;
ntype.initfunc = node_cmp_rlayers_outputs;
ntype.get_extra_info = file_ns::node_extra_info;
blender::bke::node_type_size_preset(ntype, blender::bke::eNodeSizePreset::Large);
blender::bke::node_register_type(ntype);