From a2ca050087b236d59cd194e74d3cbd6a0f660ca7 Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Mon, 26 Feb 2024 16:24:38 +0200 Subject: [PATCH] Fix #118711: Crash in compositor with many nodes The Viewport Compositors crashes when there are many nodes that are not connected to the compositor or viewer outputs. That's because those sockets were wrongly added to the shader operation, even though they will not be used, which surpasses the limit for the maximum image units per shader. --- .../realtime_compositor/COM_shader_operation.hh | 8 +++++--- .../realtime_compositor/intern/evaluator.cc | 3 ++- .../realtime_compositor/intern/shader_operation.cc | 13 ++++++++----- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/source/blender/compositor/realtime_compositor/COM_shader_operation.hh b/source/blender/compositor/realtime_compositor/COM_shader_operation.hh index 3ed6d8fd3b6..0b0187c249c 100644 --- a/source/blender/compositor/realtime_compositor/COM_shader_operation.hh +++ b/source/blender/compositor/realtime_compositor/COM_shader_operation.hh @@ -94,6 +94,8 @@ using ShaderCompileUnit = VectorSet; * resources. */ class ShaderOperation : public Operation { private: + /* A reference to the node execution schedule that is being compiled. */ + const Schedule &schedule_; /* The compile unit that will be compiled into this shader operation. */ ShaderCompileUnit compile_unit_; /* The GPU material backing the operation. This is created and compiled during construction and @@ -117,9 +119,9 @@ class ShaderOperation : public Operation { VectorSet preview_outputs_; public: - /* Construct and compile a GPU material from the given shader compile unit by calling - * GPU_material_from_callbacks with the appropriate callbacks. */ - ShaderOperation(Context &context, ShaderCompileUnit &compile_unit); + /* Construct and compile a GPU material from the given shader compile unit and execution schedule + * by calling GPU_material_from_callbacks with the appropriate callbacks. */ + ShaderOperation(Context &context, ShaderCompileUnit &compile_unit, const Schedule &schedule); /* Free the GPU material. */ ~ShaderOperation(); diff --git a/source/blender/compositor/realtime_compositor/intern/evaluator.cc b/source/blender/compositor/realtime_compositor/intern/evaluator.cc index 640ee7de8a6..2f2801de873 100644 --- a/source/blender/compositor/realtime_compositor/intern/evaluator.cc +++ b/source/blender/compositor/realtime_compositor/intern/evaluator.cc @@ -142,7 +142,8 @@ void Evaluator::map_node_operation_inputs_to_their_results(DNode node, void Evaluator::compile_and_evaluate_shader_compile_unit(CompileState &compile_state) { ShaderCompileUnit &compile_unit = compile_state.get_shader_compile_unit(); - ShaderOperation *operation = new ShaderOperation(context_, compile_unit); + const Schedule &schedule = compile_state.get_schedule(); + ShaderOperation *operation = new ShaderOperation(context_, compile_unit, schedule); for (DNode node : compile_unit) { compile_state.map_node_to_shader_operation(node, operation); diff --git a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc index 32fd75dd396..9e90413de12 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc @@ -38,8 +38,10 @@ namespace blender::realtime_compositor { using namespace nodes::derived_node_tree_types; -ShaderOperation::ShaderOperation(Context &context, ShaderCompileUnit &compile_unit) - : Operation(context), compile_unit_(compile_unit) +ShaderOperation::ShaderOperation(Context &context, + ShaderCompileUnit &compile_unit, + const Schedule &schedule) + : Operation(context), schedule_(schedule), compile_unit_(compile_unit) { material_ = GPU_material_from_callbacks( GPU_MAT_COMPOSITOR, &construct_material, &generate_code, this); @@ -290,10 +292,11 @@ void ShaderOperation::populate_results_for_node(DNode node, GPUMaterial *materia for (const bNodeSocket *output : node->output_sockets()) { const DOutputSocket doutput{node.context(), output}; - /* If any of the nodes linked to the output are not part of the shader operation, then an - * output result needs to be populated for it. */ + /* If any of the nodes linked to the output are not part of the shader operation but are part + * of the execution schedule, then an output result needs to be populated for it. */ const bool is_operation_output = is_output_linked_to_node_conditioned( - doutput, [&](DNode node) { return !compile_unit_.contains(node); }); + doutput, + [&](DNode node) { return schedule_.contains(node) && !compile_unit_.contains(node); }); /* If the output is used as the node preview, then an output result needs to be populated for * it, and we additionally keep track of that output to later compute the previews from. */