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
120
122
123/* -------------------------------------------------------------------- */
126
127void GPU_shader_free(GPUShader *shader);
128
130
131/* -------------------------------------------------------------------- */
134
142void GPU_shader_bind(
143 GPUShader *shader,
144 const blender::gpu::shader::SpecializationConstants *constants_state = nullptr);
145
151void GPU_shader_unbind();
152
157GPUShader *GPU_shader_get_bound();
158
160
161/* -------------------------------------------------------------------- */
164
165const char *GPU_shader_get_name(GPUShader *shader);
166
168
169/* -------------------------------------------------------------------- */
172
177int GPU_shader_get_ubo_binding(GPUShader *shader, const char *name);
178int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name);
179int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name);
180
185int GPU_shader_get_uniform(GPUShader *shader, const char *name);
186
190int GPU_shader_get_constant(GPUShader *shader, const char *name);
191
197 GPUShader *shader, int location, int length, int array_size, const float *value);
199 GPUShader *shader, int location, int length, int array_size, const int *value);
200
207void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value);
208void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value);
209void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value);
210void GPU_shader_uniform_2f(GPUShader *sh, const char *name, float x, float y);
211void GPU_shader_uniform_3f(GPUShader *sh, const char *name, float x, float y, float z);
212void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, float z, float w);
213void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2]);
214void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3]);
215void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]);
216void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2]);
217void GPU_shader_uniform_3iv(GPUShader *sh, const char *name, const int data[3]);
218void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]);
219void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3]);
220void GPU_shader_uniform_1f_array(GPUShader *sh, const char *name, int len, const float *val);
221void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]);
222void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]);
223
225
226/* -------------------------------------------------------------------- */
231
232uint GPU_shader_get_attribute_len(const GPUShader *shader);
233uint GPU_shader_get_ssbo_input_len(const GPUShader *shader);
234int GPU_shader_get_attribute(const GPUShader *shader, const char *name);
235bool GPU_shader_get_attribute_info(const GPUShader *shader,
236 int attr_location,
237 char r_name[256],
238 int *r_type);
239bool GPU_shader_get_ssbo_input_info(const GPUShader *shader, int ssbo_location, char r_name[256]);
240
242
243/* -------------------------------------------------------------------- */
250
251/* Return the default constants.
252 * All constants available for this shader should fit the returned structure. */
254 GPUShader *sh);
255
257
262
277
284
290
292
293/* -------------------------------------------------------------------- */
298
299GPUShader *GPU_shader_create(std::optional<blender::StringRefNull> vertcode,
300 std::optional<blender::StringRefNull> fragcode,
301 std::optional<blender::StringRefNull> geomcode,
302 std::optional<blender::StringRefNull> libcode,
303 std::optional<blender::StringRefNull> defines,
305GPUShader *GPU_shader_create_compute(std::optional<blender::StringRefNull> computecode,
306 std::optional<blender::StringRefNull> libcode,
307 std::optional<blender::StringRefNull> defines,
309GPUShader *GPU_shader_create_from_python(std::optional<blender::StringRefNull> vertcode,
310 std::optional<blender::StringRefNull> fragcode,
311 std::optional<blender::StringRefNull> geomcode,
312 std::optional<blender::StringRefNull> libcode,
313 std::optional<blender::StringRefNull> defines,
314 std::optional<blender::StringRefNull> name);
315GPUShader *GPU_shader_create_ex(std::optional<blender::StringRefNull> vertcode,
316 std::optional<blender::StringRefNull> fragcode,
317 std::optional<blender::StringRefNull> geomcode,
318 std::optional<blender::StringRefNull> computecode,
319 std::optional<blender::StringRefNull> libcode,
320 std::optional<blender::StringRefNull> defines,
322
358void GPU_shader_warm_cache(GPUShader *shader, int limit);
359
360/* We expect the parent shader to be compiled and already have some cached PSOs when being assigned
361 * as a reference. Ensure the parent shader still exists when `GPU_shader_cache_warm(..)` is
362 * called. */
363void GPU_shader_set_parent(GPUShader *shader, GPUShader *parent);
364
369 GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */
370 GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */
371 GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */
372 GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */
373 GPU_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */
374 GPU_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */
375
376 GPU_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */
377 GPU_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */
378 GPU_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */
379 GPU_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */
380 GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
381
382 GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
383 GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
384
385 GPU_UNIFORM_COLOR, /* vec4 color */
386 GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
387 GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
388 GPU_UNIFORM_RESOURCE_ID, /* int resourceId */
389 GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */
390};
391#define GPU_NUM_UNIFORMS (GPU_UNIFORM_SRGB_TRANSFORM + 1)
392
397int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
398
405
407
421
423int GPU_shader_get_builtin_block(GPUShader *shader, int builtin);
424
426int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
427
429
430#define GPU_SHADER_FREE_SAFE(shader) \
431 do { \
432 if (shader != nullptr) { \
433 GPU_shader_free(shader); \
434 shader = nullptr; \
435 } \
436 } while (0)
437
438#include "BLI_utility_mixins.hh"
439#include <atomic>
440#include <mutex>
441
442namespace blender::gpu {
443
444/* GPUShader wrapper that makes compilation threadsafe.
445 * The compilation is deferred until the first get() call.
446 * Concurrently using the shader from multiple threads is still unsafe. */
448 private:
449 std::string info_name_;
450 std::atomic<GPUShader *> shader_ = nullptr;
451 /* TODO: Failed compilation detection should be supported by the GPUShader API. */
452 std::atomic<bool> failed_ = false;
453 std::mutex mutex_;
454 /* Handle for async compilation. */
455 BatchHandle compilation_handle_ = 0;
456
457 void move(StaticShader &&other)
458 {
459 std::scoped_lock lock1(mutex_);
460 std::scoped_lock lock2(other.mutex_);
461 BLI_assert(shader_ == nullptr && info_name_.empty());
462 std::swap(info_name_, other.info_name_);
463 /* No std::swap support for atomics. */
464 shader_.exchange(other.shader_.exchange(shader_));
465 failed_.exchange(other.failed_.exchange(failed_));
466 std::swap(compilation_handle_, other.compilation_handle_);
467 }
468
469 public:
470 StaticShader(std::string info_name) : info_name_(info_name) {}
471
472 StaticShader() = default;
474 {
475 move(std::move(other));
476 }
478 {
479 move(std::move(other));
480 return *this;
481 };
482
484 {
485 if (compilation_handle_) {
486 GPU_shader_batch_cancel(compilation_handle_);
487 }
488 GPU_SHADER_FREE_SAFE(shader_);
489 }
490
491 /* Schedule the shader to be compile in a worker thread. */
493 {
494 if (is_ready()) {
495 return;
496 }
497
498 std::scoped_lock lock(mutex_);
499
500 if (compilation_handle_) {
501 if (GPU_shader_batch_is_ready(compilation_handle_)) {
502 shader_ = GPU_shader_batch_finalize(compilation_handle_)[0];
503 failed_ = shader_ == nullptr;
504 }
505 return;
506 }
507
508 if (!shader_ && !failed_ && !compilation_handle_) {
509 BLI_assert(!info_name_.empty());
510 const GPUShaderCreateInfo *create_info = GPU_shader_create_info_get(info_name_.c_str());
511 compilation_handle_ = GPU_shader_batch_create_from_infos({&create_info, 1});
512 }
513 }
514
515 bool is_ready()
516 {
517 return shader_ || failed_;
518 }
519
520 GPUShader *get()
521 {
522 if (is_ready()) {
523 return shader_;
524 }
525
526 std::scoped_lock lock(mutex_);
527
528 if (!shader_ && !failed_) {
529 if (compilation_handle_) {
530 shader_ = GPU_shader_batch_finalize(compilation_handle_)[0];
531 }
532 else {
533 BLI_assert(!info_name_.empty());
534 shader_ = GPU_shader_create_from_info_name(info_name_.c_str());
535 }
536 failed_ = shader_ == nullptr;
537 }
538
539 return shader_;
540 }
541
542 /* For batch compiled shaders. */
543 /* TODO: Find a better way to handle this. */
544 void set(GPUShader *shader)
545 {
546 std::scoped_lock lock(mutex_);
547 BLI_assert(shader_ == nullptr);
548 shader_ = shader;
549 }
550};
551
552/* Thread-safe container for StaticShader cache classes.
553 * The class instance creation is deferred until the first get() call. */
554template<typename T> class StaticShaderCache {
555 std::atomic<T *> cache_ = nullptr;
556 std::mutex mutex_;
557
558 public:
560 {
561 BLI_assert(cache_ == nullptr);
562 }
563
564 template<typename... Args> T &get(Args &&...constructor_args)
565 {
566 if (cache_) {
567 return *cache_;
568 }
569
570 std::lock_guard lock(mutex_);
571
572 if (cache_ == nullptr) {
573 cache_ = new T(std::forward<Args>(constructor_args)...);
574 }
575 return *cache_;
576 }
577
578 void release()
579 {
580 if (!cache_) {
581 return;
582 }
583
584 std::lock_guard lock(mutex_);
585
586 if (cache_) {
587 delete cache_;
588 cache_ = nullptr;
589 }
590 }
591
592 std::lock_guard<std::mutex> lock_guard()
593 {
594 return std::lock_guard(mutex_);
595 }
596};
597
598} // 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)
bool GPU_shader_batch_is_compiling()
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