1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2006 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup gpu
22  *
23  * Manages materials, lights and textures.
24  */
25 
26 #include <math.h>
27 #include <string.h>
28 
29 #include "MEM_guardedalloc.h"
30 
31 #include "DNA_material_types.h"
32 #include "DNA_scene_types.h"
33 #include "DNA_world_types.h"
34 
35 #include "BLI_ghash.h"
36 #include "BLI_listbase.h"
37 #include "BLI_math.h"
38 #include "BLI_string.h"
39 #include "BLI_string_utils.h"
40 #include "BLI_utildefines.h"
41 
42 #include "BKE_main.h"
43 #include "BKE_material.h"
44 #include "BKE_node.h"
45 #include "BKE_scene.h"
46 
47 #include "GPU_material.h"
48 #include "GPU_shader.h"
49 #include "GPU_texture.h"
50 #include "GPU_uniform_buffer.h"
51 
52 #include "DRW_engine.h"
53 
54 #include "gpu_codegen.h"
55 #include "gpu_node_graph.h"
56 
57 /* Structs */
58 #define MAX_COLOR_BAND 128
59 
60 typedef struct GPUColorBandBuilder {
61   float pixels[MAX_COLOR_BAND][CM_TABLE + 1][4];
62   int current_layer;
63 } GPUColorBandBuilder;
64 
65 struct GPUMaterial {
66   Scene *scene; /* DEPRECATED was only useful for lights. */
67   Material *ma;
68 
69   eGPUMaterialStatus status;
70 
71   const void *engine_type; /* attached engine type */
72   int options;             /* to identify shader variations (shadow, probe, world background...) */
73   bool is_volume_shader;   /* is volumetric shader */
74 
75   /* Nodes */
76   GPUNodeGraph graph;
77 
78   /* for binding the material */
79   GPUPass *pass;
80 
81   /* XXX: Should be in Material. But it depends on the output node
82    * used and since the output selection is different for GPUMaterial...
83    */
84   bool has_volume_output;
85   bool has_surface_output;
86 
87   /* Only used by Eevee to know which bsdf are used. */
88   eGPUMatFlag flag;
89 
90   /* Used by 2.8 pipeline */
91   GPUUniformBuf *ubo; /* UBOs for shader uniforms. */
92 
93   /* Eevee SSS */
94   GPUUniformBuf *sss_profile;  /* UBO containing SSS profile. */
95   GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
96   float sss_enabled;
97   float sss_radii[3];
98   int sss_samples;
99   short int sss_falloff;
100   float sss_sharpness;
101   bool sss_dirty;
102 
103   GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */
104   GPUColorBandBuilder *coba_builder;
105 
106   GSet *used_libraries;
107 
108 #ifndef NDEBUG
109   char name[64];
110 #endif
111 };
112 
113 enum {
114   GPU_USE_SURFACE_OUTPUT = (1 << 0),
115   GPU_USE_VOLUME_OUTPUT = (1 << 1),
116 };
117 
118 /* Functions */
119 
120 /* Returns the address of the future pointer to coba_tex */
gpu_material_ramp_texture_row_set(GPUMaterial * mat,int size,float * pixels,float * row)121 GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat,
122                                                int size,
123                                                float *pixels,
124                                                float *row)
125 {
126   /* In order to put all the color-bands into one 1D array texture,
127    * we need them to be the same size. */
128   BLI_assert(size == CM_TABLE + 1);
129   UNUSED_VARS_NDEBUG(size);
130 
131   if (mat->coba_builder == NULL) {
132     mat->coba_builder = MEM_mallocN(sizeof(GPUColorBandBuilder), "GPUColorBandBuilder");
133     mat->coba_builder->current_layer = 0;
134   }
135 
136   int layer = mat->coba_builder->current_layer;
137   *row = (float)layer;
138 
139   if (*row == MAX_COLOR_BAND) {
140     printf("Too many color band in shader! Remove some Curve, Black Body or Color Ramp Node.\n");
141   }
142   else {
143     float *dst = (float *)mat->coba_builder->pixels[layer];
144     memcpy(dst, pixels, sizeof(float) * (CM_TABLE + 1) * 4);
145     mat->coba_builder->current_layer += 1;
146   }
147 
148   return &mat->coba_tex;
149 }
150 
gpu_material_ramp_texture_build(GPUMaterial * mat)151 static void gpu_material_ramp_texture_build(GPUMaterial *mat)
152 {
153   if (mat->coba_builder == NULL) {
154     return;
155   }
156 
157   GPUColorBandBuilder *builder = mat->coba_builder;
158 
159   mat->coba_tex = GPU_texture_create_1d_array(
160       "mat_ramp", CM_TABLE + 1, builder->current_layer, 1, GPU_RGBA16F, (float *)builder->pixels);
161 
162   MEM_freeN(builder);
163   mat->coba_builder = NULL;
164 }
165 
gpu_material_free_single(GPUMaterial * material)166 static void gpu_material_free_single(GPUMaterial *material)
167 {
168   /* Cancel / wait any pending lazy compilation. */
169   DRW_deferred_shader_remove(material);
170 
171   gpu_node_graph_free(&material->graph);
172 
173   if (material->pass != NULL) {
174     GPU_pass_release(material->pass);
175   }
176   if (material->ubo != NULL) {
177     GPU_uniformbuf_free(material->ubo);
178   }
179   if (material->sss_tex_profile != NULL) {
180     GPU_texture_free(material->sss_tex_profile);
181   }
182   if (material->sss_profile != NULL) {
183     GPU_uniformbuf_free(material->sss_profile);
184   }
185   if (material->coba_tex != NULL) {
186     GPU_texture_free(material->coba_tex);
187   }
188 
189   BLI_gset_free(material->used_libraries, NULL);
190 }
191 
GPU_material_free(ListBase * gpumaterial)192 void GPU_material_free(ListBase *gpumaterial)
193 {
194   LISTBASE_FOREACH (LinkData *, link, gpumaterial) {
195     GPUMaterial *material = link->data;
196     gpu_material_free_single(material);
197     MEM_freeN(material);
198   }
199   BLI_freelistN(gpumaterial);
200 }
201 
GPU_material_scene(GPUMaterial * material)202 Scene *GPU_material_scene(GPUMaterial *material)
203 {
204   return material->scene;
205 }
206 
GPU_material_get_pass(GPUMaterial * material)207 GPUPass *GPU_material_get_pass(GPUMaterial *material)
208 {
209   return material->pass;
210 }
211 
GPU_material_get_shader(GPUMaterial * material)212 GPUShader *GPU_material_get_shader(GPUMaterial *material)
213 {
214   return material->pass ? GPU_pass_shader_get(material->pass) : NULL;
215 }
216 
217 /* Return can be NULL if it's a world material. */
GPU_material_get_material(GPUMaterial * material)218 Material *GPU_material_get_material(GPUMaterial *material)
219 {
220   return material->ma;
221 }
222 
GPU_material_uniform_buffer_get(GPUMaterial * material)223 GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material)
224 {
225   return material->ubo;
226 }
227 
228 /**
229  * Create dynamic UBO from parameters
230  *
231  * \param inputs: Items are #LinkData, data is #GPUInput (`BLI_genericNodeN(GPUInput)`).
232  */
GPU_material_uniform_buffer_create(GPUMaterial * material,ListBase * inputs)233 void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
234 {
235 #ifndef NDEBUG
236   const char *name = material->name;
237 #else
238   const char *name = "Material";
239 #endif
240   material->ubo = GPU_uniformbuf_create_from_list(inputs, name);
241 }
242 
243 /* Eevee Subsurface scattering. */
244 /* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
245 
246 #define SSS_SAMPLES 65
247 #define SSS_EXPONENT 2.0f /* Importance sampling exponent */
248 
249 typedef struct GPUSssKernelData {
250   float kernel[SSS_SAMPLES][4];
251   float param[3], max_radius;
252   int samples;
253   int pad[3];
254 } GPUSssKernelData;
255 
256 BLI_STATIC_ASSERT_ALIGN(GPUSssKernelData, 16)
257 
sss_calculate_offsets(GPUSssKernelData * kd,int count,float exponent)258 static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponent)
259 {
260   float step = 2.0f / (float)(count - 1);
261   for (int i = 0; i < count; i++) {
262     float o = ((float)i) * step - 1.0f;
263     float sign = (o < 0.0f) ? -1.0f : 1.0f;
264     float ofs = sign * fabsf(powf(o, exponent));
265     kd->kernel[i][3] = ofs;
266   }
267 }
268 
269 #define GAUSS_TRUNCATE 12.46f
gaussian_profile(float r,float radius)270 static float gaussian_profile(float r, float radius)
271 {
272   const float v = radius * radius * (0.25f * 0.25f);
273   const float Rm = sqrtf(v * GAUSS_TRUNCATE);
274 
275   if (r >= Rm) {
276     return 0.0f;
277   }
278   return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v);
279 }
280 
281 #define BURLEY_TRUNCATE 16.0f
282 #define BURLEY_TRUNCATE_CDF 0.9963790093708328f  // cdf(BURLEY_TRUNCATE)
burley_profile(float r,float d)283 static float burley_profile(float r, float d)
284 {
285   float exp_r_3_d = expf(-r / (3.0f * d));
286   float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
287   return (exp_r_d + exp_r_3_d) / (4.0f * d);
288 }
289 
cubic_profile(float r,float radius,float sharpness)290 static float cubic_profile(float r, float radius, float sharpness)
291 {
292   float Rm = radius * (1.0f + sharpness);
293 
294   if (r >= Rm) {
295     return 0.0f;
296   }
297   /* custom variation with extra sharpness, to match the previous code */
298   const float y = 1.0f / (1.0f + sharpness);
299   float Rmy, ry, ryinv;
300 
301   Rmy = powf(Rm, y);
302   ry = powf(r, y);
303   ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f;
304 
305   const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy;
306   const float f = Rmy - ry;
307   const float num = f * (f * f) * (y * ryinv);
308 
309   return (10.0f * num) / (Rmy5 * M_PI);
310 }
311 
eval_profile(float r,short falloff_type,float sharpness,float param)312 static float eval_profile(float r, short falloff_type, float sharpness, float param)
313 {
314   r = fabsf(r);
315 
316   if (falloff_type == SHD_SUBSURFACE_BURLEY || falloff_type == SHD_SUBSURFACE_RANDOM_WALK) {
317     return burley_profile(r, param) / BURLEY_TRUNCATE_CDF;
318   }
319   if (falloff_type == SHD_SUBSURFACE_CUBIC) {
320     return cubic_profile(r, param, sharpness);
321   }
322 
323   return gaussian_profile(r, param);
324 }
325 
326 /* Resolution for each sample of the precomputed kernel profile */
327 #define INTEGRAL_RESOLUTION 32
eval_integral(float x0,float x1,short falloff_type,float sharpness,float param)328 static float eval_integral(float x0, float x1, short falloff_type, float sharpness, float param)
329 {
330   const float range = x1 - x0;
331   const float step = range / INTEGRAL_RESOLUTION;
332   float integral = 0.0f;
333 
334   for (int i = 0; i < INTEGRAL_RESOLUTION; i++) {
335     float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION;
336     float y = eval_profile(x, falloff_type, sharpness, param);
337     integral += y * step;
338   }
339 
340   return integral;
341 }
342 #undef INTEGRAL_RESOLUTION
343 
compute_sss_kernel(GPUSssKernelData * kd,const float radii[3],int sample_len,int falloff_type,float sharpness)344 static void compute_sss_kernel(
345     GPUSssKernelData *kd, const float radii[3], int sample_len, int falloff_type, float sharpness)
346 {
347   float rad[3];
348   /* Minimum radius */
349   rad[0] = MAX2(radii[0], 1e-15f);
350   rad[1] = MAX2(radii[1], 1e-15f);
351   rad[2] = MAX2(radii[2], 1e-15f);
352 
353   /* Christensen-Burley fitting */
354   float l[3], d[3];
355 
356   if (falloff_type == SHD_SUBSURFACE_BURLEY || falloff_type == SHD_SUBSURFACE_RANDOM_WALK) {
357     mul_v3_v3fl(l, rad, 0.25f * M_1_PI);
358     const float A = 1.0f;
359     const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f);
360     /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */
361     mul_v3_v3fl(d, l, 0.6f / s);
362     mul_v3_v3fl(rad, d, BURLEY_TRUNCATE);
363     kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
364 
365     copy_v3_v3(kd->param, d);
366   }
367   else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
368     copy_v3_v3(kd->param, rad);
369     mul_v3_fl(rad, 1.0f + sharpness);
370     kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
371   }
372   else {
373     kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
374 
375     copy_v3_v3(kd->param, rad);
376   }
377 
378   /* Compute samples locations on the 1d kernel [-1..1] */
379   sss_calculate_offsets(kd, sample_len, SSS_EXPONENT);
380 
381   /* Weights sum for normalization */
382   float sum[3] = {0.0f, 0.0f, 0.0f};
383 
384   /* Compute integral of each sample footprint */
385   for (int i = 0; i < sample_len; i++) {
386     float x0, x1;
387 
388     if (i == 0) {
389       x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f;
390     }
391     else {
392       x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f;
393     }
394 
395     if (i == sample_len - 1) {
396       x1 = kd->kernel[sample_len - 1][3] +
397            fabsf(kd->kernel[sample_len - 2][3] - kd->kernel[sample_len - 1][3]) / 2.0f;
398     }
399     else {
400       x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f;
401     }
402 
403     x0 *= kd->max_radius;
404     x1 *= kd->max_radius;
405 
406     kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]);
407     kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]);
408     kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]);
409 
410     sum[0] += kd->kernel[i][0];
411     sum[1] += kd->kernel[i][1];
412     sum[2] += kd->kernel[i][2];
413   }
414 
415   for (int i = 0; i < 3; i++) {
416     if (sum[i] > 0.0f) {
417       /* Normalize */
418       for (int j = 0; j < sample_len; j++) {
419         kd->kernel[j][i] /= sum[i];
420       }
421     }
422     else {
423       /* Avoid 0 kernel sum. */
424       kd->kernel[sample_len / 2][i] = 1.0f;
425     }
426   }
427 
428   /* Put center sample at the start of the array (to sample first) */
429   float tmpv[4];
430   copy_v4_v4(tmpv, kd->kernel[sample_len / 2]);
431   for (int i = sample_len / 2; i > 0; i--) {
432     copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]);
433   }
434   copy_v4_v4(kd->kernel[0], tmpv);
435 
436   kd->samples = sample_len;
437 }
438 
439 #define INTEGRAL_RESOLUTION 512
compute_sss_translucence_kernel(const GPUSssKernelData * kd,int resolution,short falloff_type,float sharpness,float ** output)440 static void compute_sss_translucence_kernel(const GPUSssKernelData *kd,
441                                             int resolution,
442                                             short falloff_type,
443                                             float sharpness,
444                                             float **output)
445 {
446   float(*texels)[4];
447   texels = MEM_callocN(sizeof(float[4]) * resolution, "compute_sss_translucence_kernel");
448   *output = (float *)texels;
449 
450   /* Last texel should be black, hence the - 1. */
451   for (int i = 0; i < resolution - 1; i++) {
452     /* Distance from surface. */
453     float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution);
454 
455     /* For each distance d we compute the radiance incoming from an hypothetic parallel plane. */
456     /* Compute radius of the footprint on the hypothetic plane */
457     float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d);
458     float r_step = r_fp / INTEGRAL_RESOLUTION;
459     float area_accum = 0.0f;
460     for (float r = 0.0f; r < r_fp; r += r_step) {
461       /* Compute distance to the "shading" point through the medium. */
462       /* r_step * 0.5f to put sample between the area borders */
463       float dist = hypotf(r + r_step * 0.5f, d);
464 
465       float profile[3];
466       profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]);
467       profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]);
468       profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]);
469 
470       /* Since the profile and configuration are radially symmetrical we
471        * can just evaluate it once and weight it accordingly */
472       float r_next = r + r_step;
473       float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r);
474 
475       mul_v3_fl(profile, disk_area);
476       add_v3_v3(texels[i], profile);
477       area_accum += disk_area;
478     }
479     /* Normalize over the disk. */
480     mul_v3_fl(texels[i], 1.0f / (area_accum));
481   }
482 
483   /* Normalize */
484   for (int j = resolution - 2; j > 0; j--) {
485     texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f;
486     texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f;
487     texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f;
488   }
489 
490   /* First texel should be white */
491   texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f;
492   texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f;
493   texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f;
494 
495   /* dim the last few texels for smoother transition */
496   mul_v3_fl(texels[resolution - 2], 0.25f);
497   mul_v3_fl(texels[resolution - 3], 0.5f);
498   mul_v3_fl(texels[resolution - 4], 0.75f);
499 }
500 #undef INTEGRAL_RESOLUTION
501 
GPU_material_sss_profile_create(GPUMaterial * material,float radii[3],const short * falloff_type,const float * sharpness)502 void GPU_material_sss_profile_create(GPUMaterial *material,
503                                      float radii[3],
504                                      const short *falloff_type,
505                                      const float *sharpness)
506 {
507   copy_v3_v3(material->sss_radii, radii);
508   material->sss_falloff = (falloff_type) ? *falloff_type : 0.0;
509   material->sss_sharpness = (sharpness) ? *sharpness : 0.0;
510   material->sss_dirty = true;
511   material->sss_enabled = true;
512 
513   /* Update / Create UBO */
514   if (material->sss_profile == NULL) {
515     material->sss_profile = GPU_uniformbuf_create(sizeof(GPUSssKernelData));
516   }
517 }
518 
GPU_material_sss_profile_get(GPUMaterial * material,int sample_len,GPUTexture ** tex_profile)519 struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material,
520                                                    int sample_len,
521                                                    GPUTexture **tex_profile)
522 {
523   if (!material->sss_enabled) {
524     return NULL;
525   }
526 
527   if (material->sss_dirty || (material->sss_samples != sample_len)) {
528     GPUSssKernelData kd;
529 
530     float sharpness = material->sss_sharpness;
531 
532     /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */
533     sharpness *= 0.5f;
534 
535     compute_sss_kernel(&kd, material->sss_radii, sample_len, material->sss_falloff, sharpness);
536 
537     /* Update / Create UBO */
538     GPU_uniformbuf_update(material->sss_profile, &kd);
539 
540     /* Update / Create Tex */
541     float *translucence_profile;
542     compute_sss_translucence_kernel(
543         &kd, 64, material->sss_falloff, sharpness, &translucence_profile);
544 
545     if (material->sss_tex_profile != NULL) {
546       GPU_texture_free(material->sss_tex_profile);
547     }
548 
549     material->sss_tex_profile = GPU_texture_create_1d(
550         "sss_tex_profile", 64, 1, GPU_RGBA16F, translucence_profile);
551 
552     MEM_freeN(translucence_profile);
553 
554     material->sss_samples = sample_len;
555     material->sss_dirty = false;
556   }
557 
558   if (tex_profile != NULL) {
559     *tex_profile = material->sss_tex_profile;
560   }
561   return material->sss_profile;
562 }
563 
GPU_material_create_sss_profile_ubo(void)564 struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void)
565 {
566   return GPU_uniformbuf_create(sizeof(GPUSssKernelData));
567 }
568 
569 #undef SSS_EXPONENT
570 #undef SSS_SAMPLES
571 
GPU_material_attributes(GPUMaterial * material)572 ListBase GPU_material_attributes(GPUMaterial *material)
573 {
574   return material->graph.attributes;
575 }
576 
GPU_material_textures(GPUMaterial * material)577 ListBase GPU_material_textures(GPUMaterial *material)
578 {
579   return material->graph.textures;
580 }
581 
GPU_material_volume_grids(GPUMaterial * material)582 ListBase GPU_material_volume_grids(GPUMaterial *material)
583 {
584   return material->graph.volume_grids;
585 }
586 
GPU_material_output_link(GPUMaterial * material,GPUNodeLink * link)587 void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
588 {
589   if (!material->graph.outlink) {
590     material->graph.outlink = link;
591   }
592 }
593 
gpu_material_node_graph(GPUMaterial * material)594 GPUNodeGraph *gpu_material_node_graph(GPUMaterial *material)
595 {
596   return &material->graph;
597 }
598 
gpu_material_used_libraries(GPUMaterial * material)599 GSet *gpu_material_used_libraries(GPUMaterial *material)
600 {
601   return material->used_libraries;
602 }
603 
604 /* Return true if the material compilation has not yet begin or begin. */
GPU_material_status(GPUMaterial * mat)605 eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
606 {
607   return mat->status;
608 }
609 
610 /* Code generation */
611 
GPU_material_has_surface_output(GPUMaterial * mat)612 bool GPU_material_has_surface_output(GPUMaterial *mat)
613 {
614   return mat->has_surface_output;
615 }
616 
GPU_material_has_volume_output(GPUMaterial * mat)617 bool GPU_material_has_volume_output(GPUMaterial *mat)
618 {
619   return mat->has_volume_output;
620 }
621 
GPU_material_is_volume_shader(GPUMaterial * mat)622 bool GPU_material_is_volume_shader(GPUMaterial *mat)
623 {
624   return mat->is_volume_shader;
625 }
626 
GPU_material_flag_set(GPUMaterial * mat,eGPUMatFlag flag)627 void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag)
628 {
629   mat->flag |= flag;
630 }
631 
GPU_material_flag_get(GPUMaterial * mat,eGPUMatFlag flag)632 bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag)
633 {
634   return (mat->flag & flag) != 0;
635 }
636 
GPU_material_from_nodetree_find(ListBase * gpumaterials,const void * engine_type,int options)637 GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials,
638                                              const void *engine_type,
639                                              int options)
640 {
641   LISTBASE_FOREACH (LinkData *, link, gpumaterials) {
642     GPUMaterial *current_material = (GPUMaterial *)link->data;
643     if (current_material->engine_type == engine_type && current_material->options == options) {
644       return current_material;
645     }
646   }
647 
648   return NULL;
649 }
650 
651 /**
652  * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
653  * This is enforced since constructing other arguments to this function may be expensive
654  * so only do this when they are needed.
655  */
GPU_material_from_nodetree(Scene * scene,struct Material * ma,struct bNodeTree * ntree,ListBase * gpumaterials,const void * engine_type,const int options,const bool is_volume_shader,const char * vert_code,const char * geom_code,const char * frag_lib,const char * defines,const char * name,GPUMaterialEvalCallbackFn callback)656 GPUMaterial *GPU_material_from_nodetree(Scene *scene,
657                                         struct Material *ma,
658                                         struct bNodeTree *ntree,
659                                         ListBase *gpumaterials,
660                                         const void *engine_type,
661                                         const int options,
662                                         const bool is_volume_shader,
663                                         const char *vert_code,
664                                         const char *geom_code,
665                                         const char *frag_lib,
666                                         const char *defines,
667                                         const char *name,
668                                         GPUMaterialEvalCallbackFn callback)
669 {
670   LinkData *link;
671   bool has_volume_output, has_surface_output;
672 
673   /* Caller must re-use materials. */
674   BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
675 
676   /* HACK: Eevee assume this to create Ghash keys. */
677   BLI_assert(sizeof(GPUPass) > 16);
678 
679   /* allocate material */
680   GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
681   mat->ma = ma;
682   mat->scene = scene;
683   mat->engine_type = engine_type;
684   mat->options = options;
685   mat->is_volume_shader = is_volume_shader;
686 #ifndef NDEBUG
687   BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
688 #else
689   UNUSED_VARS(name);
690 #endif
691 
692   mat->used_libraries = BLI_gset_new(
693       BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUMaterial.used_libraries");
694 
695   /* localize tree to create links for reroute and mute */
696   bNodeTree *localtree = ntreeLocalize(ntree);
697   ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output);
698 
699   gpu_material_ramp_texture_build(mat);
700 
701   mat->has_surface_output = has_surface_output;
702   mat->has_volume_output = has_volume_output;
703 
704   if (mat->graph.outlink) {
705     if (callback) {
706       callback(mat, options, &vert_code, &geom_code, &frag_lib, &defines);
707     }
708     /* HACK: this is only for eevee. We add the define here after the nodetree evaluation. */
709     if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) {
710       defines = BLI_string_joinN(defines,
711                                  "#ifndef USE_ALPHA_BLEND\n"
712                                  "#  define USE_SSS\n"
713                                  "#endif\n");
714     }
715     /* Create source code and search pass cache for an already compiled version. */
716     mat->pass = GPU_generate_pass(mat, &mat->graph, vert_code, geom_code, frag_lib, defines);
717 
718     if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) {
719       MEM_freeN((char *)defines);
720     }
721 
722     if (mat->pass == NULL) {
723       /* We had a cache hit and the shader has already failed to compile. */
724       mat->status = GPU_MAT_FAILED;
725       gpu_node_graph_free(&mat->graph);
726     }
727     else {
728       GPUShader *sh = GPU_pass_shader_get(mat->pass);
729       if (sh != NULL) {
730         /* We had a cache hit and the shader is already compiled. */
731         mat->status = GPU_MAT_SUCCESS;
732         gpu_node_graph_free_nodes(&mat->graph);
733       }
734       else {
735         mat->status = GPU_MAT_QUEUED;
736       }
737     }
738   }
739   else {
740     mat->status = GPU_MAT_FAILED;
741     gpu_node_graph_free(&mat->graph);
742   }
743 
744   /* Only free after GPU_pass_shader_get where GPUUniformBuf
745    * read data from the local tree. */
746   ntreeFreeLocalTree(localtree);
747   MEM_freeN(localtree);
748 
749   /* note that even if building the shader fails in some way, we still keep
750    * it to avoid trying to compile again and again, and simply do not use
751    * the actual shader on drawing */
752 
753   link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
754   link->data = mat;
755   BLI_addtail(gpumaterials, link);
756 
757   return mat;
758 }
759 
GPU_material_compile(GPUMaterial * mat)760 void GPU_material_compile(GPUMaterial *mat)
761 {
762   bool success;
763 
764   BLI_assert(mat->status == GPU_MAT_QUEUED);
765   BLI_assert(mat->pass);
766 
767   /* NOTE: The shader may have already been compiled here since we are
768    * sharing GPUShader across GPUMaterials. In this case it's a no-op. */
769 #ifndef NDEBUG
770   success = GPU_pass_compile(mat->pass, mat->name);
771 #else
772   success = GPU_pass_compile(mat->pass, __func__);
773 #endif
774 
775   if (success) {
776     GPUShader *sh = GPU_pass_shader_get(mat->pass);
777     if (sh != NULL) {
778       mat->status = GPU_MAT_SUCCESS;
779       gpu_node_graph_free_nodes(&mat->graph);
780     }
781   }
782   else {
783     mat->status = GPU_MAT_FAILED;
784     GPU_pass_release(mat->pass);
785     mat->pass = NULL;
786     gpu_node_graph_free(&mat->graph);
787   }
788 }
789 
GPU_materials_free(Main * bmain)790 void GPU_materials_free(Main *bmain)
791 {
792   Material *ma;
793   World *wo;
794 
795   for (ma = bmain->materials.first; ma; ma = ma->id.next) {
796     GPU_material_free(&ma->gpumaterial);
797   }
798 
799   for (wo = bmain->worlds.first; wo; wo = wo->id.next) {
800     GPU_material_free(&wo->gpumaterial);
801   }
802 
803   BKE_material_defaults_free_gpu();
804 }
805