/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright 2016, Blender Foundation. */ /** \file * \ingroup draw_engine */ #include "DRW_render.h" #include "BKE_lib_id.h" #include "BKE_node.h" #include "BLI_dynstr.h" #include "BLI_string_utils.h" #include "MEM_guardedalloc.h" #include "GPU_material.h" #include "GPU_shader.h" #include "NOD_shader.h" #include "eevee_engine.h" #include "eevee_private.h" static const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n" #if defined(IRRADIANCE_SH_L2) "#define IRRADIANCE_SH_L2\n" #elif defined(IRRADIANCE_CUBEMAP) "#define IRRADIANCE_CUBEMAP\n" #elif defined(IRRADIANCE_HL2) "#define IRRADIANCE_HL2\n" #endif "#define NOISE_SIZE 64\n"; static struct { /* Probes */ struct GPUShader *probe_default_sh; struct GPUShader *probe_default_studiolight_sh; struct GPUShader *probe_background_studiolight_sh; struct GPUShader *probe_grid_display_sh; struct GPUShader *probe_cube_display_sh; struct GPUShader *probe_planar_display_sh; struct GPUShader *probe_filter_glossy_sh; struct GPUShader *probe_filter_diffuse_sh; struct GPUShader *probe_filter_visibility_sh; struct GPUShader *probe_grid_fill_sh; struct GPUShader *probe_planar_downsample_sh; /* Velocity Resolve */ struct GPUShader *velocity_resolve_sh; /* Temporal Anti Aliasing */ struct GPUShader *taa_resolve_sh; struct GPUShader *taa_resolve_reproject_sh; /* General purpose Shaders. */ struct GPUShader *default_background; struct GPUShader *update_noise_sh; /* Shader strings */ char *frag_shader_lib; char *vert_shader_str; char *vert_shadow_shader_str; char *vert_background_shader_str; char *vert_volume_shader_str; char *geom_volume_shader_str; char *volume_shader_lib; /* LookDev Materials */ Material *glossy_mat; Material *diffuse_mat; Material *error_mat; /* Default Material */ struct { bNodeTree *ntree; bNodeSocketValueRGBA *color_socket; bNodeSocketValueFloat *metallic_socket; bNodeSocketValueFloat *roughness_socket; bNodeSocketValueFloat *specular_socket; } surface; struct { bNodeTree *ntree; bNodeSocketValueRGBA *color_socket; } world; } e_data = {NULL}; /* Engine data */ extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_ambient_occlusion_lib_glsl[]; extern char datatoc_background_vert_glsl[]; extern char datatoc_common_hair_lib_glsl[]; extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_default_world_frag_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lightprobe_cube_display_frag_glsl[]; extern char datatoc_lightprobe_cube_display_vert_glsl[]; extern char datatoc_lightprobe_filter_diffuse_frag_glsl[]; extern char datatoc_lightprobe_filter_glossy_frag_glsl[]; extern char datatoc_lightprobe_filter_visibility_frag_glsl[]; extern char datatoc_lightprobe_geom_glsl[]; extern char datatoc_lightprobe_grid_display_frag_glsl[]; extern char datatoc_lightprobe_grid_display_vert_glsl[]; extern char datatoc_lightprobe_grid_fill_frag_glsl[]; extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_lightprobe_planar_display_frag_glsl[]; extern char datatoc_lightprobe_planar_display_vert_glsl[]; extern char datatoc_lightprobe_planar_downsample_frag_glsl[]; extern char datatoc_lightprobe_planar_downsample_geom_glsl[]; extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; extern char datatoc_lightprobe_vert_glsl[]; extern char datatoc_lights_lib_glsl[]; extern char datatoc_lit_surface_frag_glsl[]; extern char datatoc_lit_surface_vert_glsl[]; extern char datatoc_ltc_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_prepass_frag_glsl[]; extern char datatoc_raytrace_lib_glsl[]; extern char datatoc_shadow_vert_glsl[]; extern char datatoc_ssr_lib_glsl[]; extern char datatoc_update_noise_frag_glsl[]; extern char datatoc_volumetric_frag_glsl[]; extern char datatoc_volumetric_geom_glsl[]; extern char datatoc_volumetric_lib_glsl[]; extern char datatoc_volumetric_vert_glsl[]; /* Velocity Resolve */ extern char datatoc_effect_velocity_resolve_frag_glsl[]; /* Temporal Sampling */ extern char datatoc_effect_temporal_aa_glsl[]; /* *********** FUNCTIONS *********** */ void EEVEE_shaders_lightprobe_shaders_init(void) { BLI_assert(e_data.probe_filter_glossy_sh == NULL); char *shader_str = NULL; shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_lightprobe_filter_glossy_frag_glsl); e_data.probe_filter_glossy_sh = DRW_shader_create( datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, filter_defines); e_data.probe_default_sh = DRW_shader_create_with_lib(datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, datatoc_common_view_lib_glsl, NULL); MEM_freeN(shader_str); shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_lightprobe_filter_diffuse_frag_glsl); e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(shader_str, filter_defines); MEM_freeN(shader_str); shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_lightprobe_filter_visibility_frag_glsl); e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen(shader_str, filter_defines); MEM_freeN(shader_str); e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen(datatoc_lightprobe_grid_fill_frag_glsl, filter_defines); e_data.probe_planar_downsample_sh = DRW_shader_create( datatoc_lightprobe_planar_downsample_vert_glsl, datatoc_lightprobe_planar_downsample_geom_glsl, datatoc_lightprobe_planar_downsample_frag_glsl, NULL); } void EEVEE_shaders_material_shaders_init(void) { e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_raytrace_lib_glsl, datatoc_ssr_lib_glsl, datatoc_octahedron_lib_glsl, datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_ltc_lib_glsl, datatoc_lights_lib_glsl, /* Add one for each Closure */ datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_volumetric_lib_glsl); e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_octahedron_lib_glsl, datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_ltc_lib_glsl, datatoc_lights_lib_glsl, datatoc_volumetric_lib_glsl, datatoc_volumetric_frag_glsl); e_data.vert_shader_str = BLI_string_joinN( datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl); e_data.vert_shadow_shader_str = BLI_string_joinN( datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl); e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_background_vert_glsl); e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_volumetric_vert_glsl); e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_volumetric_geom_glsl); } GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void) { return e_data.probe_filter_glossy_sh; } GPUShader *EEVEE_shaders_probe_default_sh_get(void) { return e_data.probe_default_sh; } GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void) { return e_data.probe_filter_diffuse_sh; } GPUShader *EEVEE_shaders_probe_filter_visibility_sh_get(void) { return e_data.probe_filter_visibility_sh; } GPUShader *EEVEE_shaders_probe_grid_fill_sh_get(void) { return e_data.probe_grid_fill_sh; } GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void) { return e_data.probe_planar_downsample_sh; } GPUShader *EEVEE_shaders_default_studiolight_sh_get(void) { if (e_data.probe_default_studiolight_sh == NULL) { e_data.probe_default_studiolight_sh = DRW_shader_create_with_lib( datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, datatoc_common_view_lib_glsl, "#define LOOKDEV\n"); } return e_data.probe_default_studiolight_sh; } GPUShader *EEVEE_shaders_background_studiolight_sh_get(void) { if (e_data.probe_background_studiolight_sh == NULL) { char *frag_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, datatoc_cubemap_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_default_world_frag_glsl); e_data.probe_background_studiolight_sh = DRW_shader_create_with_lib( datatoc_background_vert_glsl, NULL, frag_str, datatoc_common_view_lib_glsl, "#define LOOKDEV_BG\n" SHADER_DEFINES); MEM_freeN(frag_str); } return e_data.probe_background_studiolight_sh; } GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void) { if (e_data.probe_cube_display_sh == NULL) { char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, datatoc_cubemap_lib_glsl, datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_lightprobe_cube_display_frag_glsl); char *vert_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_lightprobe_cube_display_vert_glsl); e_data.probe_cube_display_sh = DRW_shader_create(vert_str, NULL, shader_str, SHADER_DEFINES); MEM_freeN(vert_str); MEM_freeN(shader_str); } return e_data.probe_cube_display_sh; } GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void) { if (e_data.probe_grid_display_sh == NULL) { char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, datatoc_cubemap_lib_glsl, datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_lightprobe_grid_display_frag_glsl); char *vert_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_lightprobe_grid_display_vert_glsl); e_data.probe_grid_display_sh = DRW_shader_create(vert_str, NULL, shader_str, filter_defines); MEM_freeN(vert_str); MEM_freeN(shader_str); } return e_data.probe_grid_display_sh; } GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void) { if (e_data.probe_planar_display_sh == NULL) { char *vert_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_lightprobe_planar_display_vert_glsl); char *shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_lightprobe_planar_display_frag_glsl); e_data.probe_planar_display_sh = DRW_shader_create(vert_str, NULL, shader_str, NULL); MEM_freeN(vert_str); MEM_freeN(shader_str); } return e_data.probe_planar_display_sh; } GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void) { if (e_data.velocity_resolve_sh == NULL) { char *frag_str = BLI_string_joinN(datatoc_common_uniforms_lib_glsl, datatoc_common_view_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_effect_velocity_resolve_frag_glsl); e_data.velocity_resolve_sh = DRW_shader_create_fullscreen(frag_str, NULL); MEM_freeN(frag_str); } return e_data.velocity_resolve_sh; } GPUShader *EEVEE_shaders_default_background_sh_get(void) { if (e_data.default_background == NULL) { e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, datatoc_common_view_lib_glsl, NULL); } return e_data.default_background; } GPUShader *EEVEE_shaders_update_noise_sh_get(void) { if (e_data.update_noise_sh == NULL) { e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL); } return e_data.update_noise_sh; } GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects) { GPUShader **sh; const char *define = NULL; if (enabled_effects & EFFECT_TAA_REPROJECT) { sh = &e_data.taa_resolve_reproject_sh; define = "#define USE_REPROJECTION\n"; } else { sh = &e_data.taa_resolve_sh; } if (*sh == NULL) { char *frag_str = BLI_string_joinN(datatoc_common_uniforms_lib_glsl, datatoc_common_view_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_effect_temporal_aa_glsl); *sh = DRW_shader_create_fullscreen(frag_str, define); MEM_freeN(frag_str); } return *sh; } Material *EEVEE_material_default_diffuse_get(void) { if (!e_data.diffuse_mat) { Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default diffuse"); bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); ma->nodetree = ntree; ma->use_nodes = true; bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_DIFFUSE); bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color"); copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 0.8f); bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); nodeAddLink(ntree, bsdf, nodeFindSocket(bsdf, SOCK_OUT, "BSDF"), output, nodeFindSocket(output, SOCK_IN, "Surface")); nodeSetActive(ntree, output); e_data.diffuse_mat = ma; } return e_data.diffuse_mat; } Material *EEVEE_material_default_glossy_get(void) { if (!e_data.glossy_mat) { Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal"); bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); ma->nodetree = ntree; ma->use_nodes = true; bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_GLOSSY); bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color"); copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 1.0f); bNodeSocket *roughness = nodeFindSocket(bsdf, SOCK_IN, "Roughness"); ((bNodeSocketValueFloat *)roughness->default_value)->value = 0.0f; bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); nodeAddLink(ntree, bsdf, nodeFindSocket(bsdf, SOCK_OUT, "BSDF"), output, nodeFindSocket(output, SOCK_IN, "Surface")); nodeSetActive(ntree, output); e_data.glossy_mat = ma; } return e_data.glossy_mat; } Material *EEVEE_material_default_error_get(void) { if (!e_data.error_mat) { Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal"); bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); ma->nodetree = ntree; ma->use_nodes = true; /* Use emission and output material to be compatible with both World and Material. */ bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION); bNodeSocket *color = nodeFindSocket(bsdf, SOCK_IN, "Color"); copy_v3_fl3(((bNodeSocketValueRGBA *)color->default_value)->value, 1.0f, 0.0f, 1.0f); bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); nodeAddLink(ntree, bsdf, nodeFindSocket(bsdf, SOCK_OUT, "Emission"), output, nodeFindSocket(output, SOCK_IN, "Surface")); nodeSetActive(ntree, output); e_data.error_mat = ma; } return e_data.error_mat; } /* Configure a default nodetree with the given material. */ struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma) { /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */ if (!e_data.surface.ntree) { bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_PRINCIPLED); bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); bNodeSocket *bsdf_out = nodeFindSocket(bsdf, SOCK_OUT, "BSDF"); bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface"); nodeAddLink(ntree, bsdf, bsdf_out, output, output_in); nodeSetActive(ntree, output); e_data.surface.color_socket = nodeFindSocket(bsdf, SOCK_IN, "Base Color")->default_value; e_data.surface.metallic_socket = nodeFindSocket(bsdf, SOCK_IN, "Metallic")->default_value; e_data.surface.roughness_socket = nodeFindSocket(bsdf, SOCK_IN, "Roughness")->default_value; e_data.surface.specular_socket = nodeFindSocket(bsdf, SOCK_IN, "Specular")->default_value; e_data.surface.ntree = ntree; } /* Update */ copy_v3_fl3(e_data.surface.color_socket->value, ma->r, ma->g, ma->b); e_data.surface.metallic_socket->value = ma->metallic; e_data.surface.roughness_socket->value = ma->roughness; e_data.surface.specular_socket->value = ma->spec; return e_data.surface.ntree; } /* Configure a default nodetree with the given world. */ struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo) { /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */ if (!e_data.world.ntree) { bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); bNode *bg = nodeAddStaticNode(NULL, ntree, SH_NODE_BACKGROUND); bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_WORLD); bNodeSocket *bg_out = nodeFindSocket(bg, SOCK_OUT, "Background"); bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface"); nodeAddLink(ntree, bg, bg_out, output, output_in); nodeSetActive(ntree, output); e_data.world.color_socket = nodeFindSocket(bg, SOCK_IN, "Color")->default_value; e_data.world.ntree = ntree; } copy_v3_fl3(e_data.world.color_socket->value, wo->horr, wo->horg, wo->horb); return e_data.world.ntree; } static char *eevee_get_defines(int options) { char *str = NULL; DynStr *ds = BLI_dynstr_new(); BLI_dynstr_append(ds, SHADER_DEFINES); if ((options & VAR_WORLD_BACKGROUND) != 0) { BLI_dynstr_append(ds, "#define WORLD_BACKGROUND\n"); } if ((options & VAR_MAT_VOLUME) != 0) { BLI_dynstr_append(ds, "#define VOLUMETRICS\n"); } if ((options & VAR_MAT_MESH) != 0) { BLI_dynstr_append(ds, "#define MESH_SHADER\n"); } if ((options & VAR_MAT_DEPTH) != 0) { BLI_dynstr_append(ds, "#define DEPTH_SHADER\n"); } if ((options & VAR_MAT_HAIR) != 0) { BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); } if ((options & (VAR_MAT_PROBE | VAR_WORLD_PROBE)) != 0) { BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n"); } if ((options & VAR_MAT_HASH) != 0) { BLI_dynstr_append(ds, "#define USE_ALPHA_HASH\n"); } if ((options & VAR_MAT_BLEND) != 0) { BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND\n"); } if ((options & VAR_MAT_REFRACT) != 0) { BLI_dynstr_append(ds, "#define USE_REFRACTION\n"); } if ((options & VAR_MAT_LOOKDEV) != 0) { BLI_dynstr_append(ds, "#define LOOKDEV\n"); } if ((options & VAR_MAT_HOLDOUT) != 0) { BLI_dynstr_append(ds, "#define HOLDOUT\n"); } str = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); return str; } static char *eevee_get_vert(int options) { char *str = NULL; if ((options & VAR_MAT_VOLUME) != 0) { str = BLI_strdup(e_data.vert_volume_shader_str); } else if ((options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0) { str = BLI_strdup(e_data.vert_background_shader_str); } else { str = BLI_strdup(e_data.vert_shader_str); } return str; } static char *eevee_get_geom(int options) { char *str = NULL; if ((options & VAR_MAT_VOLUME) != 0) { str = BLI_strdup(e_data.geom_volume_shader_str); } return str; } static char *eevee_get_frag(int options) { char *str = NULL; if ((options & VAR_MAT_VOLUME) != 0) { str = BLI_strdup(e_data.volume_shader_lib); } else if ((options & VAR_MAT_DEPTH) != 0) { str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); } else { str = BLI_strdup(e_data.frag_shader_lib); } return str; } static struct GPUMaterial *eevee_material_get_ex( struct Scene *scene, Material *ma, World *wo, int options, bool deferred) { BLI_assert(ma || wo); const bool is_volume = (options & VAR_MAT_VOLUME) != 0; const bool is_default = (options & VAR_DEFAULT) != 0; const void *engine = &DRW_engine_viewport_eevee_type; GPUMaterial *mat = NULL; if (ma) { mat = DRW_shader_find_from_material(ma, engine, options, deferred); } else { mat = DRW_shader_find_from_world(wo, engine, options, deferred); } if (mat) { return mat; } char *defines = eevee_get_defines(options); char *vert = eevee_get_vert(options); char *geom = eevee_get_geom(options); char *frag = eevee_get_frag(options); if (ma) { bNodeTree *ntree = !is_default ? ma->nodetree : EEVEE_shader_default_surface_nodetree(ma); mat = DRW_shader_create_from_material( scene, ma, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred); } else { bNodeTree *ntree = !is_default ? wo->nodetree : EEVEE_shader_default_world_nodetree(wo); mat = DRW_shader_create_from_world( scene, wo, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred); } MEM_SAFE_FREE(defines); MEM_SAFE_FREE(vert); MEM_SAFE_FREE(geom); MEM_SAFE_FREE(frag); return mat; } /* Note: Compilation is not deferred. */ struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options) { Material *def_ma = (ma && (options & VAR_MAT_VOLUME)) ? BKE_material_default_volume() : BKE_material_default_surface(); BLI_assert(def_ma->use_nodes && def_ma->nodetree); return eevee_material_get_ex(scene, def_ma, NULL, options, false); } struct GPUMaterial *EEVEE_material_get( EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options) { if ((ma && (!ma->use_nodes || !ma->nodetree)) || (wo && (!wo->use_nodes || !wo->nodetree))) { options |= VAR_DEFAULT; } /* Meh, implicit option. World probe cannot be deferred because they need * to be rendered immediatly. */ const bool deferred = (options & VAR_WORLD_PROBE) == 0; GPUMaterial *mat = eevee_material_get_ex(scene, ma, wo, options, deferred); int status = GPU_material_status(mat); switch (status) { case GPU_MAT_SUCCESS: break; case GPU_MAT_QUEUED: vedata->stl->g_data->queued_shaders_count++; mat = EEVEE_material_default_get(scene, ma, options); break; case GPU_MAT_FAILED: default: ma = EEVEE_material_default_error_get(); mat = eevee_material_get_ex(scene, ma, NULL, options, false); break; } /* Returned material should be ready to be drawn. */ BLI_assert(GPU_material_status(mat) == GPU_MAT_SUCCESS); return mat; } void EEVEE_shaders_free(void) { MEM_SAFE_FREE(e_data.frag_shader_lib); MEM_SAFE_FREE(e_data.vert_shader_str); MEM_SAFE_FREE(e_data.vert_shadow_shader_str); MEM_SAFE_FREE(e_data.vert_background_shader_str); MEM_SAFE_FREE(e_data.vert_volume_shader_str); MEM_SAFE_FREE(e_data.geom_volume_shader_str); MEM_SAFE_FREE(e_data.volume_shader_lib); DRW_SHADER_FREE_SAFE(e_data.default_background); DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_SHADER_FREE_SAFE(e_data.probe_default_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_visibility_sh); DRW_SHADER_FREE_SAFE(e_data.probe_grid_fill_sh); DRW_SHADER_FREE_SAFE(e_data.probe_planar_downsample_sh); DRW_SHADER_FREE_SAFE(e_data.probe_default_studiolight_sh); DRW_SHADER_FREE_SAFE(e_data.probe_background_studiolight_sh); DRW_SHADER_FREE_SAFE(e_data.probe_grid_display_sh); DRW_SHADER_FREE_SAFE(e_data.probe_cube_display_sh); DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh); DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh); if (e_data.glossy_mat) { BKE_id_free(NULL, e_data.glossy_mat); e_data.glossy_mat = NULL; } if (e_data.diffuse_mat) { BKE_id_free(NULL, e_data.diffuse_mat); e_data.diffuse_mat = NULL; } if (e_data.error_mat) { BKE_id_free(NULL, e_data.error_mat); e_data.error_mat = NULL; } if (e_data.surface.ntree) { ntreeFreeEmbeddedTree(e_data.surface.ntree); MEM_freeN(e_data.surface.ntree); e_data.surface.ntree = NULL; } if (e_data.world.ntree) { ntreeFreeEmbeddedTree(e_data.world.ntree); MEM_freeN(e_data.world.ntree); e_data.world.ntree = NULL; } }