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.
This commit is contained in:
Omar Emara
2024-02-26 16:24:38 +02:00
parent 95f48fe7b8
commit a2ca050087
3 changed files with 15 additions and 9 deletions

View File

@@ -94,6 +94,8 @@ using ShaderCompileUnit = VectorSet<DNode>;
* 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<DOutputSocket> 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();

View File

@@ -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);

View File

@@ -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. */