Blender V5.0
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;
25class Shader;
26} // namespace blender::gpu
27
29struct GPUShaderCreateInfo;
30
31/* Hardware limit is 16. Position attribute is always needed so we reduce to 15.
32 * This makes sure the GPUVertexFormat name buffer does not overflow. */
33constexpr static int GPU_MAX_ATTR = 15;
34
35/* Determined by the maximum uniform buffer size divided by chunk size. */
36constexpr static int GPU_MAX_UNIFORM_ATTR = 8;
37
38/* -------------------------------------------------------------------- */
41
47
52blender::gpu::Shader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info);
53
57blender::gpu::Shader *GPU_shader_create_from_info_python(const GPUShaderCreateInfo *_info);
58
66
72const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name);
73
78bool GPU_shader_create_info_check_error(const GPUShaderCreateInfo *_info, char r_error[128]);
79
81
119
121
122/* -------------------------------------------------------------------- */
125
127
129
130/* -------------------------------------------------------------------- */
133
141void GPU_shader_bind(
142 blender::gpu::Shader *shader,
143 const blender::gpu::shader::SpecializationConstants *constants_state = nullptr);
144
150void GPU_shader_unbind();
151
157
159
160/* -------------------------------------------------------------------- */
163
164const char *GPU_shader_get_name(blender::gpu::Shader *shader);
165
167
168/* -------------------------------------------------------------------- */
171
179
184int GPU_shader_get_uniform(blender::gpu::Shader *shader, const char *name);
185
189int GPU_shader_get_constant(blender::gpu::Shader *shader, const char *name);
190
196 blender::gpu::Shader *shader, int location, int length, int array_size, const float *value);
198 blender::gpu::Shader *shader, int location, int length, int array_size, const int *value);
199
206void GPU_shader_uniform_1i(blender::gpu::Shader *sh, const char *name, int value);
207void GPU_shader_uniform_1b(blender::gpu::Shader *sh, const char *name, bool value);
208void GPU_shader_uniform_1f(blender::gpu::Shader *sh, const char *name, float value);
209void GPU_shader_uniform_2f(blender::gpu::Shader *sh, const char *name, float x, float y);
210void GPU_shader_uniform_3f(blender::gpu::Shader *sh, const char *name, float x, float y, float z);
212 blender::gpu::Shader *sh, const char *name, float x, float y, float z, float w);
213void GPU_shader_uniform_2fv(blender::gpu::Shader *sh, const char *name, const float data[2]);
214void GPU_shader_uniform_3fv(blender::gpu::Shader *sh, const char *name, const float data[3]);
215void GPU_shader_uniform_4fv(blender::gpu::Shader *sh, const char *name, const float data[4]);
216void GPU_shader_uniform_2iv(blender::gpu::Shader *sh, const char *name, const int data[2]);
217void GPU_shader_uniform_3iv(blender::gpu::Shader *sh, const char *name, const int data[3]);
218void GPU_shader_uniform_mat4(blender::gpu::Shader *sh, const char *name, const float data[4][4]);
220 const char *name,
221 const float data[3][3]);
223 const char *name,
224 int len,
225 const float *val);
227 const char *name,
228 int len,
229 const float (*val)[2]);
231 const char *name,
232 int len,
233 const float (*val)[4]);
234
236
237/* -------------------------------------------------------------------- */
242
245int GPU_shader_get_attribute(const blender::gpu::Shader *shader, const char *name);
247 int attr_location,
248 char r_name[256],
249 int *r_type);
251 int ssbo_location,
252 char r_name[256]);
253
255
256/* -------------------------------------------------------------------- */
263
264/* Return the default constants.
265 * All constants available for this shader should fit the returned structure. */
268
270
275
290
297
303
305
306/* -------------------------------------------------------------------- */
311
347void GPU_shader_warm_cache(blender::gpu::Shader *shader, int limit);
348
349/* We expect the parent shader to be compiled and already have some cached PSOs when being assigned
350 * as a reference. Ensure the parent shader still exists when `GPU_shader_cache_warm(..)` is
351 * called. */
353
358 GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */
359 GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */
360 GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */
361 GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */
362 GPU_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */
363 GPU_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */
364
365 GPU_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */
366 GPU_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */
367 GPU_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */
368 GPU_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */
369 GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
370
371 GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
372 GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
373
374 GPU_UNIFORM_COLOR, /* vec4 color */
375 GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
376 GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
377 GPU_UNIFORM_RESOURCE_ID, /* int resourceId */
378 GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */
379 GPU_UNIFORM_SCENE_LINEAR_XFORM, /* float3x3 gpu_scene_linear_to_xyz */
380};
381#define GPU_NUM_UNIFORMS (GPU_UNIFORM_SCENE_LINEAR_XFORM + 1)
382
388
395
397
411
414
416
417#define GPU_SHADER_FREE_SAFE(shader) \
418 do { \
419 if (shader != nullptr) { \
420 GPU_shader_free(shader); \
421 shader = nullptr; \
422 } \
423 } while (0)
424
425#include "BLI_utility_mixins.hh"
426#include <atomic>
427#include <mutex>
428
429namespace blender::gpu {
430
431/* blender::gpu::Shader wrapper that makes compilation threadsafe.
432 * The compilation is deferred until the first get() call.
433 * Concurrently using the shader from multiple threads is still unsafe. */
435 private:
436 std::string info_name_;
437 std::atomic<blender::gpu::Shader *> shader_ = nullptr;
438 /* TODO: Failed compilation detection should be supported by the blender::gpu::Shader API. */
439 std::atomic<bool> failed_ = false;
440 std::mutex mutex_;
441 /* Handle for async compilation. */
442 BatchHandle compilation_handle_ = 0;
443
444 void move(StaticShader &&other)
445 {
446 std::scoped_lock lock1(mutex_);
447 std::scoped_lock lock2(other.mutex_);
448 BLI_assert(shader_ == nullptr && info_name_.empty());
449 std::swap(info_name_, other.info_name_);
450 /* No std::swap support for atomics. */
451 shader_.exchange(other.shader_.exchange(shader_));
452 failed_.exchange(other.failed_.exchange(failed_));
453 std::swap(compilation_handle_, other.compilation_handle_);
454 }
455
456 public:
457 StaticShader(std::string info_name) : info_name_(info_name) {}
458
459 StaticShader() = default;
461 {
462 move(std::move(other));
463 }
465 {
466 move(std::move(other));
467 return *this;
468 };
469
471 {
472 if (compilation_handle_) {
473 GPU_shader_batch_cancel(compilation_handle_);
474 }
475 GPU_SHADER_FREE_SAFE(shader_);
476 }
477
478 /* Schedule the shader to be compile in a worker thread. */
480 {
481 if (is_ready()) {
482 return;
483 }
484
485 std::scoped_lock lock(mutex_);
486
487 if (compilation_handle_) {
488 if (GPU_shader_batch_is_ready(compilation_handle_)) {
489 shader_ = GPU_shader_batch_finalize(compilation_handle_)[0];
490 failed_ = shader_ == nullptr;
491 }
492 return;
493 }
494
495 if (!shader_ && !failed_ && !compilation_handle_) {
496 BLI_assert(!info_name_.empty());
497 const GPUShaderCreateInfo *create_info = GPU_shader_create_info_get(info_name_.c_str());
498 compilation_handle_ = GPU_shader_batch_create_from_infos({&create_info, 1});
499 }
500 }
501
502 bool is_ready()
503 {
504 return shader_ || failed_;
505 }
506
508 {
509 if (is_ready()) {
510 return shader_;
511 }
512
513 std::scoped_lock lock(mutex_);
514
515 if (!shader_ && !failed_) {
516 if (compilation_handle_) {
517 shader_ = GPU_shader_batch_finalize(compilation_handle_)[0];
518 }
519 else {
520 BLI_assert(!info_name_.empty());
521 shader_ = GPU_shader_create_from_info_name(info_name_.c_str());
522 }
523 failed_ = shader_ == nullptr;
524 }
525
526 return shader_;
527 }
528
529 /* For batch compiled shaders. */
530 /* TODO: Find a better way to handle this. */
532 {
533 std::scoped_lock lock(mutex_);
534 BLI_assert(shader_ == nullptr);
535 shader_ = shader;
536 }
537};
538
539/* Thread-safe container for StaticShader cache classes.
540 * The class instance creation is deferred until the first get() call. */
541template<typename T> class StaticShaderCache {
542 std::atomic<T *> cache_ = nullptr;
543 std::mutex mutex_;
544
545 public:
547 {
548 BLI_assert(cache_ == nullptr);
549 }
550
551 template<typename... Args> T &get(Args &&...constructor_args)
552 {
553 if (cache_) {
554 return *cache_;
555 }
556
557 std::lock_guard lock(mutex_);
558
559 if (cache_ == nullptr) {
560 cache_ = new T(std::forward<Args>(constructor_args)...);
561 }
562 return *cache_;
563 }
564
565 void release()
566 {
567 if (!cache_) {
568 return;
569 }
570
571 std::lock_guard lock(mutex_);
572
573 if (cache_) {
574 delete cache_;
575 cache_ = nullptr;
576 }
577 }
578
579 std::lock_guard<std::mutex> lock_guard()
580 {
581 return std::lock_guard(mutex_);
582 }
583};
584
585} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:46
unsigned int uint
blender::gpu::Shader * GPU_shader_create_from_info_python(const GPUShaderCreateInfo *_info)
int GPU_shader_get_ubo_binding(blender::gpu::Shader *shader, const char *name)
void GPU_shader_uniform_2fv_array(blender::gpu::Shader *sh, const char *name, int len, const float(*val)[2])
int GPU_shader_get_constant(blender::gpu::Shader *shader, const char *name)
void GPU_shader_uniform_1b(blender::gpu::Shader *sh, const char *name, bool value)
const blender::gpu::shader::SpecializationConstants & GPU_shader_get_default_constant_state(blender::gpu::Shader *sh)
#define GPU_SHADER_FREE_SAFE(shader)
int GPU_shader_get_uniform_block(blender::gpu::Shader *shader, const char *name)
void GPU_shader_uniform_4fv_array(blender::gpu::Shader *sh, const char *name, int len, const float(*val)[4])
static constexpr int GPU_MAX_ATTR
Definition GPU_shader.hh:33
void GPU_shader_uniform_1f(blender::gpu::Shader *sh, const char *name, float value)
void GPU_shader_cache_dir_clear_old()
void GPU_shader_free(blender::gpu::Shader *shader)
bool GPU_shader_get_attribute_info(const blender::gpu::Shader *shader, int attr_location, char r_name[256], int *r_type)
bool GPU_shader_get_ssbo_input_info(const blender::gpu::Shader *shader, int ssbo_location, char r_name[256])
blender::gpu::Shader * GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
void GPU_shader_uniform_4fv(blender::gpu::Shader *sh, const char *name, const float data[4])
void GPU_shader_uniform_mat3_as_mat4(blender::gpu::Shader *sh, const char *name, const float data[3][3])
int GPU_shader_get_sampler_binding(blender::gpu::Shader *shader, const char *name)
void GPU_shader_uniform_3fv(blender::gpu::Shader *sh, const char *name, const float data[3])
bool GPU_shader_batch_is_compiling()
void GPU_shader_batch_wait_for_all()
uint GPU_shader_get_attribute_len(const blender::gpu::Shader *shader)
int64_t BatchHandle
Definition GPU_shader.hh:82
uint GPU_shader_get_ssbo_input_len(const blender::gpu::Shader *shader)
void GPU_shader_bind(blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
blender::Vector< blender::gpu::Shader * > GPU_shader_batch_finalize(BatchHandle &handle)
bool GPU_shader_batch_is_ready(BatchHandle handle)
int GPU_shader_get_ssbo_binding(blender::gpu::Shader *shader, const char *name)
std::string GPU_shader_preprocess_source(blender::StringRefNull original)
blender::gpu::Shader * GPU_shader_get_bound()
SpecializationBatchHandle GPU_shader_batch_specializations(blender::Span< ShaderSpecialization > specializations, CompilationPriority priority=CompilationPriority::High)
const GPUShaderCreateInfo * GPU_shader_create_info_get(const char *info_name)
void GPU_shader_uniform_int_ex(blender::gpu::Shader *shader, int location, int length, int array_size, const int *value)
void GPU_shader_uniform_1i(blender::gpu::Shader *sh, const char *name, int value)
CompilationPriority
Definition GPU_shader.hh:80
void GPU_shader_batch_specializations_cancel(SpecializationBatchHandle &handle)
static constexpr int GPU_MAX_UNIFORM_ATTR
Definition GPU_shader.hh:36
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_SCENE_LINEAR_XFORM
@ GPU_UNIFORM_PROJECTION_INV
@ GPU_UNIFORM_CLIPPLANES
@ GPU_UNIFORM_COLOR
@ GPU_UNIFORM_MODELVIEW_INV
@ GPU_UNIFORM_NORMAL
@ GPU_UNIFORM_RESOURCE_CHUNK
@ GPU_UNIFORM_MVP
void GPU_shader_uniform_mat4(blender::gpu::Shader *sh, const char *name, const float data[4][4])
void GPU_shader_uniform_4f(blender::gpu::Shader *sh, const char *name, float x, float y, float z, float w)
int64_t SpecializationBatchHandle
const char * GPU_shader_get_name(blender::gpu::Shader *shader)
int GPU_shader_get_attribute(const blender::gpu::Shader *shader, const char *name)
void GPU_shader_uniform_2f(blender::gpu::Shader *sh, const char *name, float x, float y)
void GPU_shader_set_parent(blender::gpu::Shader *shader, blender::gpu::Shader *parent)
blender::gpu::Shader * GPU_shader_create_from_info_name(const char *info_name)
void GPU_shader_uniform_2fv(blender::gpu::Shader *sh, const char *name, const float data[2])
int GPU_shader_get_uniform(blender::gpu::Shader *shader, const char *name)
void GPU_shader_batch_cancel(BatchHandle &handle)
void GPU_shader_uniform_1f_array(blender::gpu::Shader *sh, const char *name, int len, const float *val)
bool GPU_shader_create_info_check_error(const GPUShaderCreateInfo *_info, char r_error[128])
void GPU_shader_unbind()
void GPU_shader_warm_cache(blender::gpu::Shader *shader, int limit)
void GPU_shader_uniform_3f(blender::gpu::Shader *sh, const char *name, float x, float y, float z)
BatchHandle GPU_shader_batch_create_from_infos(blender::Span< const GPUShaderCreateInfo * > infos, CompilationPriority priority=CompilationPriority::High)
int GPU_shader_get_builtin_uniform(blender::gpu::Shader *shader, int builtin)
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
void GPU_shader_uniform_float_ex(blender::gpu::Shader *shader, int location, int length, int array_size, const float *value)
bool GPU_shader_batch_specializations_is_ready(SpecializationBatchHandle &handle)
void GPU_shader_compile_static()
void GPU_shader_uniform_2iv(blender::gpu::Shader *sh, const char *name, const int data[2])
void GPU_shader_uniform_3iv(blender::gpu::Shader *sh, const char *name, const int data[3])
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(blender::gpu::Shader *shader)
blender::gpu::Shader * get()
StaticShader(StaticShader &&other)
StaticShader(std::string info_name)
float length(VecOp< float, D >) RET
#define T
const char * name
blender::gpu::shader::SpecializationConstants constants
blender::gpu::Shader * shader
uint len