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