Blender V4.5
GPU_shader.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#pragma once
12
13#include <mutex>
14#include <optional>
15
16#include "BLI_span.hh"
17#include "BLI_string_ref.hh"
18#include "BLI_vector.hh"
19
20#include "GPU_common_types.hh"
21#include "GPU_shader_builtin.hh"
22
23namespace blender::gpu {
24class VertBuf;
25}
26
28struct GPUShaderCreateInfo;
30struct GPUShader;
31
32/* Hardware limit is 16. Position attribute is always needed so we reduce to 15.
33 * This makes sure the GPUVertexFormat name buffer does not overflow. */
34constexpr static int GPU_MAX_ATTR = 15;
35
36/* Determined by the maximum uniform buffer size divided by chunk size. */
37constexpr static int GPU_MAX_UNIFORM_ATTR = 8;
38
39/* -------------------------------------------------------------------- */
42
48
53GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info);
54
58GPUShader *GPU_shader_create_from_info_python(const GPUShaderCreateInfo *_info);
59
66GPUShader *GPU_shader_create_from_info_name(const char *info_name);
67
73const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name);
74
79bool GPU_shader_create_info_check_error(const GPUShaderCreateInfo *_info, char r_error[128]);
80
82
116
118
119/* -------------------------------------------------------------------- */
122
123void GPU_shader_free(GPUShader *shader);
124
126
127/* -------------------------------------------------------------------- */
130
138void GPU_shader_bind(
139 GPUShader *shader,
140 const blender::gpu::shader::SpecializationConstants *constants_state = nullptr);
141
147void GPU_shader_unbind();
148
153GPUShader *GPU_shader_get_bound();
154
156
157/* -------------------------------------------------------------------- */
160
161const char *GPU_shader_get_name(GPUShader *shader);
162
164
165/* -------------------------------------------------------------------- */
168
173int GPU_shader_get_ubo_binding(GPUShader *shader, const char *name);
174int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name);
175int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name);
176
181int GPU_shader_get_uniform(GPUShader *shader, const char *name);
182
186int GPU_shader_get_constant(GPUShader *shader, const char *name);
187
193 GPUShader *shader, int location, int length, int array_size, const float *value);
195 GPUShader *shader, int location, int length, int array_size, const int *value);
196
203void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value);
204void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value);
205void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value);
206void GPU_shader_uniform_2f(GPUShader *sh, const char *name, float x, float y);
207void GPU_shader_uniform_3f(GPUShader *sh, const char *name, float x, float y, float z);
208void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, float z, float w);
209void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2]);
210void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3]);
211void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]);
212void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2]);
213void GPU_shader_uniform_3iv(GPUShader *sh, const char *name, const int data[3]);
214void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]);
215void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3]);
216void GPU_shader_uniform_1f_array(GPUShader *sh, const char *name, int len, const float *val);
217void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]);
218void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]);
219
221
222/* -------------------------------------------------------------------- */
227
228uint GPU_shader_get_attribute_len(const GPUShader *shader);
229uint GPU_shader_get_ssbo_input_len(const GPUShader *shader);
230int GPU_shader_get_attribute(const GPUShader *shader, const char *name);
231bool GPU_shader_get_attribute_info(const GPUShader *shader,
232 int attr_location,
233 char r_name[256],
234 int *r_type);
235bool GPU_shader_get_ssbo_input_info(const GPUShader *shader, int ssbo_location, char r_name[256]);
236
238
239/* -------------------------------------------------------------------- */
246
247/* Return the default constants.
248 * All constants available for this shader should fit the returned structure. */
250 GPUShader *sh);
251
253
258
273
280
286
288
289/* -------------------------------------------------------------------- */
294
295GPUShader *GPU_shader_create(std::optional<blender::StringRefNull> vertcode,
296 std::optional<blender::StringRefNull> fragcode,
297 std::optional<blender::StringRefNull> geomcode,
298 std::optional<blender::StringRefNull> libcode,
299 std::optional<blender::StringRefNull> defines,
301GPUShader *GPU_shader_create_compute(std::optional<blender::StringRefNull> computecode,
302 std::optional<blender::StringRefNull> libcode,
303 std::optional<blender::StringRefNull> defines,
305GPUShader *GPU_shader_create_from_python(std::optional<blender::StringRefNull> vertcode,
306 std::optional<blender::StringRefNull> fragcode,
307 std::optional<blender::StringRefNull> geomcode,
308 std::optional<blender::StringRefNull> libcode,
309 std::optional<blender::StringRefNull> defines,
310 std::optional<blender::StringRefNull> name);
311GPUShader *GPU_shader_create_ex(std::optional<blender::StringRefNull> vertcode,
312 std::optional<blender::StringRefNull> fragcode,
313 std::optional<blender::StringRefNull> geomcode,
314 std::optional<blender::StringRefNull> computecode,
315 std::optional<blender::StringRefNull> libcode,
316 std::optional<blender::StringRefNull> defines,
318
354void GPU_shader_warm_cache(GPUShader *shader, int limit);
355
356/* We expect the parent shader to be compiled and already have some cached PSOs when being assigned
357 * as a reference. Ensure the parent shader still exists when `GPU_shader_cache_warm(..)` is
358 * called. */
359void GPU_shader_set_parent(GPUShader *shader, GPUShader *parent);
360
365 GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */
366 GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */
367 GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */
368 GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */
369 GPU_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */
370 GPU_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */
371
372 GPU_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */
373 GPU_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */
374 GPU_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */
375 GPU_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */
376 GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
377
378 GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
379 GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
380
381 GPU_UNIFORM_COLOR, /* vec4 color */
382 GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
383 GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
384 GPU_UNIFORM_RESOURCE_ID, /* int resourceId */
385 GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */
386};
387#define GPU_NUM_UNIFORMS (GPU_UNIFORM_SRGB_TRANSFORM + 1)
388
393int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
394
401
403
417
419int GPU_shader_get_builtin_block(GPUShader *shader, int builtin);
420
422int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
423
425
426#define GPU_SHADER_FREE_SAFE(shader) \
427 do { \
428 if (shader != nullptr) { \
429 GPU_shader_free(shader); \
430 shader = nullptr; \
431 } \
432 } while (0)
433
434#include "BLI_utility_mixins.hh"
435#include <atomic>
436#include <mutex>
437
438namespace blender::gpu {
439
440/* GPUShader wrapper that makes compilation threadsafe.
441 * The compilation is deferred until the first get() call.
442 * Concurrently using the shader from multiple threads is still unsafe. */
444 private:
445 std::string info_name_;
446 std::atomic<GPUShader *> shader_ = nullptr;
447 /* TODO: Failed compilation detection should be supported by the GPUShader API. */
448 std::atomic<bool> failed_ = false;
449 std::mutex mutex_;
450 /* Handle for async compilation. */
451 BatchHandle compilation_handle_ = 0;
452
453 void move(StaticShader &&other)
454 {
455 std::scoped_lock lock1(mutex_);
456 std::scoped_lock lock2(other.mutex_);
457 BLI_assert(shader_ == nullptr && info_name_.empty());
458 std::swap(info_name_, other.info_name_);
459 /* No std::swap support for atomics. */
460 shader_.exchange(other.shader_.exchange(shader_));
461 failed_.exchange(other.failed_.exchange(failed_));
462 std::swap(compilation_handle_, other.compilation_handle_);
463 }
464
465 public:
466 StaticShader(std::string info_name) : info_name_(info_name) {}
467
468 StaticShader() = default;
470 {
471 move(std::move(other));
472 }
474 {
475 move(std::move(other));
476 return *this;
477 };
478
480 {
481 if (compilation_handle_) {
482 GPU_shader_batch_cancel(compilation_handle_);
483 }
484 GPU_SHADER_FREE_SAFE(shader_);
485 }
486
487 /* Schedule the shader to be compile in a worker thread. */
489 {
490 if (is_ready()) {
491 return;
492 }
493
494 std::scoped_lock lock(mutex_);
495
496 if (compilation_handle_) {
497 if (GPU_shader_batch_is_ready(compilation_handle_)) {
498 shader_ = GPU_shader_batch_finalize(compilation_handle_)[0];
499 failed_ = shader_ == nullptr;
500 }
501 return;
502 }
503
504 if (!shader_ && !failed_ && !compilation_handle_) {
505 BLI_assert(!info_name_.empty());
506 const GPUShaderCreateInfo *create_info = GPU_shader_create_info_get(info_name_.c_str());
507 compilation_handle_ = GPU_shader_batch_create_from_infos({&create_info, 1});
508 }
509 }
510
511 bool is_ready()
512 {
513 return shader_ || failed_;
514 }
515
516 GPUShader *get()
517 {
518 if (is_ready()) {
519 return shader_;
520 }
521
522 std::scoped_lock lock(mutex_);
523
524 if (!shader_ && !failed_) {
525 if (compilation_handle_) {
526 shader_ = GPU_shader_batch_finalize(compilation_handle_)[0];
527 }
528 else {
529 BLI_assert(!info_name_.empty());
530 shader_ = GPU_shader_create_from_info_name(info_name_.c_str());
531 }
532 failed_ = shader_ == nullptr;
533 }
534
535 return shader_;
536 }
537
538 /* For batch compiled shaders. */
539 /* TODO: Find a better way to handle this. */
540 void set(GPUShader *shader)
541 {
542 std::scoped_lock lock(mutex_);
543 BLI_assert(shader_ == nullptr);
544 shader_ = shader;
545 }
546};
547
548/* Thread-safe container for StaticShader cache classes.
549 * The class instance creation is deferred until the first get() call. */
550template<typename T> class StaticShaderCache {
551 std::atomic<T *> cache_ = nullptr;
552 std::mutex mutex_;
553
554 public:
556 {
557 BLI_assert(cache_ == nullptr);
558 }
559
560 template<typename... Args> T &get(Args &&...constructor_args)
561 {
562 if (cache_) {
563 return *cache_;
564 }
565
566 std::lock_guard lock(mutex_);
567
568 if (cache_ == nullptr) {
569 cache_ = new T(std::forward<Args>(constructor_args)...);
570 }
571 return *cache_;
572 }
573
574 void release()
575 {
576 if (!cache_) {
577 return;
578 }
579
580 std::lock_guard lock(mutex_);
581
582 if (cache_) {
583 delete cache_;
584 cache_ = nullptr;
585 }
586 }
587
588 std::lock_guard<std::mutex> lock_guard()
589 {
590 return std::lock_guard(mutex_);
591 }
592};
593
594} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:46
unsigned int uint
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
GPUShader * GPU_shader_create_from_info_python(const GPUShaderCreateInfo *_info)
void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2])
GPUShader * GPU_shader_create_compute(std::optional< blender::StringRefNull > computecode, std::optional< blender::StringRefNull > libcode, std::optional< blender::StringRefNull > defines, blender::StringRefNull shname)
bool GPU_shader_get_attribute_info(const GPUShader *shader, int attr_location, char r_name[256], int *r_type)
const char * GPU_shader_get_name(GPUShader *shader)
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
int GPU_shader_get_ubo_binding(GPUShader *shader, const char *name)
#define GPU_SHADER_FREE_SAFE(shader)
void GPU_shader_uniform_3f(GPUShader *sh, const char *name, float x, float y, float z)
void GPU_shader_uniform_3iv(GPUShader *sh, const char *name, const int data[3])
blender::Vector< GPUShader * > GPU_shader_batch_finalize(BatchHandle &handle)
void GPU_shader_uniform_2f(GPUShader *sh, const char *name, float x, float y)
static constexpr int GPU_MAX_ATTR
Definition GPU_shader.hh:34
uint GPU_shader_get_ssbo_input_len(const GPUShader *shader)
void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float(*val)[2])
GPUShader * GPU_shader_create_ex(std::optional< blender::StringRefNull > vertcode, std::optional< blender::StringRefNull > fragcode, std::optional< blender::StringRefNull > geomcode, std::optional< blender::StringRefNull > computecode, std::optional< blender::StringRefNull > libcode, std::optional< blender::StringRefNull > defines, blender::StringRefNull shname)
void GPU_shader_uniform_int_ex(GPUShader *shader, int location, int length, int array_size, const int *value)
GPUShader * GPU_shader_create_from_info_name(const char *info_name)
void GPU_shader_cache_dir_clear_old()
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
void GPU_shader_bind(GPUShader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3])
void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3])
void GPU_shader_uniform_1f_array(GPUShader *sh, const char *name, int len, const float *val)
uint GPU_shader_get_attribute_len(const GPUShader *shader)
int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name)
int GPU_shader_get_attribute(const GPUShader *shader, const char *name)
void GPU_shader_batch_wait_for_all()
void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float(*val)[4])
int64_t BatchHandle
Definition GPU_shader.hh:83
GPUShader * GPU_shader_create_from_python(std::optional< blender::StringRefNull > vertcode, std::optional< blender::StringRefNull > fragcode, std::optional< blender::StringRefNull > geomcode, std::optional< blender::StringRefNull > libcode, std::optional< blender::StringRefNull > defines, std::optional< blender::StringRefNull > name)
void GPU_shader_set_parent(GPUShader *shader, GPUShader *parent)
bool GPU_shader_batch_is_ready(BatchHandle handle)
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
void GPU_shader_uniform_float_ex(GPUShader *shader, int location, int length, int array_size, const float *value)
std::string GPU_shader_preprocess_source(blender::StringRefNull original)
SpecializationBatchHandle GPU_shader_batch_specializations(blender::Span< ShaderSpecialization > specializations, CompilationPriority priority=CompilationPriority::High)
const GPUShaderCreateInfo * GPU_shader_create_info_get(const char *info_name)
CompilationPriority
Definition GPU_shader.hh:81
void GPU_shader_batch_specializations_cancel(SpecializationBatchHandle &handle)
static constexpr int GPU_MAX_UNIFORM_ATTR
Definition GPU_shader.hh:37
void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
GPUUniformBuiltin
@ GPU_UNIFORM_VIEWPROJECTION_INV
@ GPU_UNIFORM_PROJECTION
@ GPU_UNIFORM_RESOURCE_ID
@ GPU_UNIFORM_VIEWPROJECTION
@ GPU_UNIFORM_SRGB_TRANSFORM
@ GPU_UNIFORM_VIEW
@ GPU_UNIFORM_MODEL
@ GPU_UNIFORM_MODELVIEW
@ GPU_UNIFORM_BASE_INSTANCE
@ GPU_UNIFORM_VIEW_INV
@ GPU_UNIFORM_MODEL_INV
@ GPU_UNIFORM_PROJECTION_INV
@ GPU_UNIFORM_CLIPPLANES
@ GPU_UNIFORM_COLOR
@ GPU_UNIFORM_MODELVIEW_INV
@ GPU_UNIFORM_NORMAL
@ GPU_UNIFORM_RESOURCE_CHUNK
@ GPU_UNIFORM_MVP
GPUShader * GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4])
void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, float z, float w)
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
int64_t SpecializationBatchHandle
GPUShader * GPU_shader_create(std::optional< blender::StringRefNull > vertcode, std::optional< blender::StringRefNull > fragcode, std::optional< blender::StringRefNull > geomcode, std::optional< blender::StringRefNull > libcode, std::optional< blender::StringRefNull > defines, blender::StringRefNull shname)
void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4])
int GPU_shader_get_constant(GPUShader *shader, const char *name)
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
void GPU_shader_batch_cancel(BatchHandle &handle)
void GPU_shader_free(GPUShader *shader)
bool GPU_shader_create_info_check_error(const GPUShaderCreateInfo *_info, char r_error[128])
void GPU_shader_unbind()
GPUShader * GPU_shader_get_bound()
BatchHandle GPU_shader_batch_create_from_infos(blender::Span< const GPUShaderCreateInfo * > infos, CompilationPriority priority=CompilationPriority::High)
void GPU_shader_warm_cache(GPUShader *shader, int limit)
GPUUniformBlockBuiltin
@ GPU_UNIFORM_BLOCK_DRW_VIEW
@ GPU_UNIFORM_BLOCK_DRW_MODEL
@ GPU_NUM_UNIFORM_BLOCKS
@ GPU_UNIFORM_BLOCK_MODEL
@ GPU_UNIFORM_BLOCK_VIEW
@ GPU_UNIFORM_BLOCK_DRW_CLIPPING
@ GPU_UNIFORM_BLOCK_DRW_INFOS
@ GPU_UNIFORM_BLOCK_INFO
bool GPU_shader_batch_specializations_is_ready(SpecializationBatchHandle &handle)
const blender::gpu::shader::SpecializationConstants & GPU_shader_get_default_constant_state(GPUShader *sh)
void GPU_shader_compile_static()
bool GPU_shader_get_ssbo_input_info(const GPUShader *shader, int ssbo_location, char r_name[256])
volatile int lock
BMesh const char void * data
long long int int64_t
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
NonCopyable(const NonCopyable &other)=delete
T & get(Args &&...constructor_args)
std::lock_guard< std::mutex > lock_guard()
StaticShader & operator=(StaticShader &&other)
void set(GPUShader *shader)
StaticShader(StaticShader &&other)
StaticShader(std::string info_name)
float length(VecOp< float, D >) RET
#define T
blender::gpu::shader::SpecializationConstants constants
uint len