96c321f9107fafff54c886a47f0ff9ccf21c58e8
[blender.git] / source / blender / gpu / intern / gpu_material.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2006 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Brecht Van Lommel.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/gpu/intern/gpu_material.c
29  *  \ingroup gpu
30  *
31  * Manages materials, lights and textures.
32  */
33
34 #include <math.h>
35 #include <string.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_lamp_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_world_types.h"
44
45 #include "BLI_math.h"
46 #include "BLI_blenlib.h"
47 #include "BLI_utildefines.h"
48 #include "BLI_rand.h"
49
50 #include "BKE_anim.h"
51 #include "BKE_colorband.h"
52 #include "BKE_colortools.h"
53 #include "BKE_global.h"
54 #include "BKE_image.h"
55 #include "BKE_layer.h"
56 #include "BKE_main.h"
57 #include "BKE_node.h"
58 #include "BKE_scene.h"
59
60 #include "IMB_imbuf_types.h"
61
62 #include "GPU_extensions.h"
63 #include "GPU_framebuffer.h"
64 #include "GPU_material.h"
65 #include "GPU_shader.h"
66 #include "GPU_texture.h"
67 #include "GPU_uniformbuffer.h"
68
69 #include "DRW_engine.h"
70
71 #include "gpu_codegen.h"
72
73 #ifdef WITH_OPENSUBDIV
74 #  include "BKE_DerivedMesh.h"
75 #endif
76
77 /* Structs */
78
79 struct GPUMaterial {
80         Scene *scene; /* DEPRECATED was only usefull for lamps */
81         Material *ma;
82
83         /* material for mesh surface, worlds or something else.
84          * some code generation is done differently depending on the use case */
85         int type; /* DEPRECATED */
86         GPUMaterialStatus status;
87
88         const void *engine_type;   /* attached engine type */
89         int options;    /* to identify shader variations (shadow, probe, world background...) */
90
91         /* for creating the material */
92         ListBase nodes;
93         GPUNodeLink *outlink;
94
95         /* for binding the material */
96         GPUPass *pass;
97         ListBase inputs;  /* GPUInput */
98         GPUVertexAttribs attribs;
99         int builtins;
100         int alpha, obcolalpha;
101         int dynproperty;
102
103         /* for passing uniforms */
104         int viewmatloc, invviewmatloc;
105         int obmatloc, invobmatloc;
106         int localtoviewmatloc, invlocaltoviewmatloc;
107         int obcolloc, obautobumpscaleloc;
108         int cameratexcofacloc;
109
110         int partscalarpropsloc;
111         int partcoloc;
112         int partvel;
113         int partangvel;
114
115         int objectinfoloc;
116
117         bool is_opensubdiv;
118
119         /* XXX: Should be in Material. But it depends on the output node
120          * used and since the output selection is difference for GPUMaterial...
121          */
122         int domain;
123
124         /* Used by 2.8 pipeline */
125         GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */
126
127         /* Eevee SSS */
128         GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */
129         GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
130         float *sss_radii; /* UBO containing SSS profile. */
131         int sss_samples;
132         short int *sss_falloff;
133         float *sss_sharpness;
134         bool sss_dirty;
135 };
136
137 enum {
138         GPU_DOMAIN_SURFACE    = (1 << 0),
139         GPU_DOMAIN_VOLUME     = (1 << 1),
140         GPU_DOMAIN_SSS        = (1 << 2)
141 };
142
143 /* Functions */
144
145 void GPU_material_free(ListBase *gpumaterial)
146 {
147         for (LinkData *link = gpumaterial->first; link; link = link->next) {
148                 GPUMaterial *material = link->data;
149
150                 /* Cancel / wait any pending lazy compilation. */
151                 DRW_deferred_shader_remove(material);
152
153                 GPU_pass_free_nodes(&material->nodes);
154                 GPU_inputs_free(&material->inputs);
155
156                 if (material->pass)
157                         GPU_pass_release(material->pass);
158
159                 if (material->ubo != NULL) {
160                         GPU_uniformbuffer_free(material->ubo);
161                 }
162
163                 if (material->sss_tex_profile != NULL) {
164                         GPU_texture_free(material->sss_tex_profile);
165                 }
166
167                 if (material->sss_profile != NULL) {
168                         GPU_uniformbuffer_free(material->sss_profile);
169                 }
170
171                 MEM_freeN(material);
172         }
173
174         BLI_freelistN(gpumaterial);
175 }
176
177 GPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
178 {
179         return material->builtins;
180 }
181
182 Scene *GPU_material_scene(GPUMaterial *material)
183 {
184         return material->scene;
185 }
186
187 GPUMatType GPU_Material_get_type(GPUMaterial *material)
188 {
189         return material->type;
190 }
191
192 GPUPass *GPU_material_get_pass(GPUMaterial *material)
193 {
194         return material->pass;
195 }
196
197 ListBase *GPU_material_get_inputs(GPUMaterial *material)
198 {
199         return &material->inputs;
200 }
201
202 GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material)
203 {
204         return material->ubo;
205 }
206
207 /**
208  * Create dynamic UBO from parameters
209  * \param ListBase of BLI_genericNodeN(GPUInput)
210  */
211 void GPU_material_create_uniform_buffer(GPUMaterial *material, ListBase *inputs)
212 {
213         material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL);
214 }
215
216 void GPU_material_uniform_buffer_tag_dirty(ListBase *gpumaterials)
217 {
218         for (LinkData *link = gpumaterials->first; link; link = link->next) {
219                 GPUMaterial *material = link->data;
220                 if (material->ubo != NULL) {
221                         GPU_uniformbuffer_tag_dirty(material->ubo);
222                 }
223                 if (material->sss_profile != NULL) {
224                         material->sss_dirty = true;
225                 }
226         }
227 }
228
229 /* Eevee Subsurface scattering. */
230 /* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
231
232 #define SSS_SAMPLES 65
233 #define SSS_EXPONENT 2.0f /* Importance sampling exponent */
234
235 typedef struct GPUSssKernelData {
236         float kernel[SSS_SAMPLES][4];
237         float param[3], max_radius;
238         int samples;
239 } GPUSssKernelData;
240
241 static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponent)
242 {
243         float step = 2.0f / (float)(count - 1);
244         for (int i = 0; i < count; i++) {
245                 float o = ((float)i) * step - 1.0f;
246                 float sign = (o < 0.0f) ? -1.0f : 1.0f;
247                 float ofs = sign * fabsf(powf(o, exponent));
248                 kd->kernel[i][3] = ofs;
249         }
250 }
251
252 #define GAUSS_TRUNCATE 12.46f
253 static float gaussian_profile(float r, float radius)
254 {
255         const float v = radius * radius * (0.25f * 0.25f);
256         const float Rm = sqrtf(v * GAUSS_TRUNCATE);
257
258         if (r >= Rm) {
259                 return 0.0f;
260         }
261         return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v);
262 }
263
264 #define BURLEY_TRUNCATE     16.0f
265 #define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
266 static float burley_profile(float r, float d)
267 {
268         float exp_r_3_d = expf(-r / (3.0f * d));
269         float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
270         return (exp_r_d + exp_r_3_d) / (4.0f * d);
271 }
272
273 static float cubic_profile(float r, float radius, float sharpness)
274 {
275         float Rm = radius * (1.0f + sharpness);
276
277         if (r >= Rm) {
278                 return 0.0f;
279         }
280         /* custom variation with extra sharpness, to match the previous code */
281         const float y = 1.0f / (1.0f + sharpness);
282         float Rmy, ry, ryinv;
283
284         Rmy = powf(Rm, y);
285         ry = powf(r, y);
286         ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f;
287
288         const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy;
289         const float f = Rmy - ry;
290         const float num = f * (f * f) * (y * ryinv);
291
292         return (10.0f * num) / (Rmy5 * M_PI);
293 }
294
295 static float eval_profile(float r, short falloff_type, float sharpness, float param)
296 {
297         r = fabsf(r);
298
299         if (falloff_type == SHD_SUBSURFACE_BURLEY ||
300             falloff_type == SHD_SUBSURFACE_RANDOM_WALK)
301         {
302                 return burley_profile(r, param) / BURLEY_TRUNCATE_CDF;
303         }
304         else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
305                 return cubic_profile(r, param, sharpness);
306         }
307         else {
308                 return gaussian_profile(r, param);
309         }
310 }
311
312 /* Resolution for each sample of the precomputed kernel profile */
313 #define INTEGRAL_RESOLUTION 32
314 static float eval_integral(float x0, float x1, short falloff_type, float sharpness, float param)
315 {
316         const float range = x1 - x0;
317         const float step = range / INTEGRAL_RESOLUTION;
318         float integral = 0.0f;
319
320         for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) {
321                 float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION;
322                 float y = eval_profile(x, falloff_type, sharpness, param);
323                 integral += y * step;
324         }
325
326         return integral;
327 }
328 #undef INTEGRAL_RESOLUTION
329
330 static void compute_sss_kernel(
331         GPUSssKernelData *kd, float *radii, int sample_ct, int falloff_type, float sharpness)
332 {
333         float rad[3];
334         /* Minimum radius */
335         rad[0] = MAX2(radii[0], 1e-15f);
336         rad[1] = MAX2(radii[1], 1e-15f);
337         rad[2] = MAX2(radii[2], 1e-15f);
338
339         /* Christensen-Burley fitting */
340         float l[3], d[3];
341
342         if (falloff_type == SHD_SUBSURFACE_BURLEY ||
343             falloff_type == SHD_SUBSURFACE_RANDOM_WALK)
344         {
345                 mul_v3_v3fl(l, rad, 0.25f * M_1_PI);
346                 const float A = 1.0f;
347                 const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f);
348                 /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */
349                 mul_v3_v3fl(d, l, 0.6f / s);
350                 mul_v3_v3fl(rad, d, BURLEY_TRUNCATE);
351                 kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
352
353                 copy_v3_v3(kd->param, d);
354         }
355         else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
356                 copy_v3_v3(kd->param, rad);
357                 mul_v3_fl(rad, 1.0f + sharpness);
358                 kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
359         }
360         else {
361                 kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
362
363                 copy_v3_v3(kd->param, rad);
364         }
365
366         /* Compute samples locations on the 1d kernel [-1..1] */
367         sss_calculate_offsets(kd, sample_ct, SSS_EXPONENT);
368
369         /* Weights sum for normalization */
370         float sum[3] = {0.0f, 0.0f, 0.0f};
371
372         /* Compute integral of each sample footprint */
373         for (int i = 0; i < sample_ct; i++) {
374                 float x0, x1;
375
376                 if (i == 0) {
377                         x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f;
378                 }
379                 else {
380                         x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f;
381                 }
382
383                 if (i == sample_ct - 1) {
384                         x1 = kd->kernel[sample_ct - 1][3] + fabsf(kd->kernel[sample_ct - 2][3] - kd->kernel[sample_ct - 1][3]) / 2.0f;
385                 }
386                 else {
387                         x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f;
388                 }
389
390                 x0 *= kd->max_radius;
391                 x1 *= kd->max_radius;
392
393                 kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]);
394                 kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]);
395                 kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]);
396
397                 sum[0] += kd->kernel[i][0];
398                 sum[1] += kd->kernel[i][1];
399                 sum[2] += kd->kernel[i][2];
400         }
401
402         for (int i = 0; i < 3; ++i) {
403                 if (sum[i] > 0.0f) {
404                         /* Normalize */
405                         for (int j = 0; j < sample_ct; j++) {
406                                 kd->kernel[j][i] /= sum[i];
407                         }
408                 }
409                 else {
410                         /* Avoid 0 kernel sum. */
411                         kd->kernel[sample_ct / 2][i] = 1.0f;
412                 }
413         }
414
415         /* Put center sample at the start of the array (to sample first) */
416         float tmpv[4];
417         copy_v4_v4(tmpv, kd->kernel[sample_ct / 2]);
418         for (int i = sample_ct / 2; i > 0; i--) {
419                 copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]);
420         }
421         copy_v4_v4(kd->kernel[0], tmpv);
422
423         kd->samples = sample_ct;
424 }
425
426 #define INTEGRAL_RESOLUTION 512
427 static void compute_sss_translucence_kernel(
428         const GPUSssKernelData *kd, int resolution, short falloff_type, float sharpness, float **output)
429 {
430         float (*texels)[4];
431         texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel");
432         *output = (float *)texels;
433
434         /* Last texel should be black, hence the - 1. */
435         for (int i = 0; i < resolution - 1; ++i) {
436                 /* Distance from surface. */
437                 float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution);
438
439                 /* For each distance d we compute the radiance incomming from an hypothetic parallel plane. */
440                 /* Compute radius of the footprint on the hypothetic plane */
441                 float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d);
442                 float r_step = r_fp / INTEGRAL_RESOLUTION;
443                 float area_accum = 0.0f;
444                 for (float r = 0.0f; r < r_fp; r += r_step) {
445                         /* Compute distance to the "shading" point through the medium. */
446                         /* r_step * 0.5f to put sample between the area borders */
447                         float dist = hypotf(r + r_step * 0.5f, d);
448
449                         float profile[3];
450                         profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]);
451                         profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]);
452                         profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]);
453
454                         /* Since the profile and configuration are radially symetrical we
455                          * can just evaluate it once and weight it accordingly */
456                         float r_next = r + r_step;
457                         float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r);
458
459                         mul_v3_fl(profile, disk_area);
460                         add_v3_v3(texels[i], profile);
461                         area_accum += disk_area;
462                 }
463                 /* Normalize over the disk. */
464                 mul_v3_fl(texels[i], 1.0f / (area_accum));
465         }
466
467         /* Normalize */
468         for (int j = resolution - 2; j > 0; j--) {
469                 texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f;
470                 texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f;
471                 texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f;
472         }
473
474         /* First texel should be white */
475         texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f;
476         texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f;
477         texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f;
478
479         /* dim the last few texels for smoother transition */
480         mul_v3_fl(texels[resolution - 2], 0.25f);
481         mul_v3_fl(texels[resolution - 3], 0.5f);
482         mul_v3_fl(texels[resolution - 4], 0.75f);
483 }
484 #undef INTEGRAL_RESOLUTION
485
486 void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness)
487 {
488         material->sss_radii = radii;
489         material->sss_falloff = falloff_type;
490         material->sss_sharpness = sharpness;
491         material->sss_dirty = true;
492
493         /* Update / Create UBO */
494         if (material->sss_profile == NULL) {
495                 material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL);
496         }
497 }
498
499 struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_ct, GPUTexture **tex_profile)
500 {
501         if (material->sss_radii == NULL)
502                 return NULL;
503
504         if (material->sss_dirty || (material->sss_samples != sample_ct)) {
505                 GPUSssKernelData kd;
506
507                 float sharpness = (material->sss_sharpness != NULL) ? *material->sss_sharpness : 0.0f;
508
509                 /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */
510                 sharpness *= 0.5f;
511
512                 compute_sss_kernel(&kd, material->sss_radii, sample_ct, *material->sss_falloff, sharpness);
513
514                 /* Update / Create UBO */
515                 GPU_uniformbuffer_update(material->sss_profile, &kd);
516
517                 /* Update / Create Tex */
518                 float *translucence_profile;
519                 compute_sss_translucence_kernel(&kd, 64, *material->sss_falloff, sharpness, &translucence_profile);
520
521                 if (material->sss_tex_profile != NULL) {
522                         GPU_texture_free(material->sss_tex_profile);
523                 }
524
525                 material->sss_tex_profile = GPU_texture_create_1D(64, GPU_RGBA16F, translucence_profile, NULL);
526
527                 MEM_freeN(translucence_profile);
528
529                 material->sss_samples = sample_ct;
530                 material->sss_dirty = false;
531         }
532
533         if (tex_profile != NULL) {
534                 *tex_profile = material->sss_tex_profile;
535         }
536         return material->sss_profile;
537 }
538
539 #undef SSS_EXPONENT
540 #undef SSS_SAMPLES
541
542 void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs)
543 {
544         *attribs = material->attribs;
545 }
546
547 void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
548 {
549         if (!material->outlink)
550                 material->outlink = link;
551 }
552
553 void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
554 {
555         BLI_addtail(&material->nodes, node);
556 }
557
558 /* Return true if the material compilation has not yet begin or begin. */
559 GPUMaterialStatus GPU_material_status(GPUMaterial *mat)
560 {
561         return mat->status;
562 }
563
564 /* Code generation */
565
566 bool GPU_material_do_color_management(GPUMaterial *mat)
567 {
568         if (!BKE_scene_check_color_management_enabled(mat->scene))
569                 return false;
570
571         return true;
572 }
573
574 bool GPU_material_use_domain_surface(GPUMaterial *mat)
575 {
576         return (mat->domain & GPU_DOMAIN_SURFACE);
577 }
578
579 bool GPU_material_use_domain_volume(GPUMaterial *mat)
580 {
581         return (mat->domain & GPU_DOMAIN_VOLUME);
582 }
583
584 GPUMaterial *GPU_material_from_nodetree_find(
585         ListBase *gpumaterials, const void *engine_type, int options)
586 {
587         for (LinkData *link = gpumaterials->first; link; link = link->next) {
588                 GPUMaterial *current_material = (GPUMaterial *)link->data;
589                 if (current_material->engine_type == engine_type &&
590                     current_material->options == options)
591                 {
592                         return current_material;
593                 }
594         }
595
596         return NULL;
597 }
598
599 /**
600  * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
601  * This is enforced since constructing other arguments to this function may be expensive
602  * so only do this when they are needed.
603  */
604 GPUMaterial *GPU_material_from_nodetree(
605         Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options,
606         const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines)
607 {
608         LinkData *link;
609         bool has_volume_output, has_surface_output;
610
611         /* Caller must re-use materials. */
612         BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
613
614         /* allocate material */
615         GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");;
616         mat->scene = scene;
617         mat->engine_type = engine_type;
618         mat->options = options;
619
620         ntreeGPUMaterialNodes(ntree, mat, NODE_NEW_SHADING | NODE_NEWER_SHADING);
621         ntreeGPUMaterialDomain(ntree, &has_surface_output, &has_volume_output);
622
623         if (has_surface_output) {
624                 mat->domain |= GPU_DOMAIN_SURFACE;
625         }
626         if (has_volume_output) {
627                 mat->domain |= GPU_DOMAIN_VOLUME;
628         }
629
630         if (mat->outlink) {
631                 /* Prune the unused nodes and extract attribs before compiling so the
632                  * generated VBOs are ready to accept the future shader. */
633                 GPU_nodes_prune(&mat->nodes, mat->outlink);
634                 GPU_nodes_get_vertex_attributes(&mat->nodes, &mat->attribs);
635                 /* Create source code and search pass cache for an already compiled version. */
636                 mat->pass = GPU_generate_pass_new(mat,
637                                       mat->outlink,
638                                       &mat->attribs,
639                                       &mat->nodes,
640                                       vert_code,
641                                       geom_code,
642                                       frag_lib,
643                                       defines);
644
645                 if (mat->pass == NULL) {
646                         /* We had a cache hit and the shader has already failed to compile. */
647                         mat->status = GPU_MAT_FAILED;
648                 }
649                 else {
650                         GPUShader *sh = GPU_pass_shader_get(mat->pass);
651                         if (sh != NULL) {
652                                 /* We had a cache hit and the shader is already compiled. */
653                                 mat->status = GPU_MAT_SUCCESS;
654                                 GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
655                         }
656                         else {
657                                 mat->status = GPU_MAT_QUEUED;
658                         }
659                 }
660         }
661         else {
662                 mat->status = GPU_MAT_FAILED;
663         }
664
665         /* note that even if building the shader fails in some way, we still keep
666          * it to avoid trying to compile again and again, and simply do not use
667          * the actual shader on drawing */
668
669         link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
670         link->data = mat;
671         BLI_addtail(gpumaterials, link);
672
673         return mat;
674 }
675
676 void GPU_material_compile(GPUMaterial *mat)
677 {
678         /* Only run once! */
679         BLI_assert(mat->status == GPU_MAT_QUEUED);
680         BLI_assert(mat->pass);
681
682         /* NOTE: The shader may have already been compiled here since we are
683          * sharing GPUShader across GPUMaterials. In this case it's a no-op. */
684         GPU_pass_compile(mat->pass);
685         GPUShader *sh = GPU_pass_shader_get(mat->pass);
686
687         if (sh != NULL) {
688                 mat->status = GPU_MAT_SUCCESS;
689                 GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
690         }
691         else {
692                 mat->status = GPU_MAT_FAILED;
693                 GPU_pass_free_nodes(&mat->nodes);
694                 GPU_pass_release(mat->pass);
695                 mat->pass = NULL;
696         }
697 }
698
699 void GPU_materials_free(void)
700 {
701         Material *ma;
702         World *wo;
703         extern Material defmaterial;
704
705         for (ma = G.main->mat.first; ma; ma = ma->id.next)
706                 GPU_material_free(&ma->gpumaterial);
707
708         for (wo = G.main->world.first; wo; wo = wo->id.next)
709                 GPU_material_free(&wo->gpumaterial);
710
711         GPU_material_free(&defmaterial.gpumaterial);
712 }