Blender  V3.3
eevee_shader.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation.
3  */
4 
13 
14 #include "eevee_shader.hh"
15 
16 namespace blender::eevee {
17 
18 /* -------------------------------------------------------------------- */
23 ShaderModule *ShaderModule::g_shader_module = nullptr;
24 
26 {
27  if (g_shader_module == nullptr) {
28  /* TODO(@fclem) thread-safety. */
29  g_shader_module = new ShaderModule();
30  }
31  return g_shader_module;
32 }
33 
35 {
36  if (g_shader_module != nullptr) {
37  /* TODO(@fclem) thread-safety. */
38  delete g_shader_module;
39  g_shader_module = nullptr;
40  }
41 }
42 
44 {
45  for (GPUShader *&shader : shaders_) {
46  shader = nullptr;
47  }
48 
49 #ifdef DEBUG
50  /* Ensure all shader are described. */
51  for (auto i : IndexRange(MAX_SHADER_TYPE)) {
52  const char *name = static_shader_create_info_name_get(eShaderType(i));
53  if (name == nullptr) {
54  std::cerr << "EEVEE: Missing case for eShaderType(" << i
55  << ") in static_shader_create_info_name_get().";
56  BLI_assert(0);
57  }
58  const GPUShaderCreateInfo *create_info = GPU_shader_create_info_get(name);
59  BLI_assert_msg(create_info != nullptr, "EEVEE: Missing create info for static shader.");
60  }
61 #endif
62 }
63 
65 {
66  for (GPUShader *&shader : shaders_) {
67  DRW_SHADER_FREE_SAFE(shader);
68  }
69 }
70 
73 /* -------------------------------------------------------------------- */
78 const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_type)
79 {
80  switch (shader_type) {
81  case FILM_FRAG:
82  return "eevee_film_frag";
83  case FILM_COMP:
84  return "eevee_film_comp";
85  /* To avoid compiler warning about missing case. */
86  case MAX_SHADER_TYPE:
87  return "";
88  }
89  return "";
90 }
91 
93 {
94  if (shaders_[shader_type] == nullptr) {
95  const char *shader_name = static_shader_create_info_name_get(shader_type);
96 
97  shaders_[shader_type] = GPU_shader_create_from_info_name(shader_name);
98 
99  if (shaders_[shader_type] == nullptr) {
100  fprintf(stderr, "EEVEE: error: Could not compile static shader \"%s\"\n", shader_name);
101  }
102  BLI_assert(shaders_[shader_type] != nullptr);
103  }
104  return shaders_[shader_type];
105 }
106 
109 /* -------------------------------------------------------------------- */
115 {
116  using namespace blender::gpu::shader;
117 
118  uint64_t shader_uuid = GPU_material_uuid_get(gpumat);
119 
120  eMaterialPipeline pipeline_type;
121  eMaterialGeometry geometry_type;
122  material_type_from_shader_uuid(shader_uuid, pipeline_type, geometry_type);
123 
124  GPUCodegenOutput &codegen = *codegen_;
125  ShaderCreateInfo &info = *reinterpret_cast<ShaderCreateInfo *>(codegen.create_info);
126 
127  info.auto_resource_location(true);
128 
130  info.define("MAT_TRANSPARENT");
131  }
133  switch (geometry_type) {
134  case MAT_GEOM_MESH:
135  /* Support using gpu builtin barycentrics. */
136  info.define("USE_BARYCENTRICS");
137  info.builtins(BuiltinBits::BARYCENTRIC_COORD);
138  break;
139  case MAT_GEOM_CURVES:
140  /* Support using one vec2 attribute. See #hair_get_barycentric(). */
141  info.define("USE_BARYCENTRICS");
142  break;
143  default:
144  /* No support */
145  break;
146  }
147  }
148 
149  std::stringstream global_vars;
150  switch (geometry_type) {
151  case MAT_GEOM_MESH:
153  break;
154  case MAT_GEOM_CURVES:
156  for (auto &input : info.vertex_inputs_) {
157  if (input.name == "orco") {
159  global_vars << input.type << " " << input.name << ";\n";
160  }
161  else {
162  info.sampler(0, ImageType::FLOAT_BUFFER, input.name, Frequency::BATCH);
163  }
164  }
165  info.vertex_inputs_.clear();
166  break;
167  case MAT_GEOM_WORLD:
173  case MAT_GEOM_GPENCIL:
179  for (auto &input : info.vertex_inputs_) {
180  global_vars << input.type << " " << input.name << ";\n";
181  }
182  info.vertex_inputs_.clear();
183  break;
184  case MAT_GEOM_VOLUME:
186  info.vertex_inputs_.clear();
187  break;
188  }
189 
190  const bool do_fragment_attrib_load = (geometry_type == MAT_GEOM_WORLD);
191 
192  if (do_fragment_attrib_load && !info.vertex_out_interfaces_.is_empty()) {
193  /* Codegen outputs only one interface. */
194  const StageInterfaceInfo &iface = *info.vertex_out_interfaces_.first();
195  /* Globals the attrib_load() can write to when it is in the fragment shader. */
196  global_vars << "struct " << iface.name << " {\n";
197  for (const auto &inout : iface.inouts) {
198  global_vars << " " << inout.type << " " << inout.name << ";\n";
199  }
200  global_vars << "};\n";
201  global_vars << iface.name << " " << iface.instance_name << ";\n";
202 
203  info.vertex_out_interfaces_.clear();
204  }
205 
206  std::stringstream attr_load;
207  attr_load << "void attrib_load()\n";
208  attr_load << "{\n";
209  attr_load << ((codegen.attr_load) ? codegen.attr_load : "");
210  attr_load << "}\n\n";
211 
212  std::stringstream vert_gen, frag_gen;
213 
214  if (do_fragment_attrib_load) {
215  frag_gen << global_vars.str() << attr_load.str();
216  }
217  else {
218  vert_gen << global_vars.str() << attr_load.str();
219  }
220 
221  {
222  /* Only mesh and curves support vertex displacement for now. */
223  if (ELEM(geometry_type, MAT_GEOM_MESH, MAT_GEOM_CURVES, MAT_GEOM_GPENCIL)) {
224  vert_gen << "vec3 nodetree_displacement()\n";
225  vert_gen << "{\n";
226  vert_gen << ((codegen.displacement) ? codegen.displacement : "return vec3(0);\n");
227  vert_gen << "}\n\n";
228  }
229 
230  info.vertex_source_generated = vert_gen.str();
231  }
232 
233  {
234  frag_gen << ((codegen.material_functions) ? codegen.material_functions : "\n");
235 
236  if (codegen.displacement) {
237  /* Bump displacement. Needed to recompute normals after displacement. */
238  info.define("MAT_DISPLACEMENT_BUMP");
239 
240  frag_gen << "vec3 nodetree_displacement()\n";
241  frag_gen << "{\n";
242  frag_gen << codegen.displacement;
243  frag_gen << "}\n\n";
244  }
245 
246  frag_gen << "Closure nodetree_surface()\n";
247  frag_gen << "{\n";
248  frag_gen << " closure_weights_reset();\n";
249  frag_gen << ((codegen.surface) ? codegen.surface : "return Closure(0);\n");
250  frag_gen << "}\n\n";
251 
252  frag_gen << "Closure nodetree_volume()\n";
253  frag_gen << "{\n";
254  frag_gen << " closure_weights_reset();\n";
255  frag_gen << ((codegen.volume) ? codegen.volume : "return Closure(0);\n");
256  frag_gen << "}\n\n";
257 
258  frag_gen << "float nodetree_thickness()\n";
259  frag_gen << "{\n";
260  /* TODO(fclem): Better default. */
261  frag_gen << ((codegen.thickness) ? codegen.thickness : "return 0.1;\n");
262  frag_gen << "}\n\n";
263 
264  info.fragment_source_generated = frag_gen.str();
265  }
266 
267  /* Geometry Info. */
268  switch (geometry_type) {
269  case MAT_GEOM_WORLD:
270  info.additional_info("eevee_geom_world");
271  break;
272  case MAT_GEOM_VOLUME:
273  info.additional_info("eevee_geom_volume");
274  break;
275  case MAT_GEOM_GPENCIL:
276  info.additional_info("eevee_geom_gpencil");
277  break;
278  case MAT_GEOM_CURVES:
279  info.additional_info("eevee_geom_curves");
280  break;
281  case MAT_GEOM_MESH:
282  default:
283  info.additional_info("eevee_geom_mesh");
284  break;
285  }
286 
287  /* Pipeline Info. */
288  switch (geometry_type) {
289  case MAT_GEOM_WORLD:
290  info.additional_info("eevee_surf_world");
291  break;
292  case MAT_GEOM_VOLUME:
293  break;
294  default:
295  switch (pipeline_type) {
298  info.additional_info("eevee_surf_depth", "eevee_velocity_geom");
299  break;
302  case MAT_PIPE_SHADOW:
303  info.additional_info("eevee_surf_depth");
304  break;
305  case MAT_PIPE_DEFERRED:
306  info.additional_info("eevee_surf_deferred");
307  break;
308  case MAT_PIPE_FORWARD:
309  info.additional_info("eevee_surf_forward");
310  break;
311  default:
312  BLI_assert(0);
313  break;
314  }
315  break;
316  }
317 }
318 
319 /* WATCH: This can be called from another thread! Needs to not touch the shader module in any
320  * thread unsafe manner. */
321 static void codegen_callback(void *thunk, GPUMaterial *mat, GPUCodegenOutput *codegen)
322 {
323  reinterpret_cast<ShaderModule *>(thunk)->material_create_info_ammend(mat, codegen);
324 }
325 
327  struct bNodeTree *nodetree,
328  eMaterialPipeline pipeline_type,
329  eMaterialGeometry geometry_type,
330  bool deferred_compilation)
331 {
332  uint64_t shader_uuid = shader_uuid_from_material_type(pipeline_type, geometry_type);
333 
334  bool is_volume = (pipeline_type == MAT_PIPE_VOLUME);
335 
337  blender_mat, nodetree, shader_uuid, is_volume, deferred_compilation, codegen_callback, this);
338 }
339 
340 GPUMaterial *ShaderModule::world_shader_get(::World *blender_world, struct bNodeTree *nodetree)
341 {
342  eMaterialPipeline pipeline_type = MAT_PIPE_DEFERRED; /* Unused. */
343  eMaterialGeometry geometry_type = MAT_GEOM_WORLD;
344 
345  uint64_t shader_uuid = shader_uuid_from_material_type(pipeline_type, geometry_type);
346 
347  bool is_volume = (pipeline_type == MAT_PIPE_VOLUME);
348  bool deferred_compilation = false;
349 
350  return DRW_shader_from_world(blender_world,
351  nodetree,
352  shader_uuid,
353  is_volume,
354  deferred_compilation,
356  this);
357 }
358 
359 /* Variation to compile a material only with a nodetree. Caller needs to maintain the list of
360  * materials and call GPU_material_free on it to update the material. */
363  struct bNodeTree *nodetree,
364  eMaterialPipeline pipeline_type,
365  eMaterialGeometry geometry_type,
366  bool is_lookdev)
367 {
368  uint64_t shader_uuid = shader_uuid_from_material_type(pipeline_type, geometry_type);
369 
370  bool is_volume = (pipeline_type == MAT_PIPE_VOLUME);
371 
372  GPUMaterial *gpumat = GPU_material_from_nodetree(nullptr,
373  nullptr,
374  nodetree,
375  &materials,
376  name,
377  shader_uuid,
378  is_volume,
379  is_lookdev,
381  this);
383  GPU_material_compile(gpumat);
384  return gpumat;
385 }
386 
389 } // namespace blender::eevee
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define ATTR_FALLTHROUGH
#define ELEM(...)
#define DRW_SHADER_FREE_SAFE(shader)
Definition: DRW_render.h:254
GPUMaterial * GPU_material_from_nodetree(struct Scene *scene, struct Material *ma, struct bNodeTree *ntree, struct ListBase *gpumaterials, const char *name, uint64_t shader_uuid, bool is_volume_shader, bool is_lookdev, GPUCodegenCallbackFn callback, void *thunk)
Definition: gpu_material.c:624
uint64_t GPU_material_uuid_get(GPUMaterial *mat)
Definition: gpu_material.c:619
void GPU_material_compile(GPUMaterial *mat)
Definition: gpu_material.c:712
void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus status)
Definition: gpu_material.c:579
bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag)
Definition: gpu_material.c:601
@ GPU_MATFLAG_BARYCENTRIC
Definition: GPU_material.h:85
@ GPU_MATFLAG_TRANSPARENT
Definition: GPU_material.h:76
@ GPU_MAT_QUEUED
Definition: GPU_material.h:116
struct GPUShader GPUShader
Definition: GPU_shader.h:20
GPUShader * GPU_shader_create_from_info_name(const char *info_name)
Definition: gpu_shader.cc:265
struct GPUShaderCreateInfo GPUShaderCreateInfo
Definition: GPU_shader.h:18
const GPUShaderCreateInfo * GPU_shader_create_info_get(const char *info_name)
Definition: gpu_shader.cc:247
GPUMaterial * material_shader_get(::Material *blender_mat, struct bNodeTree *nodetree, eMaterialPipeline pipeline_type, eMaterialGeometry geometry_type, bool deferred_compilation)
GPUMaterial * world_shader_get(::World *blender_world, struct bNodeTree *nodetree)
static ShaderModule * module_get()
Definition: eevee_shader.cc:25
void material_create_info_ammend(GPUMaterial *mat, GPUCodegenOutput *codegen)
GPUShader * static_shader_get(eShaderType shader_type)
Definition: eevee_shader.cc:92
GPUMaterial * DRW_shader_from_world(World *wo, struct bNodeTree *ntree, const uint64_t shader_id, const bool is_volume_shader, bool deferred, GPUCodegenCallbackFn callback, void *thunk)
GPUMaterial * DRW_shader_from_material(Material *ma, struct bNodeTree *ntree, const uint64_t shader_id, const bool is_volume_shader, bool deferred, GPUCodegenCallbackFn callback, void *thunk)
smooth(Type::VEC4, "color_mul") .smooth(Type gpFillTexture gpSceneDepthTexture materials[GPENCIL_MATERIAL_BUFFER_LEN]
Definition: gpencil_info.hh:29
ccl_global KernelShaderEvalInput * input
static void material_type_from_shader_uuid(uint64_t shader_uuid, eMaterialPipeline &pipeline_type, eMaterialGeometry &geometry_type)
static uint64_t shader_uuid_from_material_type(eMaterialPipeline pipeline_type, eMaterialGeometry geometry_type)
@ MAT_PIPE_DEFERRED_PREPASS_VELOCITY
@ MAT_PIPE_FORWARD_PREPASS_VELOCITY
static void codegen_callback(void *thunk, GPUMaterial *mat, GPUCodegenOutput *codegen)
unsigned __int64 uint64_t
Definition: stdint.h:90
char * material_functions
Definition: GPU_material.h:132
GPUShaderCreateInfo * create_info
Definition: GPU_material.h:134
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...
Vector< StageInterfaceInfo * > vertex_out_interfaces_
Self & sampler(int slot, ImageType type, StringRefNull name, Frequency freq=Frequency::PASS, eGPUSamplerState sampler=(eGPUSamplerState) -1)
Self & additional_info(StringRefNull info_name0, StringRefNull info_name1="", StringRefNull info_name2="", StringRefNull info_name3="", StringRefNull info_name4="", StringRefNull info_name5="", StringRefNull info_name6="")
Self & define(StringRefNull name, StringRefNull value="")