Blender V5.0
COM_shader_operation.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
7#include <memory>
8
9#include "BLI_map.hh"
10
11#include "GPU_material.hh"
12#include "GPU_shader.hh"
13
15
17
18#include "COM_context.hh"
21#include "COM_scheduler.hh"
22#include "COM_shader_node.hh"
23
24namespace blender::compositor {
25
26using namespace nodes::derived_node_tree_types;
27
28/* ------------------------------------------------------------------------------------------------
29 * Shader Operation
30 *
31 * A pixel operation that evaluates a shader compiled from the pixel compile unit using the GPU
32 * material compiler, see GPU_material.hh for more information. Also see the PixelOperation class
33 * for more information on pixel operations.
34 *
35 * An input to the pixel operation is declared for a distinct output socket as follows:
36 *
37 * - A texture is added to the shader, which will be bound to the result of the output socket
38 * during evaluation.
39 * - A GPU attribute is added to the GPU material for that output socket and is linked to the GPU
40 * input stack of the inputs linked to the output socket.
41 * - Code is emitted to initialize the values of the attributes by sampling the textures
42 * corresponding to each of the inputs.
43 * - The newly added attribute is mapped to the output socket in output_to_material_attribute_map_
44 * to share that same attributes for all inputs linked to the same output socket.
45 *
46 * An output to the pixel operation is declared for an output socket as follows:
47 *
48 * - An image is added in the shader where the output value will be written.
49 * - A storer GPU material node that stores the value of the output is added and linked to the GPU
50 * output stack of the output. The storer will store the value in the image identified by the
51 * index of the output given to the storer.
52 * - The storer functions are generated dynamically to map each index with its appropriate image.
53 *
54 * The GPU material code generator source is used to construct a compute shader that is then
55 * dispatched during operation evaluation after binding the inputs, outputs, and any necessary
56 * resources. */
58 private:
59 /* The GPU material backing the operation. This is created and compiled during construction and
60 * freed during destruction. */
61 GPUMaterial *material_;
62 /* A map that associates each node in the compile unit with an instance of its shader node. */
64 /* A map that associates the output socket of a node that is not part of the shader operation to
65 * the attribute that was created for it. This is used to share the same attribute with all
66 * inputs that are linked to the same output socket. */
67 Map<DOutputSocket, GPUNodeLink *> output_to_material_attribute_map_;
68 /* A map that associates implicit inputs to the attributes that were created for them. */
69 Map<ImplicitInput, GPUNodeLink *> implicit_input_to_material_attribute_map_;
70
71 public:
72 /* Construct and compile a GPU material from the given shader compile unit and execution schedule
73 * by calling GPU_material_from_callbacks with the appropriate callbacks. */
74 ShaderOperation(Context &context, PixelCompileUnit &compile_unit, const Schedule &schedule);
75
76 /* Free the GPU material. */
77 ~ShaderOperation() override;
78
79 /* Allocate the output results, bind the shader and all its needed resources, then dispatch the
80 * shader. */
81 void execute() override;
82
83 private:
84 /* Bind the uniform buffer of the GPU material as well as any color band textures needed by the
85 * GPU material. The compiled shader of the material is given as an argument and assumed to be
86 * bound. */
87 void bind_material_resources(gpu::Shader *shader);
88
89 /* Bind the input results of the operation to the appropriate textures in the GPU material. The
90 * attributes stored in output_to_material_attribute_map_ have names that match the texture
91 * samplers in the shader as well as the identifiers of the operation inputs that they correspond
92 * to. The compiled shader of the material is given as an argument and assumed to be bound. */
93 void bind_inputs(gpu::Shader *shader);
94
95 /* Bind the output results of the operation to the appropriate images in the GPU material. The
96 * name of the images in the shader match the identifier of their corresponding outputs. The
97 * compiled shader of the material is given as an argument and assumed to be bound. */
98 void bind_outputs(gpu::Shader *shader);
99
100 /* A static callback method of interface ConstructGPUMaterialFn that is passed to
101 * GPU_material_from_callbacks to construct the GPU material graph. The thunk parameter will be a
102 * pointer to the instance of ShaderOperation that is being compiled. The method goes over the
103 * compile unit and does the following for each node:
104 *
105 * - Instantiate a ShaderNode from the node and add it to shader_nodes_.
106 * - Link the inputs of the node if needed. The inputs are either linked to other nodes in the
107 * GPU material graph or are exposed as inputs to the shader operation itself if they are
108 * linked to nodes that are not part of the shader operation.
109 * - Call the compile method of the shader node to actually add and link the GPU material graph
110 * nodes.
111 * - If any of the outputs of the node are linked to nodes that are not part of the shader
112 * operation, they are exposed as outputs to the shader operation itself. */
113 static void construct_material(void *thunk, GPUMaterial *material);
114
115 /* Link the inputs of the node if needed. Unlinked inputs will be linked to constant values. If
116 * the input is linked to a node that is not part of the shader operation, the input will be
117 * exposed as an input to the shader operation and linked to it. While if the input is linked to
118 * a node that is part of the shader operation, then it is linked to that node in the GPU
119 * material node graph. */
120 void link_node_inputs(DNode node);
121
122 /* Link the GPU stack of the given unavailable input to a constant zero value setter GPU node.
123 * The value is ignored since the socket is unavailable, but the GPU Material compiler expects
124 * all inputs to be linked, even unavailable ones. */
125 void link_node_input_unavailable(const DInputSocket input);
126
127 /* Link the GPU stack of the given unlinked input to a constant value setter GPU node that
128 * supplies the value of the unlinked input. The value is taken from the given origin input,
129 * which will be equal to the input in most cases, but can also be an unlinked input of a group
130 * node. */
131 void link_node_input_constant(const DInputSocket input, const DInputSocket origin);
132
133 /* Given an unlinked input with an implicit input. Declare a new input to the operation for that
134 * implicit input if not done already and link it to the input link of the GPU node stack of the
135 * input socket. The implicit input and type are taken from the given origin input, which will
136 * be equal to the input in most cases, but can also be an unlinked input of a group node */
137 void link_node_input_implicit(const DInputSocket input, const DInputSocket origin);
138
139 /* Given the input socket of a node that is part of the shader operation which is linked to the
140 * given output socket of a node that is also part of the shader operation, just link the output
141 * link of the GPU node stack of the output socket to the input link of the GPU node stack of the
142 * input socket. This essentially establishes the needed links in the GPU material node graph. */
143 void link_node_input_internal(DInputSocket input_socket, DOutputSocket output_socket);
144
145 /* Given the input socket of a node that is part of the shader operation which is linked to the
146 * given output socket of a node that is not part of the shader operation, declare a new
147 * operation input and link it to the input link of the GPU node stack of the input socket. An
148 * operation input is only declared if no input was already declared for that same output socket
149 * before. */
150 void link_node_input_external(DInputSocket input_socket, DOutputSocket output_socket);
151
152 /* Given the input socket of a node that is part of the shader operation which is linked to the
153 * given output socket of a node that is not part of the shader operation, declare a new input to
154 * the operation that is represented in the GPU material by a newly created GPU attribute. It is
155 * assumed that no operation input was declared for this same output socket before. In the
156 * generate_code_for_inputs method, a texture will be added in the shader for each of the
157 * declared inputs, having the same name as the attribute. Additionally, code will be emitted to
158 * initialize the attributes by sampling their corresponding textures. */
159 void declare_operation_input(DInputSocket input_socket, DOutputSocket output_socket);
160
161 /* Populate the output results of the shader operation for output sockets of the given node that
162 * are linked to nodes outside of the shader operation or are used to compute a preview for the
163 * node. */
164 void populate_results_for_node(DNode node);
165
166 /* Given the output socket of a node that is part of the shader operation which is linked to an
167 * input socket of a node that is not part of the shader operation, declare a new output to the
168 * operation and link it to an output storer passing in the index of the output. In the
169 * generate_code_for_outputs method, an image will be added in the shader for each of the
170 * declared outputs. Additionally, code will be emitted to define the storer functions that store
171 * the value in the appropriate image identified by the given index. */
172 void populate_operation_result(DOutputSocket output_socket);
173
174 /* A static callback method of interface GPUCodegenCallbackFn that is passed to
175 * GPU_material_from_callbacks to create the shader create info of the GPU material. The thunk
176 * parameter will be a pointer to the instance of ShaderOperation that is being compiled.
177 *
178 * This method first generates the necessary code to load the inputs and store the outputs. Then,
179 * it creates a compute shader from the generated sources. Finally, it adds the necessary GPU
180 * resources to the shader. */
181 static void generate_code(void *thunk, GPUMaterial *material, GPUCodegenOutput *code_generator);
182
183 /* Add an image in the shader for each of the declared outputs. Additionally, emit code to define
184 * the storer functions that store the given value in the appropriate image identified by the
185 * given index. */
186 std::string generate_code_for_outputs(gpu::shader::ShaderCreateInfo &shader_create_info);
187
188 /* Add a texture will in the shader for each of the declared inputs/attributes in the operation,
189 * having the same name as the attribute. Additionally, emit code to initialize the attributes by
190 * sampling their corresponding textures. */
191 std::string generate_code_for_inputs(GPUMaterial *material,
192 gpu::shader::ShaderCreateInfo &shader_create_info);
193};
194
195} // namespace blender::compositor
PixelOperation(Context &context, PixelCompileUnit &compile_unit, const Schedule &schedule)
ShaderOperation(Context &context, PixelCompileUnit &compile_unit, const Schedule &schedule)
#define input
VectorSet< DNode > Schedule
VectorSet< DNode > PixelCompileUnit
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...