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:
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user