Blender V4.5
gpu_shader_private.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
8
9#pragma once
10
11#include "BLI_map.hh"
12#include "BLI_span.hh"
13#include "BLI_string_ref.hh"
14
15#include "GPU_shader.hh"
16#include "GPU_worker.hh"
19
20#include <deque>
21#include <string>
22
23namespace blender::gpu {
24
25class GPULogParser;
26class Context;
27
28/* Set to 1 to log the full source of shaders that fail to compile. */
29#define DEBUG_LOG_SHADER_SRC_ON_ERROR 0
30
36#define SOURCES_INDEX_VERSION 0
37#define SOURCES_INDEX_SPECIALIZATION_CONSTANTS 1
38
43class Shader {
44 public:
49
50 /* Default specialization constants state as defined inside ShaderCreateInfo.
51 * Should be considered as const after init(). */
52 std::unique_ptr<const shader::SpecializationConstants> constants;
53
54 /* WORKAROUND: True if this shader is a polyline shader and needs an appropriate setup to render.
55 * Eventually, in the future, we should modify the user code instead of relying on such hacks. */
56 bool is_polyline = false;
57
58 protected:
60 char name[64];
61
62 /* Parent shader can be used for shaders which are derived from the same source material.
63 * The child shader can pull information from its parent to prepare additional resources
64 * such as PSOs upfront. This enables asynchronous PSO compilation which mitigates stuttering
65 * when updating new materials. */
67
68 public:
69 Shader(const char *name);
70 virtual ~Shader();
71
72 /* TODO: Remove `is_batch_compilation`. */
73 virtual void init(const shader::ShaderCreateInfo &info, bool is_batch_compilation) = 0;
74 /* Variant for legacy python shaders. To be removed, not supported in Vulkan or Metal. */
75 virtual void init() = 0;
76
81 virtual bool finalize(const shader::ShaderCreateInfo *info = nullptr) = 0;
82 /* Pre-warms PSOs using parent shader's cached PSO descriptors. Limit specifies maximum PSOs to
83 * warm. If -1, compiles all PSO permutations in parent shader.
84 *
85 * See `GPU_shader_warm_cache(..)` in `GPU_shader.hh` for more information. */
86 virtual void warm_cache(int limit) = 0;
87
88 virtual void bind(const shader::SpecializationConstants *constants_state) = 0;
89 virtual void unbind() = 0;
90
91 virtual void uniform_float(int location, int comp_len, int array_size, const float *data) = 0;
92 virtual void uniform_int(int location, int comp_len, int array_size, const int *data) = 0;
93
94 /* Add specialization constant declarations to shader instance. */
96
97 std::string defines_declare(const shader::ShaderCreateInfo &info) const;
98 virtual std::string resources_declare(const shader::ShaderCreateInfo &info) const = 0;
99 virtual std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
100 virtual std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
101 virtual std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
102 virtual std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const = 0;
103 virtual std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const = 0;
104
106 {
107 return name;
108 }
109
110 void parent_set(Shader *parent)
111 {
112 parent_shader_ = parent;
113 }
114
116 {
117 return parent_shader_;
118 }
119
120 static void set_srgb_uniform(Context *ctx, GPUShader *shader);
121 static void set_framebuffer_srgb_target(int use_srgb_to_linear);
122
123 protected:
124 void print_log(Span<StringRefNull> sources,
125 const char *log,
126 const char *stage,
127 bool error,
128 GPULogParser *parser);
129};
130
131/* Syntactic sugar. */
132static inline GPUShader *wrap(Shader *vert)
133{
134 return reinterpret_cast<GPUShader *>(vert);
135}
136static inline Shader *unwrap(GPUShader *vert)
137{
138 return reinterpret_cast<Shader *>(vert);
139}
140static inline const Shader *unwrap(const GPUShader *vert)
141{
142 return reinterpret_cast<const Shader *>(vert);
143}
144
146 struct Sources {
147 std::string vert;
148 std::string geom;
149 std::string frag;
150 std::string comp;
151 };
152
153 struct Batch {
154 Vector<Shader *> shaders;
156
157 Vector<ShaderSpecialization> specializations;
158
159 std::atomic<int> pending_compilations = 0;
160 std::atomic<bool> is_cancelled = false;
161
162 bool is_specialization_batch()
163 {
164 return !specializations.is_empty();
165 }
166
167 bool is_ready()
168 {
169 BLI_assert(pending_compilations >= 0);
170 return pending_compilations == 0;
171 }
172
173 void free_shaders()
174 {
175 for (Shader *shader : shaders) {
176 if (shader) {
178 }
179 }
180 shaders.clear();
181 }
182 };
184 std::mutex mutex_;
185 std::condition_variable compilation_finished_notification_;
186
187 struct ParallelWork {
188 Batch *batch = nullptr;
189 int shader_index = 0;
190 };
191
192 struct CompilationQueue {
193 std::deque<ParallelWork> low_priority;
194 std::deque<ParallelWork> normal_priority;
195 std::deque<ParallelWork> high_priority;
196
197 void push(ParallelWork &&work, CompilationPriority priority)
198 {
199 switch (priority) {
201 low_priority.push_back(work);
202 break;
204 normal_priority.push_back(work);
205 break;
207 high_priority.push_back(work);
208 break;
209 default:
211 break;
212 }
213 }
214
215 ParallelWork pop()
216 {
217 if (!high_priority.empty()) {
218 ParallelWork work = high_priority.front();
219 high_priority.pop_front();
220 return work;
221 }
222 if (!normal_priority.empty()) {
223 ParallelWork work = normal_priority.front();
224 normal_priority.pop_front();
225 return work;
226 }
227 if (!low_priority.empty()) {
228 ParallelWork work = low_priority.front();
229 low_priority.pop_front();
230 return work;
231 }
233 return {};
234 }
235
236 bool is_empty()
237 {
238 return low_priority.empty() && normal_priority.empty() && high_priority.empty();
239 }
240
241 void remove_batch(Batch *batch)
242 {
243 auto remove = [](std::deque<ParallelWork> &queue, Batch *batch) {
244 for (ParallelWork &work : queue) {
245 if (work.batch == batch) {
246 work = {};
247 batch->pending_compilations--;
248 }
249 }
250
251 queue.erase(std::remove_if(queue.begin(),
252 queue.end(),
253 [](const ParallelWork &work) { return !work.batch; }),
254 queue.end());
255 };
256
257 remove(low_priority, batch);
258 remove(normal_priority, batch);
259 remove(high_priority, batch);
260 }
261 };
262 CompilationQueue compilation_queue_;
263
264 std::unique_ptr<GPUWorker> compilation_worker_;
265
266 bool support_specializations_;
267
268 void *pop_work();
269 void do_work(void *work_payload);
270
271 BatchHandle next_batch_handle_ = 1;
272
273 bool is_compiling_impl();
274
275 protected:
276 /* Must be called earlier from the destructor of the subclass if the compilation process relies
277 * on subclass resources. */
279 {
280 compilation_worker_.reset();
281 }
282
283 public:
284 ShaderCompiler(uint32_t threads_count = 1,
286 bool support_specializations = false);
287 virtual ~ShaderCompiler();
288
289 Shader *compile(const shader::ShaderCreateInfo &info, bool is_batch_compilation);
290
291 virtual Shader *compile_shader(const shader::ShaderCreateInfo &info);
292 virtual void specialize_shader(ShaderSpecialization & /*specialization*/){};
293
295 CompilationPriority priority);
296 void batch_cancel(BatchHandle &handle);
297 bool batch_is_ready(BatchHandle handle);
299
301 CompilationPriority priority);
302
304
305 bool is_compiling();
306 void wait_for_all();
307};
308
315
316struct LogCursor {
317 int source = -1;
318 int row = -1;
319 int column = -1;
321};
322
327
329 public:
330 virtual const char *parse_line(const char *source_combined,
331 const char *log_line,
332 GPULogItem &log_item) = 0;
333
334 protected:
335 const char *skip_severity(const char *log_line,
336 GPULogItem &log_item,
337 const char *error_msg,
338 const char *warning_msg,
339 const char *note_msg) const;
340 const char *skip_separators(const char *log_line, const StringRef separators) const;
341 const char *skip_until(const char *log_line, char stop_char) const;
342 bool at_number(const char *log_line) const;
343 bool at_any(const char *log_line, const StringRef chars) const;
344 int parse_number(const char *log_line, const char **r_new_position) const;
345
347};
348
349void printf_begin(Context *ctx);
350void printf_end(Context *ctx);
351
352} // namespace blender::gpu
353
354/* XXX do not use it. Special hack to use OCIO with batch API. */
355GPUShader *immGetShader();
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
int64_t BatchHandle
Definition GPU_shader.hh:83
CompilationPriority
Definition GPU_shader.hh:81
int64_t SpecializationBatchHandle
void GPU_shader_free(GPUShader *shader)
BMesh const char void * data
bool is_empty() const
int parse_number(const char *log_line, const char **r_new_position) const
const char * skip_separators(const char *log_line, const StringRef separators) const
bool at_number(const char *log_line) const
bool at_any(const char *log_line, const StringRef chars) const
virtual const char * parse_line(const char *source_combined, const char *log_line, GPULogItem &log_item)=0
const char * skip_until(const char *log_line, char stop_char) const
MEM_CXX_CLASS_ALLOC_FUNCS("GPULogParser")
const char * skip_severity(const char *log_line, GPULogItem &log_item, const char *error_msg, const char *warning_msg, const char *note_msg) const
void batch_cancel(BatchHandle &handle)
BatchHandle batch_compile(Span< const shader::ShaderCreateInfo * > &infos, CompilationPriority priority)
bool specialization_batch_is_ready(SpecializationBatchHandle &handle)
Vector< Shader * > batch_finalize(BatchHandle &handle)
Shader * compile(const shader::ShaderCreateInfo &info, bool is_batch_compilation)
virtual void specialize_shader(ShaderSpecialization &)
bool batch_is_ready(BatchHandle handle)
ShaderCompiler(uint32_t threads_count=1, GPUWorker::ContextType context_type=GPUWorker::ContextType::PerThread, bool support_specializations=false)
SpecializationBatchHandle precompile_specializations(Span< ShaderSpecialization > specializations, CompilationPriority priority)
virtual Shader * compile_shader(const shader::ShaderCreateInfo &info)
virtual void unbind()=0
virtual std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const =0
virtual void uniform_int(int location, int comp_len, int array_size, const int *data)=0
static void set_srgb_uniform(Context *ctx, GPUShader *shader)
std::string defines_declare(const shader::ShaderCreateInfo &info) const
Definition gpu_shader.cc:34
virtual void compute_shader_from_glsl(MutableSpan< StringRefNull > sources)=0
virtual void init(const shader::ShaderCreateInfo &info, bool is_batch_compilation)=0
virtual void bind(const shader::SpecializationConstants *constants_state)=0
std::unique_ptr< const shader::SpecializationConstants > constants
virtual void vertex_shader_from_glsl(MutableSpan< StringRefNull > sources)=0
virtual std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const =0
Shader * parent_get() const
virtual void fragment_shader_from_glsl(MutableSpan< StringRefNull > sources)=0
virtual bool finalize(const shader::ShaderCreateInfo *info=nullptr)=0
StringRefNull name_get() const
virtual std::string resources_declare(const shader::ShaderCreateInfo &info) const =0
virtual std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const =0
void specialization_constants_init(const shader::ShaderCreateInfo &info)
virtual void geometry_shader_from_glsl(MutableSpan< StringRefNull > sources)=0
virtual void warm_cache(int limit)=0
void parent_set(Shader *parent)
virtual std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const =0
virtual void init()=0
virtual void uniform_float(int location, int comp_len, int array_size, const float *data)=0
void print_log(Span< StringRefNull > sources, const char *log, const char *stage, bool error, GPULogParser *parser)
static void set_framebuffer_srgb_target(int use_srgb_to_linear)
virtual std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const =0
Shader(const char *name)
Definition gpu_shader.cc:56
struct @242053044010324116347033273112253060004051364061::@051143074301336237271216303350234260141112266062 batch
#define log
GPUShader * immGetShader()
static void error(const char *str)
static Context * unwrap(GPUContext *ctx)
static GPUContext * wrap(Context *ctx)
void printf_begin(Context *ctx)
void printf_end(Context *ctx)
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...