From 80859a6cb2726a39fb22cb49f06e0355dc9390a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Foucault?= Date: Thu, 14 Apr 2022 18:47:58 +0200 Subject: GPU: Make nodetree GLSL Codegen render engine agnostic This commit removes all EEVEE specific code from the `gpu_shader_material*.glsl` files. It defines a clear interface to evaluate the closure nodes leaving more flexibility to the render engine. Some of the long standing workaround are fixed: - bump mapping support is no longer duplicating a lot of node and is instead compiled into a function call. - bump rewiring to Normal socket is no longer needed as we now use a global `g_data.N` for that. Closure sampling with upstread weight eval is now supported if the engine needs it. This also makes all the material GLSL sources use `GPUSource` for better debugging experience. The `GPUFunction` parsing now happens in `GPUSource` creation. The whole `GPUCodegen` now uses the `ShaderCreateInfo` and is object type agnostic. Is has also been rewritten in C++. This patch changes a view behavior for EEVEE: - Mix shader node factor imput is now clamped. - Tangent Vector displacement behavior is now matching cycles. - The chosen BSDF used for SSR might change. - Hair shading may have very small changes on very large hairs when using hair polygon stripes. - ShaderToRGB node will remove any SSR and SSS form a shader. - SSS radius input now is no longer a scaling factor but defines an average radius. The SSS kernel "shape" (radii) are still defined by the socket default values. Appart from the listed changes no other regressions are expected. --- source/blender/draw/CMakeLists.txt | 9 +- .../blender/draw/engines/eevee/eevee_materials.c | 16 +- source/blender/draw/engines/eevee/eevee_private.h | 20 +- .../draw/engines/eevee/eevee_renderpasses.c | 4 +- source/blender/draw/engines/eevee/eevee_shaders.c | 84 +- .../draw/engines/eevee/eevee_shaders_extra.cc | 173 +++ source/blender/draw/engines/eevee/eevee_volumes.c | 1 + .../eevee/shaders/ambient_occlusion_lib.glsl | 35 + .../eevee/shaders/closure_eval_diffuse_lib.glsl | 3 + .../eevee/shaders/closure_eval_glossy_lib.glsl | 3 + .../engines/eevee/shaders/closure_eval_lib.glsl | 15 + .../eevee/shaders/closure_eval_refraction_lib.glsl | 3 + .../eevee/shaders/closure_eval_surface_lib.glsl | 325 ++++++ .../shaders/closure_eval_translucent_lib.glsl | 3 + .../eevee/shaders/closure_eval_volume_lib.glsl | 113 ++ .../engines/eevee/shaders/closure_type_lib.glsl | 252 ++--- .../draw/engines/eevee/shaders/eevee_empty.glsl | 7 + .../engines/eevee/shaders/eevee_empty_volume.glsl | 8 + .../eevee/shaders/effect_subsurface_frag.glsl | 3 +- .../eevee/shaders/effect_translucency_frag.glsl | 3 +- .../draw/engines/eevee/shaders/prepass_frag.glsl | 10 +- .../draw/engines/eevee/shaders/prepass_vert.glsl | 35 - .../draw/engines/eevee/shaders/renderpass_lib.glsl | 21 +- .../draw/engines/eevee/shaders/shadow_vert.glsl | 92 ++ .../draw/engines/eevee/shaders/surface_frag.glsl | 141 ++- .../draw/engines/eevee/shaders/surface_lib.glsl | 166 ++- .../draw/engines/eevee/shaders/surface_vert.glsl | 108 +- .../engines/eevee/shaders/volumetric_frag.glsl | 111 +- .../engines/eevee/shaders/volumetric_geom.glsl | 6 +- .../eevee/shaders/volumetric_integration_frag.glsl | 6 +- .../engines/eevee/shaders/volumetric_vert.glsl | 28 +- .../draw/engines/eevee/shaders/world_vert.glsl | 24 + source/blender/draw/intern/DRW_render.h | 54 +- source/blender/draw/intern/draw_hair.c | 2 +- source/blender/draw/intern/draw_manager_shader.c | 190 ++-- source/blender/draw/intern/draw_shader_shared.h | 21 +- .../draw/intern/shaders/common_attribute_lib.glsl | 21 + .../draw/intern/shaders/common_math_lib.glsl | 6 + .../draw/intern/shaders/common_view_lib.glsl | 54 +- source/blender/gpu/CMakeLists.txt | 4 +- source/blender/gpu/GPU_material.h | 126 ++- source/blender/gpu/GPU_uniform_buffer.h | 4 +- source/blender/gpu/intern/gpu_codegen.c | 1123 -------------------- source/blender/gpu/intern/gpu_codegen.cc | 825 ++++++++++++++ source/blender/gpu/intern/gpu_codegen.h | 28 +- source/blender/gpu/intern/gpu_init_exit.c | 2 - source/blender/gpu/intern/gpu_material.c | 339 +++--- source/blender/gpu/intern/gpu_material_library.c | 904 ---------------- source/blender/gpu/intern/gpu_material_library.h | 27 +- source/blender/gpu/intern/gpu_node_graph.c | 117 +- source/blender/gpu/intern/gpu_node_graph.h | 54 +- source/blender/gpu/intern/gpu_shader.cc | 5 +- .../blender/gpu/intern/gpu_shader_builder_stubs.cc | 5 +- .../blender/gpu/intern/gpu_shader_create_info.hh | 9 + source/blender/gpu/intern/gpu_shader_dependency.cc | 325 +++++- source/blender/gpu/opengl/gl_shader.cc | 17 +- .../gpu/shaders/gpu_shader_codegen_lib.glsl | 173 +++ .../gpu_shader_material_ambient_occlusion.glsl | 18 +- .../material/gpu_shader_material_anisotropic.glsl | 26 +- .../material/gpu_shader_material_background.glsl | 16 +- .../shaders/material/gpu_shader_material_bump.glsl | 38 +- .../material/gpu_shader_material_camera.glsl | 8 +- .../material/gpu_shader_material_combine_hsv.glsl | 2 + .../material/gpu_shader_material_diffuse.glsl | 31 +- .../material/gpu_shader_material_displacement.glsl | 8 +- .../gpu_shader_material_eevee_specular.glsl | 101 +- .../material/gpu_shader_material_emission.glsl | 15 +- .../gpu_shader_material_fractal_noise.glsl | 3 + .../material/gpu_shader_material_fresnel.glsl | 7 +- .../material/gpu_shader_material_gamma.glsl | 2 + .../material/gpu_shader_material_geometry.glsl | 53 +- .../material/gpu_shader_material_glass.glsl | 64 +- .../material/gpu_shader_material_glossy.glsl | 39 +- .../shaders/material/gpu_shader_material_hair.glsl | 46 + .../material/gpu_shader_material_hair_info.glsl | 26 +- .../material/gpu_shader_material_holdout.glsl | 14 +- .../material/gpu_shader_material_hue_sat_val.glsl | 2 + .../material/gpu_shader_material_layer_weight.glsl | 10 +- .../material/gpu_shader_material_light_path.glsl | 16 +- .../material/gpu_shader_material_map_range.glsl | 2 + .../material/gpu_shader_material_mapping.glsl | 2 + .../shaders/material/gpu_shader_material_math.glsl | 2 + .../material/gpu_shader_material_math_util.glsl | 69 +- .../material/gpu_shader_material_mix_rgb.glsl | 2 + .../material/gpu_shader_material_noise.glsl | 2 + .../material/gpu_shader_material_normal_map.glsl | 14 +- .../material/gpu_shader_material_object_info.glsl | 16 +- .../material/gpu_shader_material_output_aov.glsl | 12 +- .../gpu_shader_material_output_material.glsl | 36 +- .../material/gpu_shader_material_output_world.glsl | 18 +- .../gpu_shader_material_particle_info.glsl | 23 +- .../material/gpu_shader_material_point_info.glsl | 2 + .../material/gpu_shader_material_principled.glsl | 248 ++--- .../material/gpu_shader_material_refraction.glsl | 37 +- .../material/gpu_shader_material_separate_hsv.glsl | 2 + .../gpu_shader_material_shader_to_rgba.glsl | 27 +- .../gpu_shader_material_subsurface_scattering.glsl | 30 +- .../material/gpu_shader_material_tangent.glsl | 6 +- .../material/gpu_shader_material_tex_brick.glsl | 3 + .../gpu_shader_material_tex_environment.glsl | 16 +- .../material/gpu_shader_material_tex_musgrave.glsl | 3 + .../material/gpu_shader_material_tex_noise.glsl | 4 + .../material/gpu_shader_material_tex_voronoi.glsl | 3 + .../material/gpu_shader_material_tex_wave.glsl | 4 + .../gpu_shader_material_tex_white_noise.glsl | 2 + .../gpu_shader_material_texture_coordinates.glsl | 84 +- .../shaders/material/gpu_shader_material_toon.glsl | 20 +- .../material/gpu_shader_material_translucent.glsl | 23 +- .../material/gpu_shader_material_transparent.glsl | 17 +- .../gpu_shader_material_vector_displacement.glsl | 32 +- .../material/gpu_shader_material_vector_math.glsl | 2 + .../gpu_shader_material_vector_rotate.glsl | 2 + .../material/gpu_shader_material_velvet.glsl | 19 +- .../gpu_shader_material_volume_absorption.glsl | 13 +- .../material/gpu_shader_material_volume_info.glsl | 24 +- .../gpu_shader_material_volume_principled.glsl | 22 +- .../gpu_shader_material_volume_scatter.glsl | 15 +- .../material/gpu_shader_material_wireframe.glsl | 23 +- .../gpu_shader_material_world_normals.glsl | 24 +- source/blender/makesdna/DNA_node_types.h | 15 +- source/blender/nodes/NOD_shader.h | 5 +- source/blender/nodes/shader/node_shader_tree.cc | 735 +++++++------ source/blender/nodes/shader/node_shader_util.cc | 15 +- .../shader/nodes/node_shader_ambient_occlusion.cc | 2 +- .../nodes/shader/nodes/node_shader_background.cc | 1 + .../nodes/shader/nodes/node_shader_bevel.cc | 6 +- .../shader/nodes/node_shader_bsdf_anisotropic.cc | 10 +- .../nodes/shader/nodes/node_shader_bsdf_diffuse.cc | 1 + .../nodes/shader/nodes/node_shader_bsdf_glass.cc | 11 +- .../nodes/shader/nodes/node_shader_bsdf_glossy.cc | 9 +- .../nodes/shader/nodes/node_shader_bsdf_hair.cc | 1 + .../nodes/node_shader_bsdf_hair_principled.cc | 11 + .../shader/nodes/node_shader_bsdf_principled.cc | 61 +- .../shader/nodes/node_shader_bsdf_refraction.cc | 1 + .../nodes/shader/nodes/node_shader_bsdf_toon.cc | 1 + .../shader/nodes/node_shader_bsdf_translucent.cc | 1 + .../shader/nodes/node_shader_bsdf_transparent.cc | 4 + .../nodes/shader/nodes/node_shader_bsdf_velvet.cc | 1 + .../blender/nodes/shader/nodes/node_shader_bump.cc | 17 +- .../nodes/shader/nodes/node_shader_camera.cc | 6 +- .../nodes/shader/nodes/node_shader_displacement.cc | 9 +- .../shader/nodes/node_shader_eevee_specular.cc | 9 +- .../nodes/shader/nodes/node_shader_emission.cc | 4 +- .../nodes/shader/nodes/node_shader_fresnel.cc | 8 +- .../nodes/shader/nodes/node_shader_geometry.cc | 20 +- .../nodes/shader/nodes/node_shader_holdout.cc | 1 + .../nodes/shader/nodes/node_shader_layer_weight.cc | 8 +- .../nodes/shader/nodes/node_shader_normal_map.cc | 9 +- .../nodes/shader/nodes/node_shader_object_info.cc | 11 +- .../nodes/shader/nodes/node_shader_output_aov.cc | 14 +- .../shader/nodes/node_shader_output_material.cc | 44 +- .../nodes/shader/nodes/node_shader_output_world.cc | 18 +- .../shader/nodes/node_shader_particle_info.cc | 13 +- .../shader/nodes/node_shader_shader_to_rgb.cc | 4 +- .../nodes/node_shader_subsurface_scattering.cc | 20 +- .../nodes/shader/nodes/node_shader_tangent.cc | 9 +- .../nodes/shader/nodes/node_shader_tex_coord.cc | 24 +- .../shader/nodes/node_shader_tex_environment.cc | 12 +- .../nodes/shader/nodes/node_shader_tex_image.cc | 8 +- .../nodes/node_shader_vector_displacement.cc | 29 +- .../shader/nodes/node_shader_vector_transform.cc | 39 +- .../shader/nodes/node_shader_volume_absorption.cc | 1 + .../shader/nodes/node_shader_volume_principled.cc | 1 + .../shader/nodes/node_shader_volume_scatter.cc | 1 + .../nodes/shader/nodes/node_shader_wireframe.cc | 14 +- 165 files changed, 4622 insertions(+), 4335 deletions(-) create mode 100644 source/blender/draw/engines/eevee/eevee_shaders_extra.cc create mode 100644 source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl create mode 100644 source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl create mode 100644 source/blender/draw/engines/eevee/shaders/eevee_empty.glsl create mode 100644 source/blender/draw/engines/eevee/shaders/eevee_empty_volume.glsl delete mode 100644 source/blender/draw/engines/eevee/shaders/prepass_vert.glsl create mode 100644 source/blender/draw/engines/eevee/shaders/world_vert.glsl create mode 100644 source/blender/draw/intern/shaders/common_attribute_lib.glsl delete mode 100644 source/blender/gpu/intern/gpu_codegen.c create mode 100644 source/blender/gpu/intern/gpu_codegen.cc delete mode 100644 source/blender/gpu/intern/gpu_material_library.c create mode 100644 source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl (limited to 'source') diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index aed527639c5..6d3c203b076 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -16,6 +16,7 @@ set(INC ../editors/space_view3d ../functions ../gpu + ../gpu/intern ../imbuf ../makesdna ../makesrna @@ -123,6 +124,7 @@ set(SRC engines/eevee/eevee_sampling.c engines/eevee/eevee_screen_raytrace.c engines/eevee/eevee_shaders.c + engines/eevee/eevee_shaders_extra.cc engines/eevee/eevee_shadows.c engines/eevee/eevee_shadows_cascade.c engines/eevee/eevee_shadows_cube.c @@ -266,9 +268,13 @@ set(GLSL_SRC engines/eevee/shaders/closure_eval_lib.glsl engines/eevee/shaders/closure_eval_diffuse_lib.glsl engines/eevee/shaders/closure_eval_glossy_lib.glsl + engines/eevee/shaders/closure_eval_surface_lib.glsl engines/eevee/shaders/closure_eval_refraction_lib.glsl + engines/eevee/shaders/closure_eval_volume_lib.glsl engines/eevee/shaders/closure_eval_translucent_lib.glsl engines/eevee/shaders/closure_type_lib.glsl + engines/eevee/shaders/eevee_empty.glsl + engines/eevee/shaders/eevee_empty_volume.glsl engines/eevee/shaders/effect_bloom_frag.glsl engines/eevee/shaders/effect_dof_bokeh_frag.glsl engines/eevee/shaders/effect_dof_dilate_tiles_frag.glsl @@ -302,7 +308,6 @@ set(GLSL_SRC engines/eevee/shaders/object_motion_frag.glsl engines/eevee/shaders/object_motion_vert.glsl engines/eevee/shaders/prepass_frag.glsl - engines/eevee/shaders/prepass_vert.glsl engines/eevee/shaders/shadow_accum_frag.glsl engines/eevee/shaders/shadow_frag.glsl engines/eevee/shaders/shadow_vert.glsl @@ -333,6 +338,7 @@ set(GLSL_SRC engines/eevee/shaders/volumetric_resolve_frag.glsl engines/eevee/shaders/volumetric_scatter_frag.glsl engines/eevee/shaders/volumetric_integration_frag.glsl + engines/eevee/shaders/world_vert.glsl engines/workbench/shaders/workbench_cavity_lib.glsl engines/workbench/shaders/workbench_common_lib.glsl @@ -364,6 +370,7 @@ set(GLSL_SRC engines/workbench/workbench_shader_shared.h + intern/shaders/common_attribute_lib.glsl intern/shaders/common_colormanagement_lib.glsl intern/shaders/common_globals_lib.glsl intern/shaders/common_gpencil_lib.glsl diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index c3f9a606dd0..c46e5dd75d6 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -73,7 +73,12 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, bool use_diffuse = GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE); bool use_glossy = GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY); bool use_refract = GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT); + bool use_ao = GPU_material_flag_get(gpumat, GPU_MATFLAG_AO); +#ifdef __APPLE__ + /* NOTE: Some implementation do not optimize out the unused samplers. */ + use_diffuse = use_glossy = use_refract = use_ao = true; +#endif LightCache *lcache = vedata->stl->g_data->light_cache; EEVEE_EffectsInfo *effects = vedata->stl->effects; EEVEE_PrivateData *pd = vedata->stl->g_data; @@ -91,6 +96,8 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, if (use_diffuse || use_glossy || use_refract) { DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool); DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); + } + if (use_diffuse || use_glossy || use_refract || use_ao) { DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); } if ((use_diffuse || use_glossy) && !use_ssrefraction) { @@ -374,6 +381,13 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block_ref(grp, "renderpass_block", &stl->g_data->renderpass_ubo); + DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex); + DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); + DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); + DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool); + DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &stl->g_data->light_cache->cube_tx.tex); + DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &stl->g_data->light_cache->grid_tx.tex); + DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &vedata->txl->maxzbuffer); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } @@ -578,7 +592,7 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata, SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT); SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR); GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); - const bool use_sss = GPU_material_flag_get(gpumat, GPU_MATFLAG_SSS); + const bool use_sss = GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE); int ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? 1 : 0; int option = (use_ssrefract ? 0 : (use_sss ? 1 : 2)) * 2 + do_cull; diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 722c03d7536..effae313acf 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -462,7 +462,7 @@ typedef struct EEVEE_RenderPassData { int renderPassSSSColor; int renderPassEnvironment; int renderPassAOV; - int renderPassAOVActive; + uint renderPassAOVActive; int _pad[3]; } EEVEE_RenderPassData; @@ -1050,7 +1050,7 @@ typedef struct EEVEE_PrivateData { /* Renderpasses */ /* Bitmask containing the active render_passes */ eViewLayerEEVEEPassType render_passes; - int aov_hash; + uint aov_hash; int num_aovs_used; struct CryptomatteSession *cryptomatte_session; bool cryptomatte_accurate_mode; @@ -1291,6 +1291,20 @@ struct GPUMaterial *EEVEE_material_get( EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options); void EEVEE_shaders_free(void); +void eevee_shader_extra_init(void); +void eevee_shader_extra_exit(void); +void eevee_shader_material_create_info_amend(GPUMaterial *gpumat, + GPUCodegenOutput *codegen, + char *frag, + char *vert, + char *geom, + char *defines); +GPUShader *eevee_shaders_sh_create_helper(const char *name, + const char *vert_name, + const char *frag_name, + const char *defines, + bool use_layered_rendering); + /* eevee_lightprobes.c */ bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data); @@ -1508,7 +1522,7 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata); * Calculate the hash for an AOV. The least significant bit is used to store the AOV * type the rest of the bits are used for the name hash. */ -int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov); +uint EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov); /* eevee_temporal_sampling.c */ diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 3814cf44fd6..237c830d547 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -60,9 +60,9 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata) return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0; } -int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov) +uint EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov) { - int hash = BLI_hash_string(aov->name) << 1; + uint hash = BLI_hash_string(aov->name) << 1u; SET_FLAG_FROM_TEST(hash, aov->type == AOV_TYPE_COLOR, EEVEE_AOV_HASH_COLOR_TYPE_MASK); return hash; } diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index ae5e6e94f74..4e4a2a9eb8e 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -170,6 +170,7 @@ extern char datatoc_common_math_lib_glsl[]; extern char datatoc_common_math_geom_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; +extern char datatoc_gpu_shader_codegen_lib_glsl[]; extern char datatoc_ambient_occlusion_lib_glsl[]; extern char datatoc_background_vert_glsl[]; @@ -178,6 +179,7 @@ extern char datatoc_bsdf_lut_frag_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_btdf_lut_frag_glsl[]; extern char datatoc_closure_type_lib_glsl[]; +extern char datatoc_closure_eval_volume_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_utiltex_lib_glsl[]; extern char datatoc_cryptomatte_frag_glsl[]; @@ -230,6 +232,7 @@ extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; extern char datatoc_lightprobe_vert_glsl[]; extern char datatoc_lights_lib_glsl[]; extern char datatoc_closure_eval_lib_glsl[]; +extern char datatoc_closure_eval_surface_lib_glsl[]; extern char datatoc_closure_eval_diffuse_lib_glsl[]; extern char datatoc_closure_eval_glossy_lib_glsl[]; extern char datatoc_closure_eval_refraction_lib_glsl[]; @@ -239,7 +242,6 @@ extern char datatoc_object_motion_frag_glsl[]; extern char datatoc_object_motion_vert_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_prepass_frag_glsl[]; -extern char datatoc_prepass_vert_glsl[]; extern char datatoc_random_lib_glsl[]; extern char datatoc_raytrace_lib_glsl[]; extern char datatoc_renderpass_lib_glsl[]; @@ -261,6 +263,7 @@ extern char datatoc_volumetric_lib_glsl[]; extern char datatoc_volumetric_resolve_frag_glsl[]; extern char datatoc_volumetric_scatter_frag_glsl[]; extern char datatoc_volumetric_vert_glsl[]; +extern char datatoc_world_vert_glsl[]; /* *********** FUNCTIONS *********** */ @@ -275,6 +278,7 @@ static void eevee_shader_library_ensure(void) DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib); DRW_SHADER_LIB_ADD(e_data.lib, common_uniforms_lib); DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib); + DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_codegen_lib); DRW_SHADER_LIB_ADD(e_data.lib, random_lib); DRW_SHADER_LIB_ADD(e_data.lib, renderpass_lib); DRW_SHADER_LIB_ADD(e_data.lib, bsdf_common_lib); @@ -299,6 +303,8 @@ static void eevee_shader_library_ensure(void) DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_glossy_lib); DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_translucent_lib); DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_refraction_lib); + DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_surface_lib); + DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_volume_lib); e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib, datatoc_surface_frag_glsl); @@ -313,6 +319,7 @@ static void eevee_shader_library_ensure(void) void EEVEE_shaders_material_shaders_init(void) { + eevee_shader_extra_init(); eevee_shader_library_ensure(); } @@ -828,6 +835,7 @@ struct GPUShader *EEVEE_shaders_volumes_clear_sh_get() datatoc_volumetric_frag_glsl, e_data.lib, SHADER_DEFINES + "#define STANDALONE\n" "#define VOLUMETRICS\n" "#define CLEAR\n"); } @@ -842,6 +850,7 @@ struct GPUShader *EEVEE_shaders_volumes_scatter_sh_get() datatoc_volumetric_scatter_frag_glsl, e_data.lib, SHADER_DEFINES + "#define STANDALONE\n" "#define VOLUMETRICS\n" "#define VOLUME_SHADOW\n"); } @@ -857,6 +866,7 @@ struct GPUShader *EEVEE_shaders_volumes_scatter_with_lights_sh_get() datatoc_volumetric_scatter_frag_glsl, e_data.lib, SHADER_DEFINES + "#define STANDALONE\n" "#define VOLUMETRICS\n" "#define VOLUME_LIGHTING\n" "#define VOLUME_SHADOW\n"); @@ -872,7 +882,9 @@ struct GPUShader *EEVEE_shaders_volumes_integration_sh_get() datatoc_volumetric_geom_glsl, datatoc_volumetric_integration_frag_glsl, e_data.lib, - USE_VOLUME_OPTI ? "#define USE_VOLUME_OPTI\n" SHADER_DEFINES : SHADER_DEFINES); + USE_VOLUME_OPTI ? "#define USE_VOLUME_OPTI\n" + "#define STANDALONE\n" SHADER_DEFINES : + "#define STANDALONE\n" SHADER_DEFINES); } return e_data.volumetric_integration_sh; } @@ -1232,7 +1244,7 @@ Material *EEVEE_material_default_glossy_get(void) Material *EEVEE_material_default_error_get(void) { if (!e_data.error_mat) { - Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal"); + Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default error"); bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname); ma->nodetree = ntree; @@ -1375,7 +1387,7 @@ static char *eevee_get_vert(int options) str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_volumetric_vert_glsl); } else if ((options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0) { - str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_background_vert_glsl); + str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_world_vert_glsl); } else { str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_surface_vert_glsl); @@ -1412,68 +1424,43 @@ static char *eevee_get_frag(int options) return str; } -static void eevee_material_post_eval(GPUMaterial *mat, - int options, - const char **UNUSED(vert_code), - const char **geom_code, - const char **UNUSED(frag_lib), - const char **UNUSED(defines)) +static void eevee_material_post_eval(void *UNUSED(thunk), + GPUMaterial *mat, + GPUCodegenOutput *codegen) { - const bool is_hair = (options & VAR_MAT_HAIR) != 0; - const bool is_mesh = (options & VAR_MAT_MESH) != 0; + uint64_t options = GPU_material_uuid_get(mat); - /* Force geometry usage if GPU_BARYCENTRIC_DIST or GPU_BARYCENTRIC_TEXCO are used. - * NOTE: GPU_BARYCENTRIC_TEXCO only requires it if the shader is not drawing hairs. */ - if (!is_hair && is_mesh && GPU_material_flag_get(mat, GPU_MATFLAG_BARYCENTRIC) && - *geom_code == NULL) { - *geom_code = e_data.surface_geom_barycentric; - } + char *vert = eevee_get_vert(options); + char *geom = eevee_get_geom(options); + char *frag = eevee_get_frag(options); + char *defines = eevee_get_defines(options); + + eevee_shader_material_create_info_amend(mat, codegen, frag, vert, geom, defines); + + MEM_SAFE_FREE(defines); + MEM_SAFE_FREE(vert); + MEM_SAFE_FREE(geom); + MEM_SAFE_FREE(frag); } static struct GPUMaterial *eevee_material_get_ex( - struct Scene *scene, Material *ma, World *wo, int options, bool deferred) + struct Scene *UNUSED(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; + GPUCodegenCallbackFn cbfn = &eevee_material_post_eval; 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) { - GPUMaterialEvalCallbackFn cbfn = &eevee_material_post_eval; - 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, cbfn); + mat = DRW_shader_from_material(ma, ntree, options, is_volume, deferred, cbfn, NULL); } 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, NULL); + mat = DRW_shader_from_world(wo, ntree, options, is_volume, deferred, cbfn, NULL); } - - MEM_SAFE_FREE(defines); - MEM_SAFE_FREE(vert); - MEM_SAFE_FREE(geom); - MEM_SAFE_FREE(frag); - return mat; } @@ -1520,6 +1507,7 @@ struct GPUMaterial *EEVEE_material_get( void EEVEE_shaders_free(void) { + eevee_shader_extra_exit(); MEM_SAFE_FREE(e_data.surface_prepass_frag); MEM_SAFE_FREE(e_data.surface_lit_frag); MEM_SAFE_FREE(e_data.surface_geom_barycentric); diff --git a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc new file mode 100644 index 00000000000..1d3e07217b5 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc @@ -0,0 +1,173 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. */ + +/** \file + * \ingroup EEVEE + * + * This file is only there to handle ShaderCreateInfos. + */ + +#include "GPU_shader.h" + +#include "BLI_string_ref.hh" + +#include "gpu_shader_create_info.hh" + +#include "eevee_private.h" + +using blender::gpu::shader::StageInterfaceInfo; + +static StageInterfaceInfo *stage_interface = nullptr; + +void eevee_shader_extra_init() +{ + if (stage_interface != nullptr) { + return; + } + + using namespace blender::gpu::shader; + stage_interface = new StageInterfaceInfo("ShaderStageInterface", ""); + stage_interface->smooth(Type::VEC3, "worldPosition"); + stage_interface->smooth(Type::VEC3, "viewPosition"); + stage_interface->smooth(Type::VEC3, "worldNormal"); + stage_interface->smooth(Type::VEC3, "viewNormal"); + stage_interface->flat(Type::INT, "resourceIDFrag"); +} + +void eevee_shader_extra_exit() +{ + delete stage_interface; +} + +void eevee_shader_material_create_info_amend(GPUMaterial *gpumat, + GPUCodegenOutput *codegen_, + char *frag, + char *vert, + char *geom, + char *defines) +{ + using namespace blender::gpu::shader; + + uint64_t options = GPU_material_uuid_get(gpumat); + const bool is_background = (options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0; + const bool is_volume = (options & (VAR_MAT_VOLUME)) != 0; + const bool is_hair = (options & (VAR_MAT_HAIR)) != 0; + const bool is_mesh = (options & (VAR_MAT_MESH)) != 0; + const bool is_point_cloud = (options & (VAR_MAT_POINTCLOUD)) != 0; + + GPUCodegenOutput &codegen = *codegen_; + ShaderCreateInfo &info = *reinterpret_cast(codegen.create_info); + + info.legacy_resource_location(true); + info.auto_resource_location(true); + + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE)) { + info.define("USE_SSS"); + } + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SHADER_TO_RGBA)) { + info.define("USE_SHADER_TO_RGBA"); + } + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_BARYCENTRIC) && !is_volume && !is_hair && + !is_point_cloud && !is_background) { + info.define("USE_BARYCENTRICS"); + info.builtins(BuiltinBits::BARYCENTRIC_COORD); + } + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_BARYCENTRIC) && is_hair) { + info.define("USE_BARYCENTRICS"); + } + + std::stringstream attr_load; + + const bool do_fragment_attrib_load = is_background || is_volume; + + if (is_hair && !info.vertex_out_interfaces_.is_empty()) { + /** Hair attributes comme from sampler buffer. Transfer attributes to sampler. */ + for (auto &input : info.vertex_inputs_) { + info.sampler(0, ImageType::FLOAT_BUFFER, input.name, Frequency::BATCH); + } + info.vertex_inputs_.clear(); + } + else if (do_fragment_attrib_load && !info.vertex_out_interfaces_.is_empty()) { + /* Codegen outputs only one interface. */ + const StageInterfaceInfo &iface = *info.vertex_out_interfaces_.first(); + /* Globals the attrib_load() can write to when it is in the fragment shader. */ + attr_load << "struct " << iface.name << " {\n"; + for (auto &inout : iface.inouts) { + attr_load << " " << inout.type << " " << inout.name << ";\n"; + } + attr_load << "};\n"; + attr_load << iface.name << " " << iface.instance_name << ";\n"; + /* Global vars just to make code valid. Only Orco is supported. */ + for (const ShaderCreateInfo::VertIn &in : info.vertex_inputs_) { + attr_load << in.type << " " << in.name << ";\n"; + } + info.vertex_out_interfaces_.clear(); + } + + if (!is_volume) { + info.define("EEVEE_GENERATED_INTERFACE"); + info.vertex_out(*stage_interface); + } + + attr_load << "void attrib_load()\n"; + attr_load << "{\n"; + attr_load << ((codegen.attr_load) ? codegen.attr_load : ""); + attr_load << "}\n\n"; + + std::stringstream vert_gen, frag_gen, geom_gen; + + if (do_fragment_attrib_load) { + frag_gen << attr_load.str(); + } + else { + vert_gen << attr_load.str(); + } + + { + vert_gen << vert; + info.vertex_source_generated = vert_gen.str(); + /* Everything is in generated source. */ + info.vertex_source(is_volume ? "eevee_empty_volume.glsl" : "eevee_empty.glsl"); + } + + { + frag_gen << frag; + if (codegen.material_functions) { + frag_gen << codegen.material_functions; + } + frag_gen << "Closure nodetree_exec()\n"; + frag_gen << "{\n"; + if (GPU_material_is_volume_shader(gpumat)) { + frag_gen << ((codegen.volume) ? codegen.volume : "return CLOSURE_DEFAULT;\n"); + } + else { + frag_gen << ((codegen.surface) ? codegen.surface : "return CLOSURE_DEFAULT;\n"); + } + frag_gen << "}\n\n"; + + if (codegen.displacement && (is_hair || is_mesh)) { + info.define("EEVEE_DISPLACEMENT_BUMP"); + + frag_gen << "vec3 displacement_exec()\n"; + frag_gen << "{\n"; + frag_gen << codegen.displacement; + frag_gen << "}\n\n"; + } + + info.fragment_source_generated = frag_gen.str(); + /* Everything is in generated source. */ + info.fragment_source(is_volume ? "eevee_empty_volume.glsl" : "eevee_empty.glsl"); + } + + if (geom) { + geom_gen << geom; + info.geometry_source_generated = geom_gen.str(); + info.geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3); + /* Everything is in generated source. */ + info.geometry_source("eevee_empty.glsl"); + } + + if (defines) { + info.typedef_source_generated += blender::StringRefNull(defines); + } +} diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 7d210f15d8b..6a0c9fb36df 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -604,6 +604,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 4da30dd74ee..d8adf302e37 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -26,6 +26,10 @@ # endif #endif +#ifndef GPU_FRAGMENT_SHADER +# define gl_FragCoord vec4(0.0) +#endif + uniform sampler2D horizonBuffer; /* aoSettings flags */ @@ -424,3 +428,34 @@ OcclusionData occlusion_load(vec3 vP, float custom_occlusion) return data; } + +#ifndef GPU_FRAGMENT_SHADER +# undef gl_FragCoord +#endif + +float ambient_occlusion_eval(vec3 normal, + float max_distance, + const float inverted, + const float sample_count) +{ + /* Avoid multiline define causing compiler issues. */ + /* clang-format off */ +#if defined(GPU_FRAGMENT_SHADER) && (defined(MESH_SHADER) || defined(HAIR_SHADER)) && !defined(DEPTH_SHADER) && !defined(VOLUMETRICS) + /* clang-format on */ + vec3 bent_normal; + vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); + OcclusionData data = occlusion_search( + viewPosition, maxzBuffer, max_distance, inverted, sample_count); + + vec3 V = cameraVec(worldPosition); + vec3 N = normalize(normal); + vec3 Ng = safe_normalize(cross(dFdx(worldPosition), dFdy(worldPosition))); + + float unused_error, visibility; + vec3 unused; + occlusion_eval(data, V, N, Ng, inverted, visibility, unused_error, unused); + return visibility; +#else + return 1.0; +#endif +} diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl index 5cd82d298d5..574b24b3650 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl @@ -1,6 +1,8 @@ #pragma BLENDER_REQUIRE(lights_lib.glsl) #pragma BLENDER_REQUIRE(lightprobe_lib.glsl) #pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_lib.glsl) +#pragma BLENDER_REQUIRE(renderpass_lib.glsl) struct ClosureInputDiffuse { vec3 N; /** Shading normal. */ @@ -88,6 +90,7 @@ void closure_Diffuse_eval_end(ClosureInputDiffuse cl_in, ClosureEvalCommon cl_common, inout ClosureOutputDiffuse cl_out) { + cl_out.radiance = render_pass_diffuse_mask(cl_out.radiance); #if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ cl_out.radiance = vec3(0.0); diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl index 4271ac9105b..0deaf4054d2 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl @@ -4,6 +4,8 @@ #pragma BLENDER_REQUIRE(lightprobe_lib.glsl) #pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) #pragma BLENDER_REQUIRE(bsdf_common_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_lib.glsl) +#pragma BLENDER_REQUIRE(renderpass_lib.glsl) struct ClosureInputGlossy { vec3 N; /** Shading normal. */ @@ -143,6 +145,7 @@ void closure_Glossy_eval_end(ClosureInputGlossy cl_in, ClosureEvalCommon cl_common, inout ClosureOutputGlossy cl_out) { + cl_out.radiance = render_pass_glossy_mask(cl_out.radiance); #if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ cl_out.radiance = vec3(0.0); diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl index a96d8ad3dac..3f07f80571a 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl @@ -1,8 +1,14 @@ #pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) +// #pragma (gpu_shader_codegen_lib.glsl) #pragma BLENDER_REQUIRE(lights_lib.glsl) #pragma BLENDER_REQUIRE(lightprobe_lib.glsl) +#ifndef GPU_FRAGMENT_SHADER +# define gl_FragCoord vec4(0.0) +# define gl_FrontFacing true +#endif + /** * Extensive use of Macros to be able to change the maximum amount of evaluated closure easily. * NOTE: GLSL does not support variadic macros. @@ -240,7 +246,11 @@ ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in) cl_eval.N = safe_normalize(gl_FrontFacing ? worldNormal : -worldNormal); cl_eval.vN = safe_normalize(gl_FrontFacing ? viewNormal : -viewNormal); cl_eval.vP = viewPosition; +#ifdef GPU_FRAGMENT_SHADER cl_eval.Ng = safe_normalize(cross(dFdx(cl_eval.P), dFdy(cl_eval.P))); +#else + cl_eval.Ng = cl_eval.N; +#endif cl_eval.vNg = transform_direction(ViewMatrix, cl_eval.Ng); cl_eval.occlusion_data = occlusion_load(cl_eval.vP, cl_in.occlusion); @@ -337,3 +347,8 @@ ClosureGridData closure_grid_eval_init(int id, inout ClosureEvalCommon cl_common } /** \} */ + +#ifndef GPU_FRAGMENT_SHADER +# undef gl_FragCoord +# undef gl_FrontFacing +#endif diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl index 8129988920c..5c6769b185a 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl @@ -4,6 +4,8 @@ #pragma BLENDER_REQUIRE(lightprobe_lib.glsl) #pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) #pragma BLENDER_REQUIRE(ssr_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_lib.glsl) +#pragma BLENDER_REQUIRE(renderpass_lib.glsl) struct ClosureInputRefraction { vec3 N; /** Shading normal. */ @@ -123,6 +125,7 @@ void closure_Refraction_eval_end(ClosureInputRefraction cl_in, ClosureEvalCommon cl_common, inout ClosureOutputRefraction cl_out) { + cl_out.radiance = render_pass_glossy_mask(cl_out.radiance); #if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ cl_out.radiance = vec3(0.0); diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl new file mode 100644 index 00000000000..fa94b5ed272 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl @@ -0,0 +1,325 @@ + +#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl) +#pragma BLENDER_REQUIRE(renderpass_lib.glsl) + +#ifdef USE_SHADER_TO_RGBA +bool do_sss = false; +bool do_ssr = false; +#else +bool do_sss = true; +bool do_ssr = true; +#endif + +vec3 out_sss_radiance; +vec3 out_sss_color; +float out_sss_radius; + +float out_ssr_roughness; +vec3 out_ssr_color; +vec3 out_ssr_N; + +bool aov_is_valid = false; +vec3 out_aov; + +bool output_sss(ClosureDiffuse diffuse, ClosureOutputDiffuse diffuse_out) +{ + if (diffuse.sss_id == 0u || !do_sss || !sssToggle || outputSssId == 0) { + return false; + } + if (renderPassSSSColor) { + return false; + } + out_sss_radiance = diffuse_out.radiance; + out_sss_color = diffuse.color * diffuse.weight; + out_sss_radius = avg(diffuse.sss_radius); + do_sss = false; + return true; +} + +bool output_ssr(ClosureReflection reflection) +{ + if (!do_ssr || !ssrToggle || outputSsrId == 0) { + return false; + } + out_ssr_roughness = reflection.roughness; + out_ssr_color = reflection.color * reflection.weight; + out_ssr_N = reflection.N; + do_ssr = false; + return true; +} + +void output_aov(vec4 color, float value, uint hash) +{ + /* Keep in sync with `render_pass_aov_hash` and `EEVEE_renderpasses_aov_hash`. */ + hash <<= 1u; + + if (renderPassAOV && !aov_is_valid && hash == render_pass_aov_hash()) { + aov_is_valid = true; + if (render_pass_aov_is_color()) { + out_aov = color.rgb; + } + else { + out_aov = vec3(value); + } + } +} + +/* Single BSDFs. */ +CLOSURE_EVAL_FUNCTION_DECLARE_1(DiffuseBSDF, Diffuse) +Closure closure_eval(ClosureDiffuse diffuse) +{ + /* Glue with the old system. */ + CLOSURE_VARS_DECLARE_1(Diffuse); + + in_Diffuse_0.N = diffuse.N; + in_Diffuse_0.albedo = diffuse.color; + + CLOSURE_EVAL_FUNCTION_1(DiffuseBSDF, Diffuse); + + Closure closure = CLOSURE_DEFAULT; + if (!output_sss(diffuse, out_Diffuse_0)) { + closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight; + } + return closure; +} + +CLOSURE_EVAL_FUNCTION_DECLARE_1(TranslucentBSDF, Translucent) +Closure closure_eval(ClosureTranslucent translucent) +{ + /* Glue with the old system. */ + CLOSURE_VARS_DECLARE_1(Translucent); + + in_Translucent_0.N = translucent.N; + + CLOSURE_EVAL_FUNCTION_1(TranslucentBSDF, Translucent); + + Closure closure = CLOSURE_DEFAULT; + closure.radiance += out_Translucent_0.radiance * translucent.color * translucent.weight; + return closure; +} + +CLOSURE_EVAL_FUNCTION_DECLARE_1(GlossyBSDF, Glossy) +Closure closure_eval(ClosureReflection reflection) +{ + /* Glue with the old system. */ + CLOSURE_VARS_DECLARE_1(Glossy); + + in_Glossy_0.N = reflection.N; + in_Glossy_0.roughness = reflection.roughness; + + CLOSURE_EVAL_FUNCTION_1(GlossyBSDF, Glossy); + + Closure closure = CLOSURE_DEFAULT; + if (!output_ssr(reflection)) { + closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight; + } + return closure; +} + +CLOSURE_EVAL_FUNCTION_DECLARE_1(RefractionBSDF, Refraction) +Closure closure_eval(ClosureRefraction refraction) +{ + /* Glue with the old system. */ + CLOSURE_VARS_DECLARE_1(Refraction); + + in_Refraction_0.N = refraction.N; + in_Refraction_0.roughness = refraction.roughness; + in_Refraction_0.ior = refraction.ior; + + CLOSURE_EVAL_FUNCTION_1(RefractionBSDF, Refraction); + + Closure closure = CLOSURE_DEFAULT; + closure.radiance += out_Refraction_0.radiance * refraction.color * refraction.weight; + return closure; +} + +Closure closure_eval(ClosureEmission emission) +{ + Closure closure = CLOSURE_DEFAULT; + closure.radiance += render_pass_emission_mask(emission.emission) * emission.weight; + return closure; +} + +Closure closure_eval(ClosureTransparency transparency) +{ + Closure closure = CLOSURE_DEFAULT; + closure.transmittance += transparency.transmittance * transparency.weight; + closure.holdout += transparency.holdout * transparency.weight; + return closure; +} + +/* Glass BSDF. */ +CLOSURE_EVAL_FUNCTION_DECLARE_2(GlassBSDF, Glossy, Refraction) +Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction) +{ + /* Glue with the old system. */ + CLOSURE_VARS_DECLARE_2(Glossy, Refraction); + + in_Glossy_0.N = reflection.N; + in_Glossy_0.roughness = reflection.roughness; + in_Refraction_1.N = refraction.N; + in_Refraction_1.roughness = refraction.roughness; + in_Refraction_1.ior = refraction.ior; + + CLOSURE_EVAL_FUNCTION_2(GlassBSDF, Glossy, Refraction); + + Closure closure = CLOSURE_DEFAULT; + closure.radiance += out_Refraction_1.radiance * refraction.color * refraction.weight; + if (!output_ssr(reflection)) { + closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight; + } + return closure; +} + +/* Dielectric BSDF */ +CLOSURE_EVAL_FUNCTION_DECLARE_2(DielectricBSDF, Diffuse, Glossy) +Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection) +{ + /* Glue with the old system. */ + CLOSURE_VARS_DECLARE_2(Diffuse, Glossy); + + in_Diffuse_0.N = diffuse.N; + in_Diffuse_0.albedo = diffuse.color; + in_Glossy_1.N = reflection.N; + in_Glossy_1.roughness = reflection.roughness; + + CLOSURE_EVAL_FUNCTION_2(DielectricBSDF, Diffuse, Glossy); + + Closure closure = CLOSURE_DEFAULT; + if (!output_sss(diffuse, out_Diffuse_0)) { + closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight; + } + if (!output_ssr(reflection)) { + closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight; + } + return closure; +} + +/* Specular BSDF */ +CLOSURE_EVAL_FUNCTION_DECLARE_3(SpecularBSDF, Diffuse, Glossy, Glossy) +Closure closure_eval(ClosureDiffuse diffuse, + ClosureReflection reflection, + ClosureReflection clearcoat) +{ + /* Glue with the old system. */ + CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy); + + in_Diffuse_0.N = diffuse.N; + in_Diffuse_0.albedo = diffuse.color; + in_Glossy_1.N = reflection.N; + in_Glossy_1.roughness = reflection.roughness; + in_Glossy_2.N = clearcoat.N; + in_Glossy_2.roughness = clearcoat.roughness; + + CLOSURE_EVAL_FUNCTION_3(SpecularBSDF, Diffuse, Glossy, Glossy); + + Closure closure = CLOSURE_DEFAULT; + if (!output_sss(diffuse, out_Diffuse_0)) { + closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight; + } + closure.radiance += out_Glossy_2.radiance * clearcoat.color * clearcoat.weight; + if (!output_ssr(reflection)) { + closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight; + } + return closure; +} + +/* Principled BSDF */ +CLOSURE_EVAL_FUNCTION_DECLARE_4(PrincipledBSDF, Diffuse, Glossy, Glossy, Refraction) +Closure closure_eval(ClosureDiffuse diffuse, + ClosureReflection reflection, + ClosureReflection clearcoat, + ClosureRefraction refraction) +{ + /* Glue with the old system. */ + CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction); + + in_Diffuse_0.N = diffuse.N; + in_Diffuse_0.albedo = diffuse.color; + in_Glossy_1.N = reflection.N; + in_Glossy_1.roughness = reflection.roughness; + in_Glossy_2.N = clearcoat.N; + in_Glossy_2.roughness = clearcoat.roughness; + in_Refraction_3.N = refraction.N; + in_Refraction_3.roughness = refraction.roughness; + in_Refraction_3.ior = refraction.ior; + + CLOSURE_EVAL_FUNCTION_4(PrincipledBSDF, Diffuse, Glossy, Glossy, Refraction); + + Closure closure = CLOSURE_DEFAULT; + closure.radiance += out_Glossy_2.radiance * clearcoat.color * clearcoat.weight; + closure.radiance += out_Refraction_3.radiance * refraction.color * refraction.weight; + if (!output_sss(diffuse, out_Diffuse_0)) { + closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight; + } + if (!output_ssr(reflection)) { + closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight; + } + return closure; +} + +CLOSURE_EVAL_FUNCTION_DECLARE_2(PrincipledBSDFMetalClearCoat, Glossy, Glossy) +Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat) +{ + /* Glue with the old system. */ + CLOSURE_VARS_DECLARE_2(Glossy, Glossy); + + in_Glossy_0.N = reflection.N; + in_Glossy_0.roughness = reflection.roughness; + in_Glossy_1.N = clearcoat.N; + in_Glossy_1.roughness = clearcoat.roughness; + + CLOSURE_EVAL_FUNCTION_2(PrincipledBSDFMetalClearCoat, Glossy, Glossy); + + Closure closure = CLOSURE_DEFAULT; + closure.radiance += out_Glossy_1.radiance * clearcoat.color * clearcoat.weight; + if (!output_ssr(reflection)) { + closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight; + } + return closure; +} + +/* Not supported for surface shaders. */ +Closure closure_eval(ClosureVolumeScatter volume_scatter) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureVolumeAbsorption volume_absorption) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureVolumeScatter volume_scatter, + ClosureVolumeAbsorption volume_absorption, + ClosureEmission emission) +{ + return CLOSURE_DEFAULT; +} + +/* Not implemented yet. */ +Closure closure_eval(ClosureHair hair) +{ + return CLOSURE_DEFAULT; +} + +vec4 closure_to_rgba(Closure closure) +{ + return vec4(closure.radiance, 1.0 - saturate(avg(closure.transmittance))); +} + +Closure closure_add(Closure cl1, Closure cl2) +{ + Closure cl; + cl.radiance = cl1.radiance + cl2.radiance; + cl.transmittance = cl1.transmittance + cl2.transmittance; + cl.holdout = cl1.holdout + cl2.holdout; + return cl; +} + +Closure closure_mix(Closure cl1, Closure cl2, float fac) +{ + /* Weights have already been applied. */ + return closure_add(cl1, cl2); +} diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl index 706b75cb7f9..89a6f10e634 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl @@ -3,6 +3,8 @@ #pragma BLENDER_REQUIRE(lights_lib.glsl) #pragma BLENDER_REQUIRE(lightprobe_lib.glsl) #pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_lib.glsl) +#pragma BLENDER_REQUIRE(renderpass_lib.glsl) struct ClosureInputTranslucent { vec3 N; /** Shading normal. */ @@ -69,6 +71,7 @@ void closure_Translucent_eval_end(ClosureInputTranslucent cl_in, ClosureEvalCommon cl_common, inout ClosureOutputTranslucent cl_out) { + cl_out.radiance = render_pass_diffuse_mask(cl_out.radiance); #if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ cl_out.radiance = vec3(0.0); diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl new file mode 100644 index 00000000000..e450b8ad3c8 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl @@ -0,0 +1,113 @@ + +void output_aov(vec4 color, float value, uint hash) +{ + /* Unsupported. */ +} + +/* Surface BSDFs. */ +Closure closure_eval(ClosureDiffuse diffuse) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureTranslucent translucent) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureReflection reflection) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureRefraction refraction) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureEmission emission) +{ + Closure closure = CLOSURE_DEFAULT; + closure.emission = emission.emission; + return closure; +} +Closure closure_eval(ClosureTransparency transparency) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureDiffuse diffuse, + ClosureReflection reflection, + ClosureReflection clearcoat) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureDiffuse diffuse, + ClosureReflection reflection, + ClosureReflection clearcoat, + ClosureRefraction refraction) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat) +{ + return CLOSURE_DEFAULT; +} +Closure closure_eval(ClosureHair hair) +{ + return CLOSURE_DEFAULT; +} + +Closure closure_eval(ClosureVolumeScatter volume_scatter) +{ + Closure closure = CLOSURE_DEFAULT; + closure.scatter = volume_scatter.scattering; + closure.anisotropy = volume_scatter.anisotropy; + return closure; +} +Closure closure_eval(ClosureVolumeAbsorption volume_absorption) +{ + Closure closure = CLOSURE_DEFAULT; + closure.absorption = volume_absorption.absorption; + return closure; +} +Closure closure_eval(ClosureVolumeScatter volume_scatter, + ClosureVolumeAbsorption volume_absorption, + ClosureEmission emission) +{ + Closure closure = CLOSURE_DEFAULT; + closure.absorption = volume_absorption.absorption; + closure.scatter = volume_scatter.scattering; + closure.anisotropy = volume_scatter.anisotropy; + closure.emission = emission.emission; + return closure; +} + +vec4 closure_to_rgba(Closure closure) +{ + /* Not supported */ + return vec4(0.0); +} + +Closure closure_mix(Closure cl1, Closure cl2, float fac) +{ + Closure cl; + cl.absorption = mix(cl1.absorption, cl2.absorption, fac); + cl.scatter = mix(cl1.scatter, cl2.scatter, fac); + cl.emission = mix(cl1.emission, cl2.emission, fac); + cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac); + return cl; +} + +Closure closure_add(Closure cl1, Closure cl2) +{ + Closure cl; + cl.absorption = cl1.absorption + cl2.absorption; + cl.scatter = cl1.scatter + cl2.scatter; + cl.emission = cl1.emission + cl2.emission; + cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */ + return cl; +} diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl index 9022a9d3130..0096cd1747f 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl @@ -1,6 +1,8 @@ -#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) -#pragma BLENDER_REQUIRE(renderpass_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl) +/* #pragma (common_math_geom_lib.glsl) */ +/* #pragma (common_uniforms_lib.glsl) */ +/* #pragma (renderpass_lib.glsl) */ #ifndef VOLUMETRICS @@ -20,15 +22,6 @@ struct Closure { vec3 radiance; vec3 transmittance; float holdout; - vec4 ssr_data; - vec2 ssr_normal; - int flag; -# ifdef USE_SSS - vec3 sss_irradiance; - vec3 sss_albedo; - float sss_radius; -# endif - #endif /* Metal Default Constructor - Requred for C++ constructor syntax. */ @@ -45,191 +38,76 @@ struct Closure { } # else /* Explicit Closure constructors -- To support GLSL syntax */ - inline Closure(vec3 in_radiance, - vec3 in_transmittance, - float in_holdout, - vec4 in_ssr_data, - vec2 in_ssr_normal, - int in_flag -# ifdef USE_SSS - , - vec3 in_sss_irradiance, - vec3 in_sss_albedo, - float in_sss_radius -# endif /* USE_SSS */ - ) - : radiance(in_radiance), - transmittance(in_transmittance), - holdout(in_holdout), - ssr_data(in_ssr_data), - ssr_normal(in_ssr_normal), - flag(in_flag) -# ifdef USE_SSS - , - sss_irradiance(in_sss_irradiance), - sss_albedo(in_sss_albedo), - sss_radius(in_sss_radius) -# endif /* USE_SSS */ + inline Closure(vec3 in_radiance, vec3 in_transmittance, float in_holdout) + : radiance(in_radiance), transmittance(in_transmittance), holdout(in_holdout) { } -# endif /* VOLUMETRICS */ -#endif /* GPU_METAL */ +# endif /* VOLUMETRICS */ +#endif /* GPU_METAL */ }; #ifndef GPU_METAL /* Prototype */ -Closure nodetree_exec(void); +Closure nodetree_exec(); +vec4 closure_to_rgba(Closure); +void output_aov(vec4 color, float value, uint hash); +vec3 coordinate_camera(vec3 P); +vec3 coordinate_screen(vec3 P); +vec3 coordinate_reflect(vec3 P, vec3 N); +vec3 coordinate_incoming(vec3 P); + +/* Single BSDFs. */ +Closure closure_eval(ClosureDiffuse diffuse); +Closure closure_eval(ClosureTranslucent translucent); +Closure closure_eval(ClosureReflection reflection); +Closure closure_eval(ClosureRefraction refraction); +Closure closure_eval(ClosureEmission emission); +Closure closure_eval(ClosureTransparency transparency); +Closure closure_eval(ClosureVolumeScatter volume_scatter); +Closure closure_eval(ClosureVolumeAbsorption volume_absorption); +Closure closure_eval(ClosureHair hair); + +/* Glass BSDF. */ +Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction); +/* Dielectric BSDF. */ +Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection); +/* ClearCoat BSDF. */ +Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat); +/* Volume BSDF. */ +Closure closure_eval(ClosureVolumeScatter volume_scatter, + ClosureVolumeAbsorption volume_absorption, + ClosureEmission emission); +/* Specular BSDF. */ +Closure closure_eval(ClosureDiffuse diffuse, + ClosureReflection reflection, + ClosureReflection clearcoat); +/* Principled BSDF. */ +Closure closure_eval(ClosureDiffuse diffuse, + ClosureReflection reflection, + ClosureReflection clearcoat, + ClosureRefraction refraction); + +Closure closure_add(Closure cl1, Closure cl2); +Closure closure_mix(Closure cl1, Closure cl2, float fac); + +float ambient_occlusion_eval(vec3 normal, + float distance, + const float inverted, + const float sample_count); + +/* WORKAROUND: Included later with libs. This is because we are mixing include systems. */ +vec3 safe_normalize(vec3 N); +float fast_sqrt(float a); +vec3 cameraVec(vec3 P); +vec2 btdf_lut(float a, float b, float c); +vec2 brdf_lut(float a, float b); +vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c); +vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c); +float F_eta(float a, float b); #endif -/* clang-format off */ -/* Avoid multi-line defines. */ #ifdef VOLUMETRICS # define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), vec3(0), 0.0) -#elif !defined(USE_SSS) -# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), 0.0, vec4(0), vec2(0), 0) #else -# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), 0.0, vec4(0), vec2(0), 0, vec3(0), vec3(0), 0.0) -#endif -/* clang-format on */ - -#define FLAG_TEST(flag, val) (((flag) & (val)) != 0) - -#define CLOSURE_SSR_FLAG 1 -#define CLOSURE_SSS_FLAG 2 -#define CLOSURE_HOLDOUT_FLAG 4 - -#ifdef VOLUMETRICS -Closure closure_mix(Closure cl1, Closure cl2, float fac) -{ - Closure cl; - cl.absorption = mix(cl1.absorption, cl2.absorption, fac); - cl.scatter = mix(cl1.scatter, cl2.scatter, fac); - cl.emission = mix(cl1.emission, cl2.emission, fac); - cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac); - return cl; -} - -Closure closure_add(Closure cl1, Closure cl2) -{ - Closure cl; - cl.absorption = cl1.absorption + cl2.absorption; - cl.scatter = cl1.scatter + cl2.scatter; - cl.emission = cl1.emission + cl2.emission; - cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */ - return cl; -} - -Closure closure_emission(vec3 rgb) -{ - Closure cl = CLOSURE_DEFAULT; - cl.emission = rgb; - return cl; -} - -#else /* SURFACE */ - -Closure closure_mix(Closure cl1, Closure cl2, float fac) -{ - Closure cl; - cl.holdout = mix(cl1.holdout, cl2.holdout, fac); - - if (FLAG_TEST(cl1.flag, CLOSURE_HOLDOUT_FLAG)) { - fac = 1.0; - } - else if (FLAG_TEST(cl2.flag, CLOSURE_HOLDOUT_FLAG)) { - fac = 0.0; - } - - cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac); - cl.radiance = mix(cl1.radiance, cl2.radiance, fac); - cl.flag = cl1.flag | cl2.flag; - cl.ssr_data = mix(cl1.ssr_data, cl2.ssr_data, fac); - bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG); - /* When mixing SSR don't blend roughness and normals but only specular (ssr_data.xyz). */ - cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w; - cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal; - -# ifdef USE_SSS - cl.sss_albedo = mix(cl1.sss_albedo, cl2.sss_albedo, fac); - bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG); - /* It also does not make sense to mix SSS radius or irradiance. */ - cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius; - cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance; -# endif - return cl; -} - -Closure closure_add(Closure cl1, Closure cl2) -{ - Closure cl; - cl.transmittance = cl1.transmittance + cl2.transmittance; - cl.radiance = cl1.radiance + cl2.radiance; - cl.holdout = cl1.holdout + cl2.holdout; - cl.flag = cl1.flag | cl2.flag; - cl.ssr_data = cl1.ssr_data + cl2.ssr_data; - bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG); - /* When mixing SSR don't blend roughness and normals. */ - cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w; - cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal; - -# ifdef USE_SSS - cl.sss_albedo = cl1.sss_albedo + cl2.sss_albedo; - bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG); - /* It also does not make sense to mix SSS radius or irradiance. */ - cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius; - cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance; -# endif - return cl; -} - -Closure closure_emission(vec3 rgb) -{ - Closure cl = CLOSURE_DEFAULT; - cl.radiance = rgb; - return cl; -} - -#endif - -#ifndef VOLUMETRICS - -/* Let radiance passthrough or replace it to get the BRDF and color - * to applied to the SSR result. */ -vec3 closure_mask_ssr_radiance(vec3 radiance, float ssr_id) -{ - return (ssrToggle && int(ssr_id) == outputSsrId) ? vec3(1.0) : radiance; -} - -void closure_load_ssr_data( - vec3 ssr_radiance, float roughness, vec3 N, float ssr_id, inout Closure cl) -{ - /* Still encode to avoid artifacts in the SSR pass. */ - vec3 vN = normalize(mat3(ViewMatrix) * N); - cl.ssr_normal = normal_encode(vN, viewCameraVec(viewPosition)); - - if (ssrToggle && int(ssr_id) == outputSsrId) { - cl.ssr_data = vec4(ssr_radiance, roughness); - cl.flag |= CLOSURE_SSR_FLAG; - } - else { - cl.radiance += ssr_radiance; - } -} - -void closure_load_sss_data( - float radius, vec3 sss_irradiance, vec3 sss_albedo, int sss_id, inout Closure cl) -{ -# ifdef USE_SSS - if (sss_id == outputSssId) { - cl.sss_irradiance = sss_irradiance; - cl.sss_radius = radius; - cl.sss_albedo = sss_albedo; - cl.flag |= CLOSURE_SSS_FLAG; - /* Irradiance will be convolved by SSSS pass. Do not add to radiance. */ - sss_irradiance = vec3(0); - } -# endif - cl.radiance += render_pass_diffuse_mask(vec3(1), sss_irradiance) * sss_albedo; -} - +# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), 0.0) #endif diff --git a/source/blender/draw/engines/eevee/shaders/eevee_empty.glsl b/source/blender/draw/engines/eevee/shaders/eevee_empty.glsl new file mode 100644 index 00000000000..e00bcc4e557 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/eevee_empty.glsl @@ -0,0 +1,7 @@ + +/* Empty GLSL source to satisfy the GPUShaderCreateInfo requirements. */ +/* Needed includes for shader nodes. */ +#pragma BLENDER_REQUIRE(closure_type_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_attribute_lib.glsl) diff --git a/source/blender/draw/engines/eevee/shaders/eevee_empty_volume.glsl b/source/blender/draw/engines/eevee/shaders/eevee_empty_volume.glsl new file mode 100644 index 00000000000..a748c0092b6 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/eevee_empty_volume.glsl @@ -0,0 +1,8 @@ + +/* Empty GLSL source to satisfy the GPUShaderCreateInfo requirements. */ +/* Needed includes for shader nodes. */ +#pragma BLENDER_REQUIRE(closure_type_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_attribute_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_volume_lib.glsl) diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 1aff93e01f8..e86c5e06c99 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -11,6 +11,7 @@ layout(std140) uniform sssProfile { vec4 sss_kernel[MAX_SSS_SAMPLES]; vec4 radii_max_radius; + float avg_inv_radius; int sss_samples; }; @@ -26,7 +27,7 @@ void main(void) vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO: precompute. */ vec2 uvs = gl_FragCoord.xy * pixel_size; vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb; - float sss_radius = texture(sssRadius, uvs).r * radii_max_radius.w; + float sss_radius = texture(sssRadius, uvs).r * radii_max_radius.w * avg_inv_radius; float depth = texture(depthBuffer, uvs).r; float depth_view = get_view_z_from_depth(depth); diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl index 3cf21dc32d1..5e1725ace97 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl @@ -23,12 +23,13 @@ layout(std140) uniform sssProfile { vec4 sss_kernel[MAX_SSS_SAMPLES]; vec4 radii_max_radius; + float avg_inv_radius; int sss_samples; }; vec3 sss_profile(float s) { - s /= radii_max_radius.w; + s /= radii_max_radius.w * avg_inv_radius; return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb; } diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl index fd08dfda060..c8eea8d7860 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl @@ -2,15 +2,12 @@ /* Required by some nodes. */ #pragma BLENDER_REQUIRE(common_hair_lib.glsl) #pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(common_uniforms_lib.glsl) -#pragma BLENDER_REQUIRE(closure_type_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_surface_lib.glsl) #pragma BLENDER_REQUIRE(surface_lib.glsl) #ifdef USE_ALPHA_HASH @@ -73,6 +70,7 @@ float hashed_alpha_threshold(vec3 co) void main() { #if defined(USE_ALPHA_HASH) + g_data = init_globals(); Closure cl = nodetree_exec(); diff --git a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl deleted file mode 100644 index f650e2eeb8c..00000000000 --- a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl +++ /dev/null @@ -1,35 +0,0 @@ - -#pragma BLENDER_REQUIRE(common_hair_lib.glsl) -#pragma BLENDER_REQUIRE(common_view_lib.glsl) - -#ifndef HAIR_SHADER -in vec3 pos; -#endif - -void main() -{ - GPU_INTEL_VERTEX_SHADER_WORKAROUND - -#ifdef HAIR_SHADER - float time, thick_time, thickness; - vec3 worldPosition, tan, binor; - hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0), - ModelMatrixInverse, - ViewMatrixInverse[3].xyz, - ViewMatrixInverse[2].xyz, - worldPosition, - tan, - binor, - time, - thickness, - thick_time); -#else - vec3 worldPosition = point_object_to_world(pos); -#endif - - gl_Position = point_world_to_ndc(worldPosition); - -#ifdef CLIP_PLANES - gl_ClipDistance[0] = dot(vec4(worldPosition.xyz, 1.0), clipPlanes[0]); -#endif -} diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl index 3e0a5e76d00..f276e4f26ca 100644 --- a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl @@ -1,4 +1,4 @@ -#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1 +#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1u /* ---------------------------------------------------------------------- */ /** \name Resources @@ -14,7 +14,7 @@ layout(std140) uniform renderpass_block bool renderPassSSSColor; bool renderPassEnvironment; bool renderPassAOV; - int renderPassAOVActive; + uint renderPassAOVActive; }; /** \} */ @@ -23,19 +23,14 @@ layout(std140) uniform renderpass_block /** \name Functions * \{ */ -vec3 render_pass_diffuse_mask(vec3 diffuse_color, vec3 diffuse_light) +vec3 render_pass_diffuse_mask(vec3 diffuse_light) { - return renderPassDiffuse ? (renderPassDiffuseLight ? diffuse_light : diffuse_color) : vec3(0.0); + return renderPassDiffuse ? (renderPassDiffuseLight ? diffuse_light : vec3(1.0)) : vec3(0.0); } -vec3 render_pass_sss_mask(vec3 sss_color) +vec3 render_pass_glossy_mask(vec3 specular_light) { - return renderPassSSSColor ? sss_color : vec3(0.0); -} - -vec3 render_pass_glossy_mask(vec3 specular_color, vec3 specular_light) -{ - return renderPassGlossy ? (renderPassGlossyLight ? specular_light : specular_color) : vec3(0.0); + return renderPassGlossy ? (renderPassGlossyLight ? specular_light : vec3(1.0)) : vec3(0.0); } vec3 render_pass_emission_mask(vec3 emission_light) @@ -45,10 +40,10 @@ vec3 render_pass_emission_mask(vec3 emission_light) bool render_pass_aov_is_color() { - return (renderPassAOVActive & EEVEE_AOV_HASH_COLOR_TYPE_MASK) != 0; + return (renderPassAOVActive & EEVEE_AOV_HASH_COLOR_TYPE_MASK) != 0u; } -int render_pass_aov_hash() +uint render_pass_aov_hash() { return renderPassAOVActive & ~EEVEE_AOV_HASH_COLOR_TYPE_MASK; } diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl index cbfa9737a84..0e8e8dd9d01 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl @@ -1,5 +1,6 @@ #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) #pragma BLENDER_REQUIRE(common_hair_lib.glsl) #pragma BLENDER_REQUIRE(surface_lib.glsl) @@ -12,6 +13,7 @@ void main() #ifdef HAIR_SHADER hairStrandID = hair_get_strand_id(); + hairBary = hair_get_barycentric(); vec3 pos, binor; hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0), ModelMatrixInverse, @@ -52,3 +54,93 @@ void main() # endif #endif } + +#ifdef HAIR_SHADER +# ifdef OBINFO_LIB +vec3 attr_load_orco(samplerBuffer cd_buf) +{ + vec3 P = hair_get_strand_pos(); + vec3 lP = transform_point(ModelMatrixInverse, P); + return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz; +} +# endif + +vec4 attr_load_tangent(samplerBuffer cd_buf) +{ + /* Not supported. */ + return vec4(0.0, 0.0, 0.0, 1.0); +} + +vec3 attr_load_uv(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rgb; +} + +vec4 attr_load_color(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rgba; +} + +vec4 attr_load_vec4(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rgba; +} + +vec3 attr_load_vec3(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rgb; +} + +vec2 attr_load_vec2(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rg; +} + +float attr_load_float(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).r; +} + +#else + +# ifdef OBINFO_LIB +vec3 attr_load_orco(samplerBuffer cd_buf) +{ + vec3 P = hair_get_strand_pos(); + vec3 lP = transform_point(ModelMatrixInverse, P); + return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz; +} +# endif + +vec4 attr_load_tangent(vec4 tangent) +{ + tangent.xyz = safe_normalize(normal_object_to_world(tangent.xyz)); + return tangent; +} + +/* Simple passthrough. */ +vec4 attr_load_vec4(vec4 attr) +{ + return attr; +} +vec3 attr_load_vec3(vec3 attr) +{ + return attr; +} +vec2 attr_load_vec2(vec2 attr) +{ + return attr; +} +vec2 attr_load_float(vec2 attr) +{ + return attr; +} +vec4 attr_load_color(vec4 attr) +{ + return attr; +} +vec3 attr_load_uv(vec3 attr) +{ + return attr; +} +#endif diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl index 889bf439d5f..9ad7a4fdbc1 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl @@ -2,16 +2,14 @@ /* Required by some nodes. */ #pragma BLENDER_REQUIRE(common_hair_lib.glsl) #pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) -#pragma BLENDER_REQUIRE(closure_type_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl) -#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_surface_lib.glsl) #pragma BLENDER_REQUIRE(surface_lib.glsl) #pragma BLENDER_REQUIRE(volumetric_lib.glsl) +#pragma BLENDER_REQUIRE(renderpass_lib.glsl) #ifdef USE_ALPHA_BLEND /* Use dual source blending to be able to make a whole range of effects. */ @@ -22,18 +20,74 @@ layout(location = 0, index = 1) out vec4 outTransmittance; layout(location = 0) out vec4 outRadiance; layout(location = 1) out vec2 ssrNormals; layout(location = 2) out vec4 ssrData; -# ifdef USE_SSS layout(location = 3) out vec3 sssIrradiance; layout(location = 4) out float sssRadius; layout(location = 5) out vec3 sssAlbedo; + +#endif + +uniform float backgroundAlpha; + +#ifdef EEVEE_DISPLACEMENT_BUMP + +# ifndef GPU_METAL +/* Prototype. */ +vec3 displacement_exec(); # endif +/* Return new shading normal. */ +vec3 displacement_bump() +{ + vec2 dHd; + dF_branch(dot(displacement_exec(), g_data.N + dF_impl(g_data.N)), dHd); + + vec3 dPdx = dFdx(g_data.P); + vec3 dPdy = dFdy(g_data.P); + + /* Get surface tangents from normal. */ + vec3 Rx = cross(dPdy, g_data.N); + vec3 Ry = cross(g_data.N, dPdx); + + /* Compute surface gradient and determinant. */ + float det = dot(dPdx, Rx); + + vec3 surfgrad = dHd.x * Rx + dHd.y * Ry; + + float facing = FrontFacing ? 1.0 : -1.0; + return normalize(abs(det) * g_data.N - facing * sign(det) * surfgrad); +} + #endif void main() { + g_data = init_globals(); + +#ifdef EEVEE_DISPLACEMENT_BUMP + g_data.N = displacement_bump(); +#endif + +#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) + attrib_load(); +#endif + + out_ssr_color = vec3(0.0); + out_ssr_roughness = 0.0; + out_ssr_N = g_data.N; + + out_sss_radiance = vec3(0.0); + out_sss_radius = 0.0; + out_sss_color = vec3(0.0); + Closure cl = nodetree_exec(); +#ifdef WORLD_BACKGROUND + if (!renderPassEnvironment) { + cl.holdout += 1.0 - backgroundAlpha; + cl.radiance *= backgroundAlpha; + } +#endif + float holdout = saturate(1.0 - cl.holdout); float transmit = saturate(avg(cl.transmittance)); float alpha = 1.0 - transmit; @@ -53,38 +107,40 @@ void main() outTransmittance = vec4(cl.transmittance, transmit) * holdout; #else outRadiance = vec4(cl.radiance, holdout); - ssrNormals = cl.ssr_normal; - ssrData = cl.ssr_data; -# ifdef USE_SSS - sssIrradiance = cl.sss_irradiance; - sssRadius = cl.sss_radius; - sssAlbedo = cl.sss_albedo; -# endif + ssrNormals = normal_encode(normalize(mat3(ViewMatrix) * out_ssr_N), vec3(0.0)); + ssrData = vec4(out_ssr_color, out_ssr_roughness); + sssIrradiance = out_sss_radiance; + sssRadius = out_sss_radius; + sssAlbedo = out_sss_color; #endif - /* For Probe capture */ -#ifdef USE_SSS - float fac = float(!sssToggle); - - /* TODO(fclem): we shouldn't need this. - * Just disable USE_SSS when USE_REFRACTION is enabled. */ -# ifdef USE_REFRACTION +#ifdef USE_REFRACTION /* SSRefraction pass is done after the SSS pass. * In order to not lose the diffuse light totally we * need to merge the SSS radiance to the main radiance. */ - fac = 1.0; -# endif - - outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac; + const bool use_refraction = true; +#else + const bool use_refraction = false; #endif + /* For Probe capture */ + if (!sssToggle || use_refraction) { + outRadiance.rgb += out_sss_radiance * out_sss_color; + } #ifndef USE_ALPHA_BLEND float alpha_div = safe_rcp(alpha); outRadiance.rgb *= alpha_div; ssrData.rgb *= alpha_div; -# ifdef USE_SSS sssAlbedo.rgb *= alpha_div; -# endif + + if (renderPassAOV) { + if (aov_is_valid) { + outRadiance = vec4(out_aov, 1.0); + } + else { + outRadiance = vec4(0.0); + } + } #endif #ifdef LOOKDEV @@ -92,3 +148,34 @@ void main() gl_FragDepth = 0.0; #endif } + +/* Only supported attrib for world/background shaders. */ +vec3 attr_load_orco(vec4 orco) +{ + return g_data.P; +} +/* Unsupported. */ +vec4 attr_load_tangent(vec4 tangent) +{ + return vec4(0); +} +vec4 attr_load_vec4(vec4 attr) +{ + return vec4(0); +} +vec3 attr_load_vec3(vec3 attr) +{ + return vec3(0); +} +vec2 attr_load_vec2(vec2 attr) +{ + return vec2(0); +} +vec4 attr_load_color(vec4 attr) +{ + return vec4(0); +} +vec3 attr_load_uv(vec3 attr) +{ + return vec3(0); +} diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl index d7fc5e0b52a..1f2f7cb65cc 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl @@ -1,12 +1,23 @@ /** This describe the entire interface of the shader. */ +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + #define SURFACE_INTERFACE \ vec3 worldPosition; \ vec3 viewPosition; \ vec3 worldNormal; \ vec3 viewNormal; -#if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE) +#ifndef IN_OUT +# if defined(GPU_VERTEX_SHADER) +# define IN_OUT out +# elif defined(GPU_FRAGMENT_SHADER) +# define IN_OUT in +# endif +#endif + +#ifndef EEVEE_GENERATED_INTERFACE +# if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE) /* SSR will set these global variables itself. * Also make false positive compiler warnings disappear by setting values. */ vec3 worldPosition = vec3(0); @@ -14,22 +25,23 @@ vec3 viewPosition = vec3(0); vec3 worldNormal = vec3(0); vec3 viewNormal = vec3(0); -#elif defined(GPU_GEOMETRY_SHADER) +# elif defined(GPU_GEOMETRY_SHADER) in ShaderStageInterface{SURFACE_INTERFACE} dataIn[]; out ShaderStageInterface{SURFACE_INTERFACE} dataOut; -# define PASS_SURFACE_INTERFACE(vert) \ - dataOut.worldPosition = dataIn[vert].worldPosition; \ - dataOut.viewPosition = dataIn[vert].viewPosition; \ - dataOut.worldNormal = dataIn[vert].worldNormal; \ - dataOut.viewNormal = dataIn[vert].viewNormal; +# define PASS_SURFACE_INTERFACE(vert) \ + dataOut.worldPosition = dataIn[vert].worldPosition; \ + dataOut.viewPosition = dataIn[vert].viewPosition; \ + dataOut.worldNormal = dataIn[vert].worldNormal; \ + dataOut.viewNormal = dataIn[vert].viewNormal; -#else /* GPU_VERTEX_SHADER || GPU_FRAGMENT_SHADER*/ +# else /* GPU_VERTEX_SHADER || GPU_FRAGMENT_SHADER*/ IN_OUT ShaderStageInterface{SURFACE_INTERFACE}; -#endif +# endif +#endif /* EEVEE_GENERATED_INTERFACE */ #ifdef HAIR_SHADER IN_OUT ShaderHairInterface @@ -40,6 +52,7 @@ IN_OUT ShaderHairInterface float hairThickness; float hairTime; flat int hairStrandID; + vec2 hairBary; }; #endif @@ -52,3 +65,138 @@ IN_OUT ShaderPointCloudInterface flat int pointID; }; #endif + +#if defined(GPU_FRAGMENT_SHADER) && defined(CODEGEN_LIB) + +# if defined(USE_BARYCENTRICS) && !defined(HAIR_SHADER) +vec3 barycentric_distances_get() +{ + /* NOTE: No need to undo perspective divide since it is not applied yet. */ + vec3 pos0 = (ProjectionMatrixInverse * gpu_position_at_vertex(0)).xyz; + vec3 pos1 = (ProjectionMatrixInverse * gpu_position_at_vertex(1)).xyz; + vec3 pos2 = (ProjectionMatrixInverse * gpu_position_at_vertex(2)).xyz; + vec3 edge21 = pos2 - pos1; + vec3 edge10 = pos1 - pos0; + vec3 edge02 = pos0 - pos2; + vec3 d21 = safe_normalize(edge21); + vec3 d10 = safe_normalize(edge10); + vec3 d02 = safe_normalize(edge02); + vec3 dists; + float d = dot(d21, edge02); + dists.x = sqrt(dot(edge02, edge02) - d * d); + d = dot(d02, edge10); + dists.y = sqrt(dot(edge10, edge10) - d * d); + d = dot(d10, edge21); + dists.z = sqrt(dot(edge21, edge21) - d * d); + return dists.xyz; +} +# endif + +GlobalData init_globals(void) +{ + GlobalData surf; + +# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) + surf.P = -cameraVec(worldPosition); + surf.N = surf.Ng = -surf.P; + surf.ray_length = 0.0; +# else + surf.P = worldPosition; + surf.N = safe_normalize(worldNormal); + surf.Ng = safe_normalize(cross(dFdx(surf.P), dFdy(surf.P))); + surf.ray_length = distance(surf.P, cameraPos); +# endif + surf.barycentric_coords = vec2(0.0); + surf.barycentric_dists = vec3(0.0); + if (!FrontFacing) { + surf.N = -surf.N; + } +# ifdef HAIR_SHADER + /* Shade as a cylinder. */ + vec3 B = normalize(cross(worldNormal, hairTangent)); + float cos_theta; + if (hairThicknessRes == 1) { + /* Random cosine normal distribution on the hair surface. */ + cos_theta = texelfetch_noise_tex(gl_FragCoord.xy).x * 2.0 - 1.0; + } + else { + /* Shade as a cylinder. */ + cos_theta = hairThickTime / hairThickness; + } + float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta)); + surf.N = safe_normalize(worldNormal * sin_theta + B * cos_theta); + surf.T = hairTangent; + surf.is_strand = true; + surf.hair_time = hairTime; + surf.hair_thickness = hairThickness; + surf.hair_strand_id = hairStrandID; +# ifdef USE_BARYCENTRICS + surf.barycentric_coords = hair_resolve_barycentric(hairBary); +# endif +# else + surf.T = vec3(0.0); + surf.is_strand = false; + surf.hair_time = 0.0; + surf.hair_thickness = 0.0; + surf.hair_strand_id = 0; +# ifdef USE_BARYCENTRICS + surf.barycentric_coords = gpu_BaryCoord.xy; + surf.barycentric_dists = barycentric_distances_get(); +# endif +# endif + surf.ray_type = rayType; + surf.ray_depth = 0.0; + return surf; +} +#endif + +vec3 coordinate_camera(vec3 P) +{ + vec3 vP; +#if defined(PROBE_CAPTURE) + /* Unsupported. It would make the probe camera-dependent. */ + vP = P; +#elif defined(WORLD_BACKGROUND) + vP = transform_direction(ViewMatrix, P); +#else + vP = transform_point(ViewMatrix, P); +#endif + vP.z = -vP.z; + return vP; +} + +vec3 coordinate_screen(vec3 P) +{ + vec3 window = vec3(0.0); +#if defined(PROBE_CAPTURE) + /* Unsupported. It would make the probe camera-dependent. */ + window.xy = vec2(0.5); + +#elif defined(WORLD_BACKGROUND) + window.xy = project_point(ProjectionMatrix, viewPosition).xy * 0.5 + 0.5; + window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw; + +#else /* MESH */ + window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5; + window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw; +#endif + return window; +} + +vec3 coordinate_reflect(vec3 P, vec3 N) +{ +#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) + return N; +#else + return -reflect(cameraVec(P), N); +#endif +} + +vec3 coordinate_incoming(vec3 P) +{ +#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) + return -P; +#else + return cameraVec(P); +#endif +} \ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl index 51e9eda6cc2..6c6b810422b 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl @@ -1,6 +1,9 @@ #pragma BLENDER_REQUIRE(common_hair_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_surface_lib.glsl) #pragma BLENDER_REQUIRE(surface_lib.glsl) #ifndef HAIR_SHADER @@ -18,6 +21,7 @@ void main() #ifdef HAIR_SHADER hairStrandID = hair_get_strand_id(); + hairBary = hair_get_barycentric(); vec3 pos, binor; hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0), ModelMatrixInverse, @@ -53,11 +57,103 @@ void main() /* No need to normalize since this is just a rotation. */ viewNormal = normal_world_to_view(worldNormal); -# ifdef USE_ATTR -# ifdef HAIR_SHADER - pos = hair_get_strand_pos(); -# endif - pass_attr(pos, NormalMatrix, ModelMatrixInverse); -# endif + + attrib_load(); #endif } + +#ifdef HAIR_SHADER +# ifdef OBINFO_LIB +vec3 attr_load_orco(samplerBuffer cd_buf) +{ + vec3 P = hair_get_strand_pos(); + vec3 lP = transform_point(ModelMatrixInverse, P); + return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz; +} +# endif + +vec4 attr_load_tangent(samplerBuffer cd_buf) +{ + return vec4(hairTangent, 1.0); +} + +vec3 attr_load_uv(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rgb; +} + +vec4 attr_load_color(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rgba; +} + +vec4 attr_load_vec4(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rgba; +} + +vec3 attr_load_vec3(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rgb; +} + +vec2 attr_load_vec2(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).rg; +} + +float attr_load_float(samplerBuffer cd_buf) +{ + return texelFetch(cd_buf, hairStrandID).r; +} + +#else + +# ifdef OBINFO_LIB +vec3 attr_load_orco(vec4 orco) +{ + /* We know when there is no orco layer when orco.w is 1.0 because it uses the generic vertex + * attrib (which is [0,0,0,1]). */ + if (orco.w == 0.0) { + return orco.xyz * 0.5 + 0.5; + } + else { + /* If the object does not have any deformation, the orco layer calculation is done on the fly + * using the orco_madd factors. */ + return OrcoTexCoFactors[0].xyz + pos * OrcoTexCoFactors[1].xyz; + } +} +# endif + +vec4 attr_load_tangent(vec4 tangent) +{ + tangent.xyz = normal_object_to_world(tangent.xyz); + return tangent; +} + +/* Simple passthrough. */ +vec4 attr_load_vec4(vec4 attr) +{ + return attr; +} +vec3 attr_load_vec3(vec3 attr) +{ + return attr; +} +vec2 attr_load_vec2(vec2 attr) +{ + return attr; +} +float attr_load_float(float attr) +{ + return attr; +} +vec4 attr_load_color(vec4 attr) +{ + return attr; +} +vec3 attr_load_uv(vec3 attr) +{ + return attr; +} +#endif diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index 4ff42892f7d..e0a79872928 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -1,6 +1,5 @@ #pragma BLENDER_REQUIRE(volumetric_lib.glsl) -#pragma BLENDER_REQUIRE(closure_type_lib.glsl) /* Based on Frosbite Unified Volumetric. * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */ @@ -18,9 +17,7 @@ flat in int slice; vec3 worldPosition = vec3(0.0); vec3 viewPosition = vec3(0.0); vec3 viewNormal = vec3(0.0); -#ifdef MESH_SHADER -vec3 volumeObjectLocalCoord = vec3(0.0); -#endif +vec3 volumeOrco = vec3(0.0); layout(location = 0) out vec4 volumeScattering; layout(location = 1) out vec4 volumeExtinction; @@ -29,6 +26,52 @@ layout(location = 3) out vec4 volumePhase; /* Store volumetric properties into the froxel textures. */ +#ifdef MESH_SHADER +GlobalData init_globals(void) +{ + GlobalData surf; + surf.P = worldPosition; + surf.N = vec3(0.0); + surf.Ng = vec3(0.0); + surf.is_strand = false; + surf.hair_time = 0.0; + surf.hair_thickness = 0.0; + surf.hair_strand_id = 0; + surf.barycentric_coords = vec2(0.0); + surf.barycentric_dists = vec3(0.0); + surf.ray_type = RAY_TYPE_CAMERA; + surf.ray_depth = 0.0; + surf.ray_length = distance(surf.P, cameraPos); + return surf; +} + +vec3 coordinate_camera(vec3 P) +{ + vec3 vP; + vP = transform_point(ViewMatrix, P); + vP.z = -vP.z; + return vP; +} + +vec3 coordinate_screen(vec3 P) +{ + vec3 window = vec3(0.0); + window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5; + window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw; + return window; +} + +vec3 coordinate_reflect(vec3 P, vec3 N) +{ + return vec3(0.0); +} + +vec3 coordinate_incoming(vec3 P) +{ + return cameraVec(P); +} +#endif + void main() { ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), slice); @@ -37,14 +80,12 @@ void main() viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z); worldPosition = point_view_to_world(viewPosition); #ifdef MESH_SHADER - volumeObjectLocalCoord = point_world_to_object(worldPosition); + volumeOrco = point_world_to_object(worldPosition); /* TODO: redundant transform */ - volumeObjectLocalCoord = (volumeObjectLocalCoord - volumeOrcoLoc + volumeOrcoSize) / - (volumeOrcoSize * 2.0); - volumeObjectLocalCoord = (volumeObjectToTexture * vec4(volumeObjectLocalCoord, 1.0)).xyz; + volumeOrco = (volumeOrco - volumeOrcoLoc + volumeOrcoSize) / (volumeOrcoSize * 2.0); + volumeOrco = (volumeObjectToTexture * vec4(volumeOrco, 1.0)).xyz; - if (any(lessThan(volumeObjectLocalCoord, vec3(0.0))) || - any(greaterThan(volumeObjectLocalCoord, vec3(1.0)))) { + if (any(lessThan(volumeOrco, vec3(0.0))) || any(greaterThan(volumeOrco, vec3(1.0)))) { /* Note: Discard is not an explicit return in Metal prior to versions 2.3. * adding return after discard ensures consistent behaviour and avoids GPU * side-effects where control flow continues with undefined values. */ @@ -54,21 +95,25 @@ void main() #endif #ifdef CLEAR - Closure cl = CLOSURE_DEFAULT; + volumeScattering = vec4(0.0, 0.0, 0.0, 1.0); + volumeExtinction = vec4(0.0, 0.0, 0.0, 1.0); + volumeEmissive = vec4(0.0, 0.0, 0.0, 1.0); + volumePhase = vec4(0.0, 0.0, 0.0, 0.0); #else +# ifdef MESH_SHADER + g_data = init_globals(); + attrib_load(); +# endif Closure cl = nodetree_exec(); -#endif - -#ifdef MESH_SHADER +# ifdef MESH_SHADER cl.scatter *= volumeDensityScale; cl.absorption *= volumeDensityScale; cl.emission *= volumeDensityScale; -#endif +# endif volumeScattering = vec4(cl.scatter, 1.0); volumeExtinction = vec4(cl.absorption + cl.scatter, 1.0); volumeEmissive = vec4(cl.emission, 1.0); - /* Do not add phase weight if no scattering. */ if (all(equal(cl.scatter, vec3(0.0)))) { volumePhase = vec4(0.0); @@ -76,4 +121,38 @@ void main() else { volumePhase = vec4(cl.anisotropy, vec3(1.0)); } +#endif +} + +vec3 attr_load_orco(vec4 orco) +{ + return volumeOrco; +} +vec4 attr_load_tangent(vec4 tangent) +{ + return vec4(0); +} +vec4 attr_load_vec4(vec4 attr) +{ + return vec4(0); +} +vec3 attr_load_vec3(vec3 attr) +{ + return vec3(0); +} +vec2 attr_load_vec2(vec2 attr) +{ + return vec2(0); +} +float attr_load_float(float attr) +{ + return 0.0; +} +vec4 attr_load_color(vec4 attr) +{ + return vec4(0); +} +vec3 attr_load_uv(vec3 attr) +{ + return vec3(0); } diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl index 5226da57a06..1269761ffa4 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl @@ -1,11 +1,7 @@ #pragma BLENDER_REQUIRE(common_view_lib.glsl) -#ifdef MESH_SHADER -/* TODO: tight slices. */ -layout(triangles) in; -layout(triangle_strip, max_vertices = 3) out; -#else /* World */ +#ifdef STANDALONE layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; #endif diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl index 527bbd18896..26b60c992e1 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl @@ -11,8 +11,10 @@ uniform sampler3D volumeScattering; /* Result of the scatter step */ uniform sampler3D volumeExtinction; #ifdef USE_VOLUME_OPTI -uniform layout(r11f_g11f_b10f) writeonly restrict image3D finalScattering_img; -uniform layout(r11f_g11f_b10f) writeonly restrict image3D finalTransmittance_img; +uniform layout(r11f_g11f_b10f) +writeonly restrict image3D finalScattering_img; +uniform layout(r11f_g11f_b10f) +writeonly restrict image3D finalTransmittance_img; vec3 finalScattering; vec3 finalTransmittance; diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl index b70747ecec3..b574e8cdb4c 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl @@ -30,8 +30,30 @@ void main() vPos.w = 1.0; PASS_RESOURCE_ID +} + +/* Stubs */ +vec2 btdf_lut(float a, float b, float c) +{ + return vec2(0.0); +} + +vec2 brdf_lut(float a, float b) +{ + return vec2(0.0); +} -#ifdef USE_ATTR - pass_attr(vec3(0.0), mat3(1), mat4(1)); -#endif +vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c) +{ + return vec3(0.0); +} + +vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c) +{ + return vec3(0.0); +} + +float F_eta(float a, float b) +{ + return 0.0; } diff --git a/source/blender/draw/engines/eevee/shaders/world_vert.glsl b/source/blender/draw/engines/eevee/shaders/world_vert.glsl new file mode 100644 index 00000000000..29892a7ffb4 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/world_vert.glsl @@ -0,0 +1,24 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) + +#pragma BLENDER_REQUIRE(closure_eval_surface_lib.glsl) + +in vec2 pos; + +RESOURCE_ID_VARYING + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + PASS_RESOURCE_ID + + gl_Position = vec4(pos, 1.0, 1.0); + viewPosition = project_point(ProjectionMatrixInverse, vec3(pos, 0.0)); + worldPosition = project_point(ViewProjectionMatrixInverse, vec3(pos, 0.0)); + /* Not usable. */ + viewNormal = vec3(0.0); + worldNormal = vec3(0.0); +} diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 1bf67a4f315..712118e8282 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -28,6 +28,7 @@ #include "DNA_world_types.h" #include "GPU_framebuffer.h" +#include "GPU_material.h" #include "GPU_primitive.h" #include "GPU_shader.h" #include "GPU_storage_buffer.h" @@ -197,13 +198,6 @@ void DRW_texture_free(struct GPUTexture *tex); /* Shaders */ -typedef void (*GPUMaterialEvalCallbackFn)(struct GPUMaterial *mat, - int options, - const char **vert_code, - const char **geom_code, - const char **frag_lib, - const char **defines); - struct GPUShader *DRW_shader_create_ex( const char *vert, const char *geom, const char *frag, const char *defines, const char *name); struct GPUShader *DRW_shader_create_with_lib_ex(const char *vert, @@ -242,38 +236,20 @@ struct GPUShader *DRW_shader_create_fullscreen_with_shaderlib_ex(const char *fra #define DRW_shader_create_fullscreen_with_shaderlib(frag, lib, defines) \ DRW_shader_create_fullscreen_with_shaderlib_ex(frag, lib, defines, __func__) -struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, - const void *engine_type, - int options, - bool deferred); -struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, - const void *engine_type, - int options, - bool deferred); -struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, - struct World *wo, - struct bNodeTree *ntree, - const void *engine_type, - int options, - bool is_volume_shader, - const char *vert, - const char *geom, - const char *frag_lib, - const char *defines, - bool deferred, - GPUMaterialEvalCallbackFn callback); -struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, - struct Material *ma, - struct bNodeTree *ntree, - const void *engine_type, - int options, - bool is_volume_shader, - const char *vert, - const char *geom, - const char *frag_lib, - const char *defines, - bool deferred, - GPUMaterialEvalCallbackFn callback); +struct GPUMaterial *DRW_shader_from_world(struct World *wo, + struct bNodeTree *ntree, + const uint64_t shader_id, + const bool is_volume_shader, + bool deferred, + GPUCodegenCallbackFn callback, + void *thunk); +struct GPUMaterial *DRW_shader_from_material(struct Material *ma, + struct bNodeTree *ntree, + const uint64_t shader_id, + const bool is_volume_shader, + bool deferred, + GPUCodegenCallbackFn callback, + void *thunk); void DRW_shader_free(struct GPUShader *shader); #define DRW_SHADER_FREE_SAFE(shader) \ do { \ diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 0ac8bf91906..aac6f7e58c5 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -306,7 +306,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_tex); if (hair_cache->length_tex) { - DRW_shgroup_uniform_texture(shgrp, "hairLen", hair_cache->length_tex); + DRW_shgroup_uniform_texture(shgrp, "l", hair_cache->length_tex); } DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res); diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 1936aa599ff..9f8a68f81f6 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -417,119 +417,81 @@ GPUShader *DRW_shader_create_fullscreen_with_shaderlib_ex(const char *frag, return sh; } -GPUMaterial *DRW_shader_find_from_world(World *wo, - const void *engine_type, - const int options, - bool deferred) +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 *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options); - if (DRW_state_is_image_render() || !deferred) { - if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) { - /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX - * with the shader code and we will resume the compilation from there. */ - return NULL; - } - } - return mat; -} - -GPUMaterial *DRW_shader_find_from_material(Material *ma, - const void *engine_type, - const int options, - bool deferred) -{ - GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options); - if (DRW_state_is_image_render() || !deferred) { - if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) { - /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX - * with the shader code and we will resume the compilation from there. */ - return NULL; - } - } - return mat; -} - -GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, - World *wo, - struct bNodeTree *ntree, - const void *engine_type, - const int options, - const bool is_volume_shader, - const char *vert, - const char *geom, - const char *frag_lib, - const char *defines, - bool deferred, - GPUMaterialEvalCallbackFn callback) -{ - GPUMaterial *mat = NULL; - if (DRW_state_is_image_render() || !deferred) { - mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options); - } - - if (mat == NULL) { - scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); - mat = GPU_material_from_nodetree(scene, - NULL, - ntree, - &wo->gpumaterial, - engine_type, - options, - is_volume_shader, - vert, - geom, - frag_lib, - defines, - wo->id.name, - callback); + Scene *scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); + GPUMaterial *mat = GPU_material_from_nodetree(scene, + NULL, + ntree, + &wo->gpumaterial, + wo->id.name, + shader_id, + is_volume_shader, + false, + callback, + thunk); + if (!DRW_state_is_image_render() && deferred && GPU_material_status(mat) == GPU_MAT_QUEUED) { + /* Shader has been already queued. */ + return mat; } - if (GPU_material_status(mat) == GPU_MAT_QUEUED) { + if (GPU_material_status(mat) == GPU_MAT_CREATED) { + GPU_material_status_set(mat, GPU_MAT_QUEUED); drw_deferred_shader_add(mat, deferred); } + if (!deferred && GPU_material_status(mat) == GPU_MAT_QUEUED) { + /* Force compilation for shaders already queued. */ + drw_deferred_shader_add(mat, false); + } return mat; } -GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, - Material *ma, - struct bNodeTree *ntree, - const void *engine_type, - const int options, - const bool is_volume_shader, - const char *vert, - const char *geom, - const char *frag_lib, - const char *defines, - bool deferred, - GPUMaterialEvalCallbackFn callback) +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) { - GPUMaterial *mat = NULL; - if (DRW_state_is_image_render() || !deferred) { - mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options); + Scene *scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); + GPUMaterial *mat = GPU_material_from_nodetree(scene, + ma, + ntree, + &ma->gpumaterial, + ma->id.name, + shader_id, + is_volume_shader, + false, + callback, + thunk); + + if (DRW_state_is_image_render()) { + /* Do not deferred if doing render. */ + deferred = false; } - if (mat == NULL) { - scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); - mat = GPU_material_from_nodetree(scene, - ma, - ntree, - &ma->gpumaterial, - engine_type, - options, - is_volume_shader, - vert, - geom, - frag_lib, - defines, - ma->id.name, - callback); + if (deferred && GPU_material_status(mat) == GPU_MAT_QUEUED) { + /* Shader has been already queued. */ + return mat; } - if (GPU_material_status(mat) == GPU_MAT_QUEUED) { + if (GPU_material_status(mat) == GPU_MAT_CREATED) { + GPU_material_status_set(mat, GPU_MAT_QUEUED); drw_deferred_shader_add(mat, deferred); } + if (!deferred && GPU_material_status(mat) == GPU_MAT_QUEUED) { + /* Force compilation for shaders already queued. */ + drw_deferred_shader_add(mat, false); + } return mat; } @@ -552,15 +514,15 @@ void DRW_shader_free(GPUShader *shader) * contains the needed libraries for this shader. * \{ */ -/* 32 because we use a 32bit bitmap. */ -#define MAX_LIB 32 +/* 64 because we use a 64bit bitmap. */ +#define MAX_LIB 64 #define MAX_LIB_NAME 64 #define MAX_LIB_DEPS 8 struct DRWShaderLibrary { const char *libs[MAX_LIB]; char libs_name[MAX_LIB][MAX_LIB_NAME]; - uint32_t libs_deps[MAX_LIB]; + uint64_t libs_deps[MAX_LIB]; }; DRWShaderLibrary *DRW_shader_library_create(void) @@ -589,23 +551,27 @@ static int drw_shader_library_search(const DRWShaderLibrary *lib, const char *na } /* Return bitmap of dependencies. */ -static uint32_t drw_shader_dependencies_get(const DRWShaderLibrary *lib, const char *lib_code) +static uint64_t drw_shader_dependencies_get(const DRWShaderLibrary *lib, + const char *pragma_str, + const char *lib_code, + const char *UNUSED(lib_name)) { /* Search dependencies. */ - uint32_t deps = 0; + uint pragma_len = strlen(pragma_str); + uint64_t deps = 0; const char *haystack = lib_code; - while ((haystack = strstr(haystack, "BLENDER_REQUIRE("))) { - haystack += 16; + while ((haystack = strstr(haystack, pragma_str))) { + haystack += pragma_len; int dep = drw_shader_library_search(lib, haystack); if (dep == -1) { - char dbg_name[33]; + char dbg_name[MAX_NAME]; int i = 0; while ((*haystack != ')') && (i < (sizeof(dbg_name) - 2))) { dbg_name[i] = *haystack; haystack++; i++; } - dbg_name[i + 1] = '\0'; + dbg_name[i] = '\0'; CLOG_INFO(&LOG, 0, @@ -614,7 +580,7 @@ static uint32_t drw_shader_dependencies_get(const DRWShaderLibrary *lib, const c dbg_name); } else { - deps |= 1u << (uint32_t)dep; + deps |= 1llu << ((uint64_t)dep); } } return deps; @@ -633,7 +599,8 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, const char *lib_code, co if (index > -1) { lib->libs[index] = lib_code; BLI_strncpy(lib->libs_name[index], lib_name, MAX_LIB_NAME); - lib->libs_deps[index] = drw_shader_dependencies_get(lib, lib_code); + lib->libs_deps[index] = drw_shader_dependencies_get( + lib, "BLENDER_REQUIRE(", lib_code, lib_name); } else { printf("Error: Too many libraries. Cannot add %s.\n", lib_name); @@ -643,21 +610,20 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, const char *lib_code, co char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib, const char *shader_code) { - uint32_t deps = drw_shader_dependencies_get(lib, shader_code); + uint64_t deps = drw_shader_dependencies_get(lib, "BLENDER_REQUIRE(", shader_code, "shader code"); DynStr *ds = BLI_dynstr_new(); /* Add all dependencies recursively. */ for (int i = MAX_LIB - 1; i > -1; i--) { - if (lib->libs[i] && (deps & (1u << (uint32_t)i))) { + if (lib->libs[i] && (deps & (1llu << (uint64_t)i))) { deps |= lib->libs_deps[i]; } } /* Concatenate all needed libs into one string. */ - for (int i = 0; i < MAX_LIB; i++) { - if (deps & 1u) { + for (int i = 0; i < MAX_LIB && deps != 0llu; i++, deps >>= 1llu) { + if (deps & 1llu) { BLI_dynstr_append(ds, lib->libs[i]); } - deps = deps >> 1; } BLI_dynstr_append(ds, shader_code); diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index 5fc76bc25e6..58875c0496a 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -36,16 +36,19 @@ struct ViewInfos { }; BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16) +/* Do not override old definitions if the shader uses this header but not shader info. */ +#ifdef USE_GPU_SHADER_CREATE_INFO /* TODO(@fclem): Mass rename. */ -#define ViewProjectionMatrix drw_view.persmat -#define ViewProjectionMatrixInverse drw_view.persinv -#define ViewMatrix drw_view.viewmat -#define ViewMatrixInverse drw_view.viewinv -#define ProjectionMatrix drw_view.winmat -#define ProjectionMatrixInverse drw_view.wininv -#define clipPlanes drw_view.clip_planes -#define ViewVecs drw_view.viewvecs -#define CameraTexCoFactors drw_view.viewcamtexcofac +# define ViewProjectionMatrix drw_view.persmat +# define ViewProjectionMatrixInverse drw_view.persinv +# define ViewMatrix drw_view.viewmat +# define ViewMatrixInverse drw_view.viewinv +# define ProjectionMatrix drw_view.winmat +# define ProjectionMatrixInverse drw_view.wininv +# define clipPlanes drw_view.clip_planes +# define ViewVecs drw_view.viewvecs +# define CameraTexCoFactors drw_view.viewcamtexcofac +#endif struct ObjectMatrices { float4x4 drw_modelMatrix; diff --git a/source/blender/draw/intern/shaders/common_attribute_lib.glsl b/source/blender/draw/intern/shaders/common_attribute_lib.glsl new file mode 100644 index 00000000000..99db2929a13 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_attribute_lib.glsl @@ -0,0 +1,21 @@ + +/* Prototype of functions to implement to load attributes data. + * Implementation changes based on object data type. */ + +vec3 attr_load_orco(vec4 orco); +vec4 attr_load_tangent(vec4 tangent); +vec3 attr_load_uv(vec3 uv); +vec4 attr_load_color(vec4 color); +vec4 attr_load_vec4(vec4 attr); +vec3 attr_load_vec3(vec3 attr); +vec2 attr_load_vec2(vec2 attr); +float attr_load_float(float attr); + +vec3 attr_load_orco(samplerBuffer orco); +vec4 attr_load_tangent(samplerBuffer tangent); +vec3 attr_load_uv(samplerBuffer uv); +vec4 attr_load_color(samplerBuffer color); +vec4 attr_load_vec4(samplerBuffer attr); +vec3 attr_load_vec3(samplerBuffer attr); +vec2 attr_load_vec2(samplerBuffer attr); +float attr_load_float(samplerBuffer attr); diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index 4d0ffaeb40f..1ac26c91b93 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -1,4 +1,8 @@ +/* WORKAROUND: to guard against double include in EEVEE. */ +#ifndef COMMON_MATH_LIB_GLSL +#define COMMON_MATH_LIB_GLSL + /* ---------------------------------------------------------------------- */ /** \name Common Math Utilities * \{ */ @@ -276,3 +280,5 @@ vec3 hue_gradient(float t) vec3 p = abs(fract(t + vec3(1.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - 3.0); return (clamp(p - 1.0, 0.0, 1.0)); } + +#endif /* COMMON_MATH_LIB_GLSL */ diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index a2b8cb4bbd6..4086162a530 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -1,5 +1,10 @@ + +/* WORKAROUND: to guard against double include in EEVEE. */ +#ifndef COMMON_VIEW_LIB_GLSL +#define COMMON_VIEW_LIB_GLSL + /* Temporary until we fully make the switch. */ -#ifndef USE_GPU_SHADER_CREATE_INFO +#if !defined(USE_GPU_SHADER_CREATE_INFO) # define DRW_RESOURCE_CHUNK_LEN 512 @@ -37,7 +42,10 @@ layout(std140) uniform viewBlock #define cameraForward ViewMatrixInverse[2].xyz #define cameraPos ViewMatrixInverse[3].xyz -#define cameraVec(P) ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - P) : cameraForward) +vec3 cameraVec(vec3 P) +{ + return ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - P) : cameraForward); +} #define viewCameraVec(vP) ((ProjectionMatrix[3][3] == 0.0) ? normalize(-vP) : vec3(0.0, 0.0, 1.0)) #ifdef world_clip_planes_calc_clip_distance @@ -92,14 +100,14 @@ vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos) } /* Temporary until we fully make the switch. */ -#ifndef DRW_SHADER_SHARED_H +#ifndef USE_GPU_SHADER_CREATE_INFO uniform int drw_resourceChunk; -#endif /* DRW_SHADER_SHARED_H */ +#endif /* USE_GPU_SHADER_CREATE_INFO */ #ifdef GPU_VERTEX_SHADER /* Temporary until we fully make the switch. */ -# ifndef DRW_SHADER_SHARED_H +# ifndef USE_GPU_SHADER_CREATE_INFO /* clang-format off */ # if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTR) || defined(DRW_LEGACY_MODEL_MATRIX) || defined(GPU_DEPRECATED_AMD_DRIVER) @@ -121,7 +129,10 @@ uniform int drw_ResourceID; /* Use this to declare and pass the value if * the fragment shader uses the resource_id. */ -# ifdef USE_GEOMETRY_SHADER +# if defined(EEVEE_GENERATED_INTERFACE) +# define RESOURCE_ID_VARYING +# define PASS_RESOURCE_ID resourceIDFrag = resource_id; +# elif defined(USE_GEOMETRY_SHADER) # define RESOURCE_ID_VARYING flat out int resourceIDGeom; # define PASS_RESOURCE_ID resourceIDGeom = resource_id; # else @@ -129,12 +140,12 @@ uniform int drw_ResourceID; # define PASS_RESOURCE_ID resourceIDFrag = resource_id; # endif -# endif /* DRW_SHADER_SHARED_H */ +# endif /* USE_GPU_SHADER_CREATE_INFO */ #endif /* GPU_VERTEX_SHADER */ /* Temporary until we fully make the switch. */ -#ifdef DRW_SHADER_SHARED_H +#ifdef USE_GPU_SHADER_CREATE_INFO /* TODO(fclem): Rename PASS_RESOURCE_ID to DRW_RESOURCE_ID_VARYING_SET */ # if defined(UNIFORM_RESOURCE_ID) # define resource_id drw_ResourceID @@ -159,16 +170,23 @@ uniform int drw_ResourceID; /* If used in a fragment / geometry shader, we pass * resource_id as varying. */ # ifdef GPU_GEOMETRY_SHADER -# define RESOURCE_ID_VARYING \ - flat out int resourceIDFrag; \ - flat in int resourceIDGeom[]; +/* TODO(fclem): Remove. This is getting ridiculous. */ +# if !defined(EEVEE_GENERATED_INTERFACE) +# define RESOURCE_ID_VARYING \ + flat out int resourceIDFrag; \ + flat in int resourceIDGeom[]; +# else +# define RESOURCE_ID_VARYING +# endif # define resource_id resourceIDGeom # define PASS_RESOURCE_ID resourceIDFrag = resource_id[0]; # endif -# ifdef GPU_FRAGMENT_SHADER +# if defined(GPU_FRAGMENT_SHADER) +# if !defined(EEVEE_GENERATED_INTERFACE) flat in int resourceIDFrag; +# endif # define resource_id resourceIDFrag # endif #endif @@ -185,7 +203,9 @@ struct ObjectMatrices { mat4 drw_modelMatrix; mat4 drw_modelMatrixInverse; }; +# endif /* DRW_SHADER_SHARED_H */ +# ifndef USE_GPU_SHADER_CREATE_INFO layout(std140) uniform modelBlock { ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN]; @@ -193,24 +213,24 @@ layout(std140) uniform modelBlock # define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix) # define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse) -# endif /* DRW_SHADER_SHARED_H */ +# endif /* USE_GPU_SHADER_CREATE_INFO */ #else /* GPU_INTEL */ /* Temporary until we fully make the switch. */ -# ifndef DRW_SHADER_SHARED_H +# ifndef USE_GPU_SHADER_CREATE_INFO /* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage. * So for now we just force using the legacy path. */ /* Note that this is also a workaround of a problem on osx (amd or nvidia) * and older amd driver on windows. */ uniform mat4 ModelMatrix; uniform mat4 ModelMatrixInverse; -# endif /* DRW_SHADER_SHARED_H */ +# endif /* USE_GPU_SHADER_CREATE_INFO */ #endif /* Temporary until we fully make the switch. */ -#ifndef DRW_SHADER_SHARED_H +#ifndef USE_GPU_SHADER_CREATE_INFO # define resource_handle (drw_resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id) #endif @@ -337,3 +357,5 @@ vec3 get_view_vector_from_screen_uv(vec2 uv) return vec3(0.0, 0.0, 1.0); } } + +#endif /* COMMON_VIEW_LIB_GLSL */ diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 3e12426acdc..98d15a1024c 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -46,7 +46,7 @@ set(SRC intern/gpu_batch_utils.c intern/gpu_buffers.c intern/gpu_capabilities.cc - intern/gpu_codegen.c + intern/gpu_codegen.cc intern/gpu_compute.cc intern/gpu_context.cc intern/gpu_debug.cc @@ -57,7 +57,6 @@ set(SRC intern/gpu_index_buffer.cc intern/gpu_init_exit.c intern/gpu_material.c - intern/gpu_material_library.c intern/gpu_matrix.cc intern/gpu_node_graph.c intern/gpu_platform.cc @@ -312,6 +311,7 @@ set(GLSL_SRC shaders/material/gpu_shader_material_glass.glsl shaders/material/gpu_shader_material_glossy.glsl shaders/material/gpu_shader_material_hair_info.glsl + shaders/material/gpu_shader_material_hair.glsl shaders/material/gpu_shader_material_hash.glsl shaders/material/gpu_shader_material_holdout.glsl shaders/material/gpu_shader_material_hue_sat_val.glsl diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 9b63d0feb1e..f38b9681ad7 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -13,6 +13,7 @@ #include "BLI_sys_types.h" /* for bool */ +#include "GPU_shader.h" /* for GPUShaderCreateInfo */ #include "GPU_texture.h" /* for eGPUSamplerState */ #ifdef __cplusplus @@ -58,8 +59,6 @@ typedef enum eGPUType { GPU_TEX2D = 1002, GPU_TEX2D_ARRAY = 1003, GPU_TEX3D = 1004, - GPU_SHADOW2D = 1005, - GPU_TEXCUBE = 1006, /* GLSL Struct types */ GPU_CLOSURE = 1007, @@ -68,35 +67,30 @@ typedef enum eGPUType { GPU_ATTR = 3001, } eGPUType; -typedef enum eGPUBuiltin { - GPU_VIEW_MATRIX = (1 << 0), - GPU_OBJECT_MATRIX = (1 << 1), - GPU_INVERSE_VIEW_MATRIX = (1 << 2), - GPU_INVERSE_OBJECT_MATRIX = (1 << 3), - GPU_VIEW_POSITION = (1 << 4), - GPU_VIEW_NORMAL = (1 << 5), - GPU_OBJECT_COLOR = (1 << 6), - GPU_AUTO_BUMPSCALE = (1 << 7), - GPU_CAMERA_TEXCO_FACTORS = (1 << 8), - GPU_PARTICLE_SCALAR_PROPS = (1 << 9), - GPU_PARTICLE_LOCATION = (1 << 10), - GPU_PARTICLE_VELOCITY = (1 << 11), - GPU_PARTICLE_ANG_VELOCITY = (1 << 12), - GPU_LOC_TO_VIEW_MATRIX = (1 << 13), - GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14), - GPU_OBJECT_INFO = (1 << 15), - GPU_BARYCENTRIC_TEXCO = (1 << 16), - GPU_BARYCENTRIC_DIST = (1 << 17), - GPU_WORLD_NORMAL = (1 << 18), -} eGPUBuiltin; - -typedef enum eGPUMatFlag { +typedef enum eGPUMaterialFlag { GPU_MATFLAG_DIFFUSE = (1 << 0), - GPU_MATFLAG_GLOSSY = (1 << 1), - GPU_MATFLAG_REFRACT = (1 << 2), - GPU_MATFLAG_SSS = (1 << 3), - GPU_MATFLAG_BARYCENTRIC = (1 << 4), -} eGPUMatFlag; + GPU_MATFLAG_SUBSURFACE = (1 << 1), + GPU_MATFLAG_GLOSSY = (1 << 2), + GPU_MATFLAG_REFRACT = (1 << 3), + GPU_MATFLAG_EMISSION = (1 << 4), + GPU_MATFLAG_TRANSPARENT = (1 << 5), + GPU_MATFLAG_HOLDOUT = (1 << 6), + GPU_MATFLAG_SHADER_TO_RGBA = (1 << 7), + GPU_MATFLAG_AO = (1 << 8), + + GPU_MATFLAG_OBJECT_INFO = (1 << 10), + GPU_MATFLAG_AOV = (1 << 11), + + GPU_MATFLAG_BARYCENTRIC = (1 << 20), + + /* Tells the render engine the material was just compiled or updated. */ + GPU_MATFLAG_UPDATED = (1 << 29), + + /* HACK(fclem) Tells the environment texture node to not bail out if empty. */ + GPU_MATFLAG_LOOKDEV_HACK = (1 << 30), +} eGPUMaterialFlag; + +ENUM_OPERATORS(eGPUMaterialFlag, GPU_MATFLAG_LOOKDEV_HACK); typedef struct GPUNodeStack { eGPUType type; @@ -110,6 +104,7 @@ typedef struct GPUNodeStack { typedef enum eGPUMaterialStatus { GPU_MAT_FAILED = 0, + GPU_MAT_CREATED, GPU_MAT_QUEUED, GPU_MAT_SUCCESS, } eGPUMaterialStatus; @@ -119,12 +114,19 @@ typedef enum eGPUVolumeDefaultValue { GPU_VOLUME_DEFAULT_1, } eGPUVolumeDefaultValue; -typedef void (*GPUMaterialEvalCallbackFn)(GPUMaterial *mat, - int options, - const char **vert_code, - const char **geom_code, - const char **frag_lib, - const char **defines); +typedef struct GPUCodegenOutput { + char *attr_load; + /* Nodetree functions calls. */ + char *displacement; + char *surface; + char *volume; + char *thickness; + char *material_functions; + + GPUShaderCreateInfo *create_info; +} GPUCodegenOutput; + +typedef void (*GPUCodegenCallbackFn)(void *thunk, GPUMaterial *mat, GPUCodegenOutput *codegen); GPUNodeLink *GPU_constant(const float *num); GPUNodeLink *GPU_uniform(const float *num); @@ -143,7 +145,12 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name, eGPUVolumeDefaultValue default_value); -GPUNodeLink *GPU_builtin(eGPUBuiltin builtin); +/** + * Create an implementation defined differential calculation of a float function. + * The given function should return a float. + * The result will be a vec2 containing dFdx and dFdy result of that function. + */ +GPUNodeLink *GPU_differentiate_float_function(const char *function_name); bool GPU_link(GPUMaterial *mat, const char *name, ...); bool GPU_stack_link(GPUMaterial *mat, @@ -157,10 +164,26 @@ GPUNodeLink *GPU_uniformbuf_link_out(struct GPUMaterial *mat, struct GPUNodeStack *stack, int index); -void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link); +void GPU_material_output_surface(GPUMaterial *material, GPUNodeLink *link); +void GPU_material_output_volume(GPUMaterial *material, GPUNodeLink *link); +void GPU_material_output_displacement(GPUMaterial *material, GPUNodeLink *link); +void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link); + void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash); -void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]); +/** + * Wrap a part of the material graph into a function. You need then need to call the function by + * using something like #GPU_differentiate_float_function. + * \note This replace the link by a constant to break the link with the main graph. + * \param return_type: sub function return type. Output is cast to this type. + * \param link: link to use as the sub function output. + * \return the name of the generated function. + */ +char *GPU_material_split_sub_function(GPUMaterial *material, + eGPUType return_type, + GPUNodeLink **link); + +bool GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]); struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material, int sample_len, struct GPUTexture **tex_profile); @@ -180,15 +203,13 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene, struct Material *ma, struct bNodeTree *ntree, struct ListBase *gpumaterials, - const void *engine_type, - int options, - bool is_volume_shader, - const char *vert_code, - const char *geom_code, - const char *frag_lib, - const char *defines, const char *name, - GPUMaterialEvalCallbackFn callback); + uint64_t shader_uuid, + bool is_volume_shader, + bool is_lookdev, + GPUCodegenCallbackFn callback, + void *thunk); + void GPU_material_compile(GPUMaterial *mat); void GPU_material_free(struct ListBase *gpumaterial); @@ -205,6 +226,7 @@ struct Material *GPU_material_get_material(GPUMaterial *material); * Return true if the material compilation has not yet begin or begin. */ eGPUMaterialStatus GPU_material_status(GPUMaterial *mat); +void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus status); struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material); /** @@ -215,13 +237,15 @@ struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material); void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs); struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void); +bool GPU_material_is_volume_shader(GPUMaterial *mat); bool GPU_material_has_surface_output(GPUMaterial *mat); bool GPU_material_has_volume_output(GPUMaterial *mat); -bool GPU_material_is_volume_shader(GPUMaterial *mat); - -void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag); -bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag); +void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag); +bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag); +eGPUMaterialFlag GPU_material_flag(const GPUMaterial *mat); +bool GPU_material_recalc_flag_get(GPUMaterial *mat); +uint64_t GPU_material_uuid_get(GPUMaterial *mat); void GPU_pass_cache_init(void); void GPU_pass_cache_garbage_collect(void); diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h index c47be05a646..f78719d1963 100644 --- a/source/blender/gpu/GPU_uniform_buffer.h +++ b/source/blender/gpu/GPU_uniform_buffer.h @@ -42,8 +42,8 @@ void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot); void GPU_uniformbuf_unbind(GPUUniformBuf *ubo); void GPU_uniformbuf_unbind_all(void); -#define GPU_UBO_BLOCK_NAME "nodeTree" -#define GPU_ATTRIBUTE_UBO_BLOCK_NAME "uniformAttrs" +#define GPU_UBO_BLOCK_NAME "node_tree" +#define GPU_ATTRIBUTE_UBO_BLOCK_NAME "unf_attrs" #ifdef __cplusplus } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c deleted file mode 100644 index e462308d3ee..00000000000 --- a/source/blender/gpu/intern/gpu_codegen.c +++ /dev/null @@ -1,1123 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2005 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup gpu - * - * Convert material node-trees to GLSL. - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_customdata_types.h" -#include "DNA_image_types.h" - -#include "BLI_blenlib.h" -#include "BLI_dynstr.h" -#include "BLI_ghash.h" -#include "BLI_hash_mm2a.h" -#include "BLI_link_utils.h" -#include "BLI_threads.h" -#include "BLI_utildefines.h" - -#include "PIL_time.h" - -#include "BKE_material.h" - -#include "GPU_capabilities.h" -#include "GPU_material.h" -#include "GPU_shader.h" -#include "GPU_uniform_buffer.h" -#include "GPU_vertex_format.h" - -#include "BLI_sys_types.h" /* for intptr_t support */ - -#include "gpu_codegen.h" -#include "gpu_material_library.h" -#include "gpu_node_graph.h" - -#include -#include - -extern char datatoc_gpu_shader_codegen_lib_glsl[]; -extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; - -/* -------------------- GPUPass Cache ------------------ */ -/** - * Internal shader cache: This prevent the shader recompilation / stall when - * using undo/redo AND also allows for GPUPass reuse if the Shader code is the - * same for 2 different Materials. Unused GPUPasses are free by Garbage collection. - */ - -/* Only use one linked-list that contains the GPUPasses grouped by hash. */ -static GPUPass *pass_cache = NULL; -static SpinLock pass_cache_spin; - -static uint32_t gpu_pass_hash(const char *frag_gen, const char *defs, ListBase *attributes) -{ - BLI_HashMurmur2A hm2a; - BLI_hash_mm2a_init(&hm2a, 0); - BLI_hash_mm2a_add(&hm2a, (uchar *)frag_gen, strlen(frag_gen)); - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attributes) { - BLI_hash_mm2a_add(&hm2a, (uchar *)attr->name, strlen(attr->name)); - } - if (defs) { - BLI_hash_mm2a_add(&hm2a, (uchar *)defs, strlen(defs)); - } - - return BLI_hash_mm2a_end(&hm2a); -} - -/* Search by hash only. Return first pass with the same hash. - * There is hash collision if (pass->next && pass->next->hash == hash) */ -static GPUPass *gpu_pass_cache_lookup(uint32_t hash) -{ - BLI_spin_lock(&pass_cache_spin); - /* Could be optimized with a Lookup table. */ - for (GPUPass *pass = pass_cache; pass; pass = pass->next) { - if (pass->hash == hash) { - BLI_spin_unlock(&pass_cache_spin); - return pass; - } - } - BLI_spin_unlock(&pass_cache_spin); - return NULL; -} - -/* Check all possible passes with the same hash. */ -static GPUPass *gpu_pass_cache_resolve_collision(GPUPass *pass, - const char *vert, - const char *geom, - const char *frag, - const char *defs, - uint32_t hash) -{ - BLI_spin_lock(&pass_cache_spin); - /* Collision, need to `strcmp` the whole shader. */ - for (; pass && (pass->hash == hash); pass = pass->next) { - if ((defs != NULL) && (!STREQ(pass->defines, defs))) { /* Pass */ - } - else if ((geom != NULL) && (!STREQ(pass->geometrycode, geom))) { /* Pass */ - } - else if ((!STREQ(pass->fragmentcode, frag) == 0) && (STREQ(pass->vertexcode, vert))) { - BLI_spin_unlock(&pass_cache_spin); - return pass; - } - } - BLI_spin_unlock(&pass_cache_spin); - return NULL; -} - -/* GLSL code generation */ - -static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *tmp, int id) -{ - char name[1024]; - - BLI_snprintf(name, sizeof(name), "%s%d", tmp, id); - - if (from == to) { - BLI_dynstr_append(ds, name); - } - else if (to == GPU_FLOAT) { - if (from == GPU_VEC4) { - BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.2126, 0.7152, 0.0722))", name); - } - else if (from == GPU_VEC3) { - BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name); - } - else if (from == GPU_VEC2) { - BLI_dynstr_appendf(ds, "%s.r", name); - } - } - else if (to == GPU_VEC2) { - if (from == GPU_VEC4) { - BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, %s.a)", name, name, name, name); - } - else if (from == GPU_VEC3) { - BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, 1.0)", name, name, name); - } - else if (from == GPU_FLOAT) { - BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name); - } - } - else if (to == GPU_VEC3) { - if (from == GPU_VEC4) { - BLI_dynstr_appendf(ds, "%s.rgb", name); - } - else if (from == GPU_VEC2) { - BLI_dynstr_appendf(ds, "vec3(%s.r, %s.r, %s.r)", name, name, name); - } - else if (from == GPU_FLOAT) { - BLI_dynstr_appendf(ds, "vec3(%s, %s, %s)", name, name, name); - } - } - else if (to == GPU_VEC4) { - if (from == GPU_VEC3) { - BLI_dynstr_appendf(ds, "vec4(%s, 1.0)", name); - } - else if (from == GPU_VEC2) { - BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name); - } - else if (from == GPU_FLOAT) { - BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name); - } - } - else if (to == GPU_CLOSURE) { - if (from == GPU_VEC4) { - BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name); - } - else if (from == GPU_VEC3) { - BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name); - } - else if (from == GPU_VEC2) { - BLI_dynstr_appendf(ds, "closure_emission(%s.rrr)", name); - } - else if (from == GPU_FLOAT) { - BLI_dynstr_appendf(ds, "closure_emission(vec3(%s, %s, %s))", name, name, name); - } - } - else { - BLI_dynstr_append(ds, name); - } -} - -static void codegen_print_datatype(DynStr *ds, const eGPUType type, float *data) -{ - int i; - - BLI_dynstr_appendf(ds, "%s(", gpu_data_type_to_string(type)); - - for (i = 0; i < type; i++) { - BLI_dynstr_appendf(ds, "%.12f", data[i]); - if (i == type - 1) { - BLI_dynstr_append(ds, ")"); - } - else { - BLI_dynstr_append(ds, ", "); - } - } -} - -static const char *gpu_builtin_name(eGPUBuiltin builtin) -{ - if (builtin == GPU_VIEW_MATRIX) { - return "unfviewmat"; - } - if (builtin == GPU_OBJECT_MATRIX) { - return "unfobmat"; - } - if (builtin == GPU_INVERSE_VIEW_MATRIX) { - return "unfinvviewmat"; - } - if (builtin == GPU_INVERSE_OBJECT_MATRIX) { - return "unfinvobmat"; - } - if (builtin == GPU_LOC_TO_VIEW_MATRIX) { - return "unflocaltoviewmat"; - } - if (builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) { - return "unfinvlocaltoviewmat"; - } - if (builtin == GPU_VIEW_POSITION) { - return "varposition"; - } - if (builtin == GPU_WORLD_NORMAL) { - return "varwnormal"; - } - if (builtin == GPU_VIEW_NORMAL) { - return "varnormal"; - } - if (builtin == GPU_OBJECT_COLOR) { - return "unfobjectcolor"; - } - if (builtin == GPU_AUTO_BUMPSCALE) { - return "unfobautobumpscale"; - } - if (builtin == GPU_CAMERA_TEXCO_FACTORS) { - return "unfcameratexfactors"; - } - if (builtin == GPU_PARTICLE_SCALAR_PROPS) { - return "unfparticlescalarprops"; - } - if (builtin == GPU_PARTICLE_LOCATION) { - return "unfparticleco"; - } - if (builtin == GPU_PARTICLE_VELOCITY) { - return "unfparticlevel"; - } - if (builtin == GPU_PARTICLE_ANG_VELOCITY) { - return "unfparticleangvel"; - } - if (builtin == GPU_OBJECT_INFO) { - return "unfobjectinfo"; - } - if (builtin == GPU_BARYCENTRIC_TEXCO) { - return "unfbarycentrictex"; - } - if (builtin == GPU_BARYCENTRIC_DIST) { - return "unfbarycentricdist"; - } - return ""; -} - -static void codegen_set_unique_ids(GPUNodeGraph *graph) -{ - int id = 1; - - LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) { - LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { - /* set id for unique names of uniform variables */ - input->id = id++; - } - - LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) { - /* set id for unique names of tmp variables storing output */ - output->id = id++; - } - } -} - -/** - * It will create an UBO for GPUMaterial if there is any GPU_DYNAMIC_UBO. - */ -static int codegen_process_uniforms_functions(GPUMaterial *material, - DynStr *ds, - GPUNodeGraph *graph) -{ - const char *name; - int builtins = 0; - ListBase ubo_inputs = {NULL, NULL}; - - /* Textures */ - LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph->textures) { - if (tex->colorband) { - BLI_dynstr_appendf(ds, "uniform sampler1DArray %s;\n", tex->sampler_name); - } - else if (tex->tiled_mapping_name[0]) { - BLI_dynstr_appendf(ds, "uniform sampler2DArray %s;\n", tex->sampler_name); - BLI_dynstr_appendf(ds, "uniform sampler1DArray %s;\n", tex->tiled_mapping_name); - } - else { - BLI_dynstr_appendf(ds, "uniform sampler2D %s;\n", tex->sampler_name); - } - } - - /* Volume Grids */ - LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) { - BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", grid->sampler_name); - BLI_dynstr_appendf(ds, "uniform mat4 %s = mat4(0.0);\n", grid->transform_name); - } - - /* Print other uniforms */ - - LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) { - LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { - if (input->source == GPU_SOURCE_BUILTIN) { - /* only define each builtin uniform/varying once */ - if (!(builtins & input->builtin)) { - builtins |= input->builtin; - name = gpu_builtin_name(input->builtin); - - if (BLI_str_startswith(name, "unf")) { - BLI_dynstr_appendf(ds, "uniform %s %s;\n", gpu_data_type_to_string(input->type), name); - } - else { - BLI_dynstr_appendf(ds, "in %s %s;\n", gpu_data_type_to_string(input->type), name); - } - } - } - else if (input->source == GPU_SOURCE_STRUCT) { - /* Add other struct here if needed. */ - BLI_dynstr_appendf(ds, "Closure strct%d = CLOSURE_DEFAULT;\n", input->id); - } - else if (input->source == GPU_SOURCE_UNIFORM) { - if (!input->link) { - /* We handle the UBOuniforms separately. */ - BLI_addtail(&ubo_inputs, BLI_genericNodeN(input)); - } - } - else if (input->source == GPU_SOURCE_CONSTANT) { - BLI_dynstr_appendf( - ds, "const %s cons%d = ", gpu_data_type_to_string(input->type), input->id); - codegen_print_datatype(ds, input->type, input->vec); - BLI_dynstr_append(ds, ";\n"); - } - } - } - - /* Handle the UBO block separately. */ - if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) { - GPU_material_uniform_buffer_create(material, &ubo_inputs); - - /* Inputs are sorted */ - BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME); - - LISTBASE_FOREACH (LinkData *, link, &ubo_inputs) { - GPUInput *input = (GPUInput *)(link->data); - BLI_dynstr_appendf(ds, " %s unf%d;\n", gpu_data_type_to_string(input->type), input->id); - } - BLI_dynstr_append(ds, "};\n"); - BLI_freelistN(&ubo_inputs); - } - - /* Generate the uniform attribute UBO if necessary. */ - if (!BLI_listbase_is_empty(&graph->uniform_attrs.list)) { - BLI_dynstr_append(ds, "\nstruct UniformAttributes {\n"); - LISTBASE_FOREACH (GPUUniformAttr *, attr, &graph->uniform_attrs.list) { - BLI_dynstr_appendf(ds, " vec4 attr%d;\n", attr->id); - } - BLI_dynstr_append(ds, "};\n"); - BLI_dynstr_appendf(ds, "layout (std140) uniform %s {\n", GPU_ATTRIBUTE_UBO_BLOCK_NAME); - BLI_dynstr_append(ds, " UniformAttributes uniform_attrs[DRW_RESOURCE_CHUNK_LEN];\n"); - BLI_dynstr_append(ds, "};\n"); - BLI_dynstr_append(ds, "#define GET_UNIFORM_ATTR(name) (uniform_attrs[resource_id].name)\n"); - } - - BLI_dynstr_append(ds, "\n"); - - return builtins; -} - -static void codegen_declare_tmps(DynStr *ds, GPUNodeGraph *graph) -{ - LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) { - /* declare temporary variables for node output storage */ - LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) { - if (output->type == GPU_CLOSURE) { - BLI_dynstr_appendf(ds, " Closure tmp%d;\n", output->id); - } - else { - BLI_dynstr_appendf(ds, " %s tmp%d;\n", gpu_data_type_to_string(output->type), output->id); - } - } - } - BLI_dynstr_append(ds, "\n"); -} - -static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph) -{ - LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) { - BLI_dynstr_appendf(ds, " %s(", node->name); - - LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { - if (input->source == GPU_SOURCE_TEX) { - BLI_dynstr_append(ds, input->texture->sampler_name); - } - else if (input->source == GPU_SOURCE_TEX_TILED_MAPPING) { - BLI_dynstr_append(ds, input->texture->tiled_mapping_name); - } - else if (input->source == GPU_SOURCE_VOLUME_GRID) { - BLI_dynstr_append(ds, input->volume_grid->sampler_name); - } - else if (input->source == GPU_SOURCE_VOLUME_GRID_TRANSFORM) { - BLI_dynstr_append(ds, input->volume_grid->transform_name); - } - else if (input->source == GPU_SOURCE_OUTPUT) { - codegen_convert_datatype( - ds, input->link->output->type, input->type, "tmp", input->link->output->id); - } - else if (input->source == GPU_SOURCE_BUILTIN) { - /* TODO(fclem): get rid of that. */ - if (input->builtin == GPU_INVERSE_VIEW_MATRIX) { - BLI_dynstr_append(ds, "viewinv"); - } - else if (input->builtin == GPU_VIEW_MATRIX) { - BLI_dynstr_append(ds, "viewmat"); - } - else if (input->builtin == GPU_CAMERA_TEXCO_FACTORS) { - BLI_dynstr_append(ds, "camtexfac"); - } - else if (input->builtin == GPU_LOC_TO_VIEW_MATRIX) { - BLI_dynstr_append(ds, "localtoviewmat"); - } - else if (input->builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) { - BLI_dynstr_append(ds, "invlocaltoviewmat"); - } - else if (input->builtin == GPU_BARYCENTRIC_DIST) { - BLI_dynstr_append(ds, "barycentricDist"); - } - else if (input->builtin == GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_append(ds, "barytexco"); - } - else if (input->builtin == GPU_OBJECT_MATRIX) { - BLI_dynstr_append(ds, "objmat"); - } - else if (input->builtin == GPU_OBJECT_INFO) { - BLI_dynstr_append(ds, "ObjectInfo"); - } - else if (input->builtin == GPU_OBJECT_COLOR) { - BLI_dynstr_append(ds, "ObjectColor"); - } - else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) { - BLI_dynstr_append(ds, "objinv"); - } - else if (input->builtin == GPU_VIEW_POSITION) { - BLI_dynstr_append(ds, "viewposition"); - } - else if (input->builtin == GPU_VIEW_NORMAL) { - BLI_dynstr_append(ds, "facingnormal"); - } - else if (input->builtin == GPU_WORLD_NORMAL) { - BLI_dynstr_append(ds, "facingwnormal"); - } - else { - BLI_dynstr_append(ds, gpu_builtin_name(input->builtin)); - } - } - else if (input->source == GPU_SOURCE_STRUCT) { - BLI_dynstr_appendf(ds, "strct%d", input->id); - } - else if (input->source == GPU_SOURCE_UNIFORM) { - BLI_dynstr_appendf(ds, "unf%d", input->id); - } - else if (input->source == GPU_SOURCE_CONSTANT) { - BLI_dynstr_appendf(ds, "cons%d", input->id); - } - else if (input->source == GPU_SOURCE_ATTR) { - codegen_convert_datatype(ds, input->attr->gputype, input->type, "var", input->attr->id); - } - else if (input->source == GPU_SOURCE_UNIFORM_ATTR) { - BLI_dynstr_appendf(ds, "GET_UNIFORM_ATTR(attr%d)", input->uniform_attr->id); - } - - BLI_dynstr_append(ds, ", "); - } - - LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) { - BLI_dynstr_appendf(ds, "tmp%d", output->id); - if (output->next) { - BLI_dynstr_append(ds, ", "); - } - } - - BLI_dynstr_append(ds, ");\n"); - } -} - -static void codegen_final_output(DynStr *ds, GPUOutput *finaloutput) -{ - BLI_dynstr_appendf(ds, "return tmp%d;\n", finaloutput->id); -} - -static char *code_generate_fragment(GPUMaterial *material, - GPUNodeGraph *graph, - const char *interface_str) -{ - DynStr *ds = BLI_dynstr_new(); - char *code; - int builtins; - - codegen_set_unique_ids(graph); - - /* Attributes, Shader stage interface. */ - if (interface_str) { - BLI_dynstr_appendf(ds, "in codegenInterface {%s};\n\n", interface_str); - } - - builtins = codegen_process_uniforms_functions(material, ds, graph); - - if (builtins & (GPU_OBJECT_INFO | GPU_OBJECT_COLOR)) { - BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl); - } - - if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl); - } - - BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n"); - - if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_append(ds, " vec2 barytexco = barycentric_resolve(barycentricTexCo);\n"); - } - /* TODO(fclem): get rid of that. */ - if (builtins & GPU_VIEW_MATRIX) { - BLI_dynstr_append(ds, " #define viewmat ViewMatrix\n"); - } - if (builtins & GPU_CAMERA_TEXCO_FACTORS) { - BLI_dynstr_append(ds, " #define camtexfac CameraTexCoFactors\n"); - } - if (builtins & GPU_OBJECT_MATRIX) { - BLI_dynstr_append(ds, " #define objmat ModelMatrix\n"); - } - if (builtins & GPU_INVERSE_OBJECT_MATRIX) { - BLI_dynstr_append(ds, " #define objinv ModelMatrixInverse\n"); - } - if (builtins & GPU_INVERSE_VIEW_MATRIX) { - BLI_dynstr_append(ds, " #define viewinv ViewMatrixInverse\n"); - } - if (builtins & GPU_LOC_TO_VIEW_MATRIX) { - BLI_dynstr_append(ds, " #define localtoviewmat (ViewMatrix * ModelMatrix)\n"); - } - if (builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) { - BLI_dynstr_append(ds, - " #define invlocaltoviewmat (ModelMatrixInverse * ViewMatrixInverse)\n"); - } - if (builtins & GPU_VIEW_NORMAL) { - BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); - BLI_dynstr_append(ds, " vec3 n;\n"); - BLI_dynstr_append(ds, " world_normals_get(n);\n"); - BLI_dynstr_append(ds, " vec3 facingnormal = transform_direction(ViewMatrix, n);\n"); - BLI_dynstr_append(ds, "#else\n"); - BLI_dynstr_append(ds, " vec3 facingnormal = gl_FrontFacing ? viewNormal: -viewNormal;\n"); - BLI_dynstr_append(ds, "#endif\n"); - } - if (builtins & GPU_WORLD_NORMAL) { - BLI_dynstr_append(ds, " vec3 facingwnormal;\n"); - if (builtins & GPU_VIEW_NORMAL) { - BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); - BLI_dynstr_append(ds, " facingwnormal = n;\n"); - BLI_dynstr_append(ds, "#else\n"); - BLI_dynstr_append(ds, " world_normals_get(facingwnormal);\n"); - BLI_dynstr_append(ds, "#endif\n"); - } - else { - BLI_dynstr_append(ds, " world_normals_get(facingwnormal);\n"); - } - } - if (builtins & GPU_VIEW_POSITION) { - BLI_dynstr_append(ds, " #define viewposition viewPosition\n"); - } - - codegen_declare_tmps(ds, graph); - codegen_call_functions(ds, graph); - - BLI_dynstr_append(ds, " #ifndef VOLUMETRICS\n"); - BLI_dynstr_append(ds, " if (renderPassAOV) {\n"); - BLI_dynstr_append(ds, " switch (render_pass_aov_hash()) {\n"); - GSet *aovhashes_added = BLI_gset_int_new(__func__); - LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) { - void *aov_key = POINTER_FROM_INT(aovlink->hash); - if (BLI_gset_haskey(aovhashes_added, aov_key)) { - continue; - } - BLI_dynstr_appendf(ds, " case %d: {\n ", aovlink->hash); - codegen_final_output(ds, aovlink->outlink->output); - BLI_dynstr_append(ds, " }\n"); - BLI_gset_add(aovhashes_added, aov_key); - } - BLI_gset_free(aovhashes_added, NULL); - BLI_dynstr_append(ds, " default: {\n"); - BLI_dynstr_append(ds, " Closure no_aov = CLOSURE_DEFAULT;\n"); - BLI_dynstr_append(ds, " no_aov.holdout = 1.0;\n"); - BLI_dynstr_append(ds, " return no_aov;\n"); - BLI_dynstr_append(ds, " }\n"); - BLI_dynstr_append(ds, " }\n"); - BLI_dynstr_append(ds, " } else {\n"); - BLI_dynstr_append(ds, " #else /* VOLUMETRICS */\n"); - BLI_dynstr_append(ds, " {\n"); - BLI_dynstr_append(ds, " #endif /* VOLUMETRICS */\n "); - codegen_final_output(ds, graph->outlink->output); - BLI_dynstr_append(ds, " }\n"); - - BLI_dynstr_append(ds, "}\n"); - - /* create shader */ - code = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - -#if 0 - if (G.debug & G_DEBUG) { - printf("%s\n", code); - } -#endif - - return code; -} - -static const char *attr_prefix_get(CustomDataType type) -{ - switch (type) { - case CD_ORCO: - return "orco"; - case CD_MTFACE: - return "u"; - case CD_TANGENT: - return "t"; - case CD_MCOL: - case CD_MLOOPCOL: - return "c"; - case CD_PROP_COLOR: - return "c"; - case CD_AUTO_FROM_NAME: - return "a"; - case CD_HAIRLENGTH: - return "hl"; - default: - BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!"); - return ""; - } -} - -/* We talk about shader stage interface, not to be mistaken with GPUShaderInterface. */ -static char *code_generate_interface(GPUNodeGraph *graph, int builtins) -{ - if (BLI_listbase_is_empty(&graph->attributes) && - (builtins & (GPU_BARYCENTRIC_DIST | GPU_BARYCENTRIC_TEXCO)) == 0) { - return NULL; - } - - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, "\n"); - - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { - if (attr->type == CD_HAIRLENGTH) { - BLI_dynstr_appendf(ds, "float var%d;\n", attr->id); - } - else { - BLI_dynstr_appendf(ds, "%s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id); - } - } - if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_append(ds, "vec2 barycentricTexCo;\n"); - } - if (builtins & GPU_BARYCENTRIC_DIST) { - BLI_dynstr_append(ds, "vec3 barycentricDist;\n"); - } - - char *code = BLI_dynstr_get_cstring(ds); - - BLI_dynstr_free(ds); - - return code; -} - -static char *code_generate_vertex(GPUNodeGraph *graph, - const char *interface_str, - const char *vert_code, - int builtins) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl); - - /* Inputs */ - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { - const char *type_str = gpu_data_type_to_string(attr->gputype); - const char *prefix = attr_prefix_get(attr->type); - /* XXX FIXME: see notes in mesh_render_data_create() */ - /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ - if (attr->type == CD_ORCO) { - /* OPTI: orco is computed from local positions, but only if no modifier is present. */ - BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl); - BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n"); - } - else if (attr->type == CD_HAIRLENGTH) { - BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl); - BLI_dynstr_append(ds, "DEFINE_ATTR(float, hairLen);\n"); - } - else if (attr->name[0] == '\0') { - BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s);\n", type_str, prefix); - BLI_dynstr_appendf(ds, "#define att%d %s\n", attr->id, prefix); - } - else { - char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - GPU_vertformat_safe_attr_name(attr->name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); - BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s%s);\n", type_str, prefix, attr_safe_name); - BLI_dynstr_appendf(ds, "#define att%d %s%s\n", attr->id, prefix, attr_safe_name); - } - } - - /* Outputs interface */ - if (interface_str) { - BLI_dynstr_appendf(ds, "out codegenInterface {%s};\n\n", interface_str); - } - - /* Prototype. Needed for hair functions. */ - BLI_dynstr_append(ds, "void pass_attr(vec3 position, mat3 normalmat, mat4 modelmatinv);\n"); - BLI_dynstr_append(ds, "#define USE_ATTR\n\n"); - - BLI_dynstr_append(ds, vert_code); - BLI_dynstr_append(ds, "\n\n"); - - BLI_dynstr_append(ds, "void pass_attr(vec3 position, mat3 normalmat, mat4 modelmatinv) {\n"); - - /* GPU_BARYCENTRIC_TEXCO cannot be computed based on gl_VertexID - * for MESH_SHADER because of indexed drawing. In this case a - * geometry shader is needed. */ - if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_appendf(ds, " barycentricTexCo = barycentric_get();\n"); - } - if (builtins & GPU_BARYCENTRIC_DIST) { - BLI_dynstr_appendf(ds, " barycentricDist = vec3(0);\n"); - } - - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { - if (attr->type == CD_TANGENT) { /* silly exception */ - BLI_dynstr_appendf(ds, " var%d = tangent_get(att%d, normalmat);\n", attr->id, attr->id); - } - else if (attr->type == CD_ORCO) { - BLI_dynstr_appendf( - ds, " var%d = orco_get(position, modelmatinv, OrcoTexCoFactors, orco);\n", attr->id); - } - else if (attr->type == CD_HAIRLENGTH) { - BLI_dynstr_appendf(ds, " var%d = hair_len_get(hair_get_strand_id(), hairLen);\n", attr->id); - } - else { - const char *type_str = gpu_data_type_to_string(attr->gputype); - BLI_dynstr_appendf(ds, " var%d = GET_ATTR(%s, att%d);\n", attr->id, type_str, attr->id); - } - } - - BLI_dynstr_append(ds, "}\n"); - - char *code = BLI_dynstr_get_cstring(ds); - - BLI_dynstr_free(ds); - -#if 0 - if (G.debug & G_DEBUG) { - printf("%s\n", code); - } -#endif - - return code; -} - -static char *code_generate_geometry(GPUNodeGraph *graph, - const char *interface_str, - const char *geom_code, - int builtins) -{ - if (!geom_code) { - return NULL; - } - - DynStr *ds = BLI_dynstr_new(); - - /* Attributes, Shader interface; */ - if (interface_str) { - BLI_dynstr_appendf(ds, "in codegenInterface {%s} dataAttrIn[];\n\n", interface_str); - BLI_dynstr_appendf(ds, "out codegenInterface {%s} dataAttrOut;\n\n", interface_str); - } - - BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl); - - if (builtins & GPU_BARYCENTRIC_DIST) { - /* geom_code should do something with this, but may not. */ - BLI_dynstr_append(ds, "#define DO_BARYCENTRIC_DISTANCES\n"); - } - - /* Generate varying assignments. */ - BLI_dynstr_append(ds, "#define USE_ATTR\n"); - /* This needs to be a define. Some drivers don't like variable vert index inside dataAttrIn. */ - BLI_dynstr_append(ds, "#define pass_attr(vert) {\\\n"); - - if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_append(ds, "dataAttrOut.barycentricTexCo = calc_barycentric_co(vert);\\\n"); - } - - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { - /* TODO: let shader choose what to do depending on what the attribute is. */ - BLI_dynstr_appendf(ds, "dataAttrOut.var%d = dataAttrIn[vert].var%d;\\\n", attr->id, attr->id); - } - BLI_dynstr_append(ds, "}\n\n"); - - BLI_dynstr_append(ds, geom_code); - - char *code = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return code; -} - -GPUShader *GPU_pass_shader_get(GPUPass *pass) -{ - return pass->shader; -} - -/* Pass create/free */ - -static bool gpu_pass_is_valid(GPUPass *pass) -{ - /* Shader is not null if compilation is successful. */ - return (pass->compiled == false || pass->shader != NULL); -} - -GPUPass *GPU_generate_pass(GPUMaterial *material, - GPUNodeGraph *graph, - const char *vert_code, - const char *geom_code, - const char *frag_lib, - const char *defines) -{ - /* Prune the unused nodes and extract attributes before compiling so the - * generated VBOs are ready to accept the future shader. */ - gpu_node_graph_prune_unused(graph); - gpu_node_graph_finalize_uniform_attrs(graph); - - int builtins = 0; - LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) { - LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { - if (input->source == GPU_SOURCE_BUILTIN) { - builtins |= input->builtin; - } - } - } - /* generate code */ - char *interface_str = code_generate_interface(graph, builtins); - char *fragmentgen = code_generate_fragment(material, graph, interface_str); - - /* Cache lookup: Reuse shaders already compiled */ - uint32_t hash = gpu_pass_hash(fragmentgen, defines, &graph->attributes); - GPUPass *pass_hash = gpu_pass_cache_lookup(hash); - - if (pass_hash && (pass_hash->next == NULL || pass_hash->next->hash != hash)) { - /* No collision, just return the pass. */ - MEM_SAFE_FREE(interface_str); - MEM_freeN(fragmentgen); - if (!gpu_pass_is_valid(pass_hash)) { - /* Shader has already been created but failed to compile. */ - return NULL; - } - pass_hash->refcount += 1; - return pass_hash; - } - - /* Either the shader is not compiled or there is a hash collision... - * continue generating the shader strings. */ - GSet *used_libraries = gpu_material_used_libraries(material); - char *tmp = gpu_material_library_generate_code(used_libraries, frag_lib); - - char *geometrycode = code_generate_geometry(graph, interface_str, geom_code, builtins); - char *vertexcode = code_generate_vertex(graph, interface_str, vert_code, builtins); - char *fragmentcode = BLI_strdupcat(tmp, fragmentgen); - - MEM_SAFE_FREE(interface_str); - MEM_freeN(fragmentgen); - MEM_freeN(tmp); - - GPUPass *pass = NULL; - if (pass_hash) { - /* Cache lookup: Reuse shaders already compiled */ - pass = gpu_pass_cache_resolve_collision( - pass_hash, vertexcode, geometrycode, fragmentcode, defines, hash); - } - - if (pass) { - MEM_SAFE_FREE(vertexcode); - MEM_SAFE_FREE(fragmentcode); - MEM_SAFE_FREE(geometrycode); - - /* Cache hit. Reuse the same GPUPass and GPUShader. */ - if (!gpu_pass_is_valid(pass)) { - /* Shader has already been created but failed to compile. */ - return NULL; - } - - pass->refcount += 1; - } - else { - /* We still create a pass even if shader compilation - * fails to avoid trying to compile again and again. */ - pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); - pass->shader = NULL; - pass->refcount = 1; - pass->hash = hash; - pass->vertexcode = vertexcode; - pass->fragmentcode = fragmentcode; - pass->geometrycode = geometrycode; - pass->defines = (defines) ? BLI_strdup(defines) : NULL; - pass->compiled = false; - - BLI_spin_lock(&pass_cache_spin); - if (pass_hash != NULL) { - /* Add after the first pass having the same hash. */ - pass->next = pass_hash->next; - pass_hash->next = pass; - } - else { - /* No other pass have same hash, just prepend to the list. */ - BLI_LINKS_PREPEND(pass_cache, pass); - } - BLI_spin_unlock(&pass_cache_spin); - } - - return pass; -} - -static int count_active_texture_sampler(GPUShader *shader, const char *source) -{ - const char *code = source; - - /* Remember this is per stage. */ - GSet *sampler_ids = BLI_gset_int_new(__func__); - int num_samplers = 0; - - while ((code = strstr(code, "uniform "))) { - /* Move past "uniform". */ - code += 7; - /* Skip following spaces. */ - while (*code == ' ') { - code++; - } - /* Skip "i" from potential isamplers. */ - if (*code == 'i') { - code++; - } - /* Skip following spaces. */ - if (BLI_str_startswith(code, "sampler")) { - /* Move past "uniform". */ - code += 7; - /* Skip sampler type suffix. */ - while (!ELEM(*code, ' ', '\0')) { - code++; - } - /* Skip following spaces. */ - while (*code == ' ') { - code++; - } - - if (*code != '\0') { - char sampler_name[64]; - code = gpu_str_skip_token(code, sampler_name, sizeof(sampler_name)); - int id = GPU_shader_get_uniform(shader, sampler_name); - - if (id == -1) { - continue; - } - /* Catch duplicates. */ - if (BLI_gset_add(sampler_ids, POINTER_FROM_INT(id))) { - num_samplers++; - } - } - } - } - - BLI_gset_free(sampler_ids, NULL); - - return num_samplers; -} - -static bool gpu_pass_shader_validate(GPUPass *pass, GPUShader *shader) -{ - if (shader == NULL) { - return false; - } - - /* NOTE: The only drawback of this method is that it will count a sampler - * used in the fragment shader and only declared (but not used) in the vertex - * shader as used by both. But this corner case is not happening for now. */ - int vert_samplers_len = count_active_texture_sampler(shader, pass->vertexcode); - int frag_samplers_len = count_active_texture_sampler(shader, pass->fragmentcode); - - int total_samplers_len = vert_samplers_len + frag_samplers_len; - - /* Validate against opengl limit. */ - if ((frag_samplers_len > GPU_max_textures_frag()) || - (vert_samplers_len > GPU_max_textures_vert())) { - return false; - } - - if (pass->geometrycode) { - int geom_samplers_len = count_active_texture_sampler(shader, pass->geometrycode); - total_samplers_len += geom_samplers_len; - if (geom_samplers_len > GPU_max_textures_geom()) { - return false; - } - } - - return (total_samplers_len <= GPU_max_textures()); -} - -bool GPU_pass_compile(GPUPass *pass, const char *shname) -{ - bool success = true; - if (!pass->compiled) { - GPUShader *shader = GPU_shader_create( - pass->vertexcode, pass->fragmentcode, pass->geometrycode, NULL, pass->defines, shname); - - /* NOTE: Some drivers / gpu allows more active samplers than the opengl limit. - * We need to make sure to count active samplers to avoid undefined behavior. */ - if (!gpu_pass_shader_validate(pass, shader)) { - success = false; - if (shader != NULL) { - fprintf(stderr, "GPUShader: error: too many samplers in shader.\n"); - GPU_shader_free(shader); - shader = NULL; - } - } - pass->shader = shader; - pass->compiled = true; - } - - return success; -} - -void GPU_pass_release(GPUPass *pass) -{ - BLI_assert(pass->refcount > 0); - pass->refcount--; -} - -static void gpu_pass_free(GPUPass *pass) -{ - BLI_assert(pass->refcount == 0); - if (pass->shader) { - GPU_shader_free(pass->shader); - } - MEM_SAFE_FREE(pass->fragmentcode); - MEM_SAFE_FREE(pass->geometrycode); - MEM_SAFE_FREE(pass->vertexcode); - MEM_SAFE_FREE(pass->defines); - MEM_freeN(pass); -} - -void GPU_pass_cache_garbage_collect(void) -{ - static int lasttime = 0; - const int shadercollectrate = 60; /* hardcoded for now. */ - int ctime = (int)PIL_check_seconds_timer(); - - if (ctime < shadercollectrate + lasttime) { - return; - } - - lasttime = ctime; - - BLI_spin_lock(&pass_cache_spin); - GPUPass *next, **prev_pass = &pass_cache; - for (GPUPass *pass = pass_cache; pass; pass = next) { - next = pass->next; - if (pass->refcount == 0) { - /* Remove from list */ - *prev_pass = next; - gpu_pass_free(pass); - } - else { - prev_pass = &pass->next; - } - } - BLI_spin_unlock(&pass_cache_spin); -} - -void GPU_pass_cache_init(void) -{ - BLI_spin_init(&pass_cache_spin); -} - -void GPU_pass_cache_free(void) -{ - BLI_spin_lock(&pass_cache_spin); - while (pass_cache) { - GPUPass *next = pass_cache->next; - gpu_pass_free(pass_cache); - pass_cache = next; - } - BLI_spin_unlock(&pass_cache_spin); - - BLI_spin_end(&pass_cache_spin); -} - -/* Module */ - -void gpu_codegen_init(void) -{ -} - -void gpu_codegen_exit(void) -{ - BKE_material_defaults_free_gpu(); - GPU_shader_free_builtin_shaders(); -} diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc new file mode 100644 index 00000000000..8963fa45c96 --- /dev/null +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -0,0 +1,825 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2005 Blender Foundation. */ + +/** \file + * \ingroup gpu + * + * Convert material node-trees to GLSL. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_customdata_types.h" +#include "DNA_image_types.h" + +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" +#include "BLI_ghash.h" +#include "BLI_hash_mm2a.h" +#include "BLI_link_utils.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "PIL_time.h" + +#include "BKE_material.h" +#include "BKE_world.h" + +#include "GPU_capabilities.h" +#include "GPU_material.h" +#include "GPU_shader.h" +#include "GPU_uniform_buffer.h" +#include "GPU_vertex_format.h" + +#include "BLI_sys_types.h" /* for intptr_t support */ + +#include "gpu_codegen.h" +#include "gpu_material_library.h" +#include "gpu_node_graph.h" +#include "gpu_shader_create_info.hh" +#include "gpu_shader_dependency_private.h" + +#include +#include + +#include +#include + +using namespace blender::gpu::shader; + +struct GPUCodegenCreateInfo : ShaderCreateInfo { + struct NameBuffer { + char attr_names[16][GPU_MAX_SAFE_ATTR_NAME + 1]; + char var_names[16][8]; + }; + + /** Optional generated interface. */ + StageInterfaceInfo *interface_generated = nullptr; + /** Optional name buffer containing names referenced by StringRefNull. */ + NameBuffer *name_buffer = nullptr; + + GPUCodegenCreateInfo(const char *name) : ShaderCreateInfo(name){}; + ~GPUCodegenCreateInfo() + { + delete interface_generated; + MEM_delete(name_buffer); + }; +}; + +struct GPUPass { + struct GPUPass *next; + + GPUShader *shader; + GPUCodegenCreateInfo *create_info = nullptr; + /** Orphaned GPUPasses gets freed by the garbage collector. */ + uint refcount; + /** Identity hash generated from all GLSL code. */ + uint32_t hash; + /** Did we already tried to compile the attached GPUShader. */ + bool compiled; +}; + +/* -------------------------------------------------------------------- */ +/** \name GPUPass Cache + * + * Internal shader cache: This prevent the shader recompilation / stall when + * using undo/redo AND also allows for GPUPass reuse if the Shader code is the + * same for 2 different Materials. Unused GPUPasses are free by Garbage collection. + */ + +/* Only use one linklist that contains the GPUPasses grouped by hash. */ +static GPUPass *pass_cache = nullptr; +static SpinLock pass_cache_spin; + +/* Search by hash only. Return first pass with the same hash. + * There is hash collision if (pass->next && pass->next->hash == hash) */ +static GPUPass *gpu_pass_cache_lookup(uint32_t hash) +{ + BLI_spin_lock(&pass_cache_spin); + /* Could be optimized with a Lookup table. */ + for (GPUPass *pass = pass_cache; pass; pass = pass->next) { + if (pass->hash == hash) { + BLI_spin_unlock(&pass_cache_spin); + return pass; + } + } + BLI_spin_unlock(&pass_cache_spin); + return nullptr; +} + +static void gpu_pass_cache_insert_after(GPUPass *node, GPUPass *pass) +{ + BLI_spin_lock(&pass_cache_spin); + if (node != nullptr) { + /* Add after the first pass having the same hash. */ + pass->next = node->next; + node->next = pass; + } + else { + /* No other pass have same hash, just prepend to the list. */ + BLI_LINKS_PREPEND(pass_cache, pass); + } + BLI_spin_unlock(&pass_cache_spin); +} + +/* Check all possible passes with the same hash. */ +static GPUPass *gpu_pass_cache_resolve_collision(GPUPass *pass, + GPUShaderCreateInfo *info, + uint32_t hash) +{ + BLI_spin_lock(&pass_cache_spin); + for (; pass && (pass->hash == hash); pass = pass->next) { + if (*reinterpret_cast(info) == + *reinterpret_cast(pass->create_info)) { + BLI_spin_unlock(&pass_cache_spin); + return pass; + } + } + BLI_spin_unlock(&pass_cache_spin); + return nullptr; +} + +static bool gpu_pass_is_valid(GPUPass *pass) +{ + /* Shader is not null if compilation is successful. */ + return (pass->compiled == false || pass->shader != nullptr); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Type > string conversion + * \{ */ + +static std::ostream &operator<<(std::ostream &stream, const GPUInput *input) +{ + switch (input->source) { + case GPU_SOURCE_FUNCTION_CALL: + case GPU_SOURCE_OUTPUT: + return stream << "tmp" << input->id; + case GPU_SOURCE_CONSTANT: + return stream << "cons" << input->id; + case GPU_SOURCE_UNIFORM: + return stream << "node_tree.u" << input->id; + case GPU_SOURCE_ATTR: + return stream << "var_attrs.v" << input->attr->id; + case GPU_SOURCE_UNIFORM_ATTR: + return stream << "unf_attrs[resource_id].attr" << input->uniform_attr->id; + case GPU_SOURCE_STRUCT: + return stream << "strct" << input->id; + case GPU_SOURCE_TEX: + return stream << input->texture->sampler_name; + case GPU_SOURCE_TEX_TILED_MAPPING: + return stream << input->texture->tiled_mapping_name; + case GPU_SOURCE_VOLUME_GRID: + return stream << input->volume_grid->sampler_name; + case GPU_SOURCE_VOLUME_GRID_TRANSFORM: + return stream << input->volume_grid->transform_name; + default: + BLI_assert(0); + return stream; + } +} + +static std::ostream &operator<<(std::ostream &stream, const GPUOutput *output) +{ + return stream << "tmp" << output->id; +} + +/* Trick type to change overload and keep a somewhat nice syntax. */ +struct GPUConstant : public GPUInput { +}; + +/* Print data constructor (i.e: vec2(1.0f, 1.0f)). */ +static std::ostream &operator<<(std::ostream &stream, const GPUConstant *input) +{ + stream << input->type << "("; + for (int i = 0; i < input->type; i++) { + char formated_float[32]; + /* Print with the maximum precision for single precision float using scientific notation. + * See https://stackoverflow.com/questions/16839658/#answer-21162120 */ + SNPRINTF(formated_float, "%.9g", input->vec[i]); + stream << formated_float; + if (i < input->type - 1) { + stream << ", "; + } + } + stream << ")"; + return stream; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name GLSL code generation + * \{ */ + +class GPUCodegen { + public: + GPUMaterial &mat; + GPUNodeGraph &graph; + GPUCodegenOutput output = {}; + GPUCodegenCreateInfo *create_info = nullptr; + + private: + uint32_t hash_ = 0; + BLI_HashMurmur2A hm2a_; + ListBase ubo_inputs_ = {nullptr, nullptr}; + + public: + GPUCodegen(GPUMaterial *mat_, GPUNodeGraph *graph_) : mat(*mat_), graph(*graph_) + { + BLI_hash_mm2a_init(&hm2a_, GPU_material_uuid_get(&mat)); + BLI_hash_mm2a_add_int(&hm2a_, GPU_material_flag(&mat)); + create_info = new GPUCodegenCreateInfo("codegen"); + output.create_info = reinterpret_cast( + static_cast(create_info)); + + if (GPU_material_flag_get(mat_, GPU_MATFLAG_OBJECT_INFO)) { + create_info->additional_info("draw_object_infos"); + } + } + + ~GPUCodegen() + { + MEM_SAFE_FREE(output.attr_load); + MEM_SAFE_FREE(output.surface); + MEM_SAFE_FREE(output.volume); + MEM_SAFE_FREE(output.thickness); + MEM_SAFE_FREE(output.displacement); + MEM_SAFE_FREE(output.material_functions); + delete create_info; + BLI_freelistN(&ubo_inputs_); + }; + + void generate_graphs(); + void generate_uniform_buffer(); + void generate_attribs(); + void generate_resources(); + void generate_library(); + + uint32_t hash_get() const + { + return hash_; + } + + private: + void set_unique_ids(); + + void node_serialize(std::stringstream &eval_ss, const GPUNode *node); + char *graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link); + + static char *extract_c_str(std::stringstream &stream) + { + auto string = stream.str(); + return BLI_strdup(string.c_str()); + } +}; + +static char attr_prefix_get(CustomDataType type) +{ + switch (type) { + case CD_MTFACE: + return 'u'; + case CD_TANGENT: + return 't'; + case CD_MCOL: + case CD_MLOOPCOL: + return 'c'; + case CD_PROP_COLOR: + return 'c'; + case CD_AUTO_FROM_NAME: + return 'a'; + case CD_HAIRLENGTH: + return 'l'; + default: + BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!"); + return '\0'; + } +} + +void GPUCodegen::generate_attribs() +{ + if (BLI_listbase_is_empty(&graph.attributes)) { + output.attr_load = nullptr; + return; + } + + GPUCodegenCreateInfo &info = *create_info; + + info.name_buffer = MEM_new("info.name_buffer"); + info.interface_generated = new StageInterfaceInfo("codegen_iface", "var_attrs"); + StageInterfaceInfo &iface = *info.interface_generated; + info.vertex_out(iface); + + /* Input declaration, loading / assignment to interface and geometry shader passthrough. */ + std::stringstream decl_ss, iface_ss, load_ss; + + int slot = 15; + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph.attributes) { + + /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ + if (attr->type == CD_ORCO) { + /* OPTI: orco is computed from local positions, but only if no modifier is present. */ + STRNCPY(info.name_buffer->attr_names[slot], "orco"); + } + else { + char *name = info.name_buffer->attr_names[slot]; + name[0] = attr_prefix_get(static_cast(attr->type)); + name[1] = '\0'; + if (attr->name[0] != '\0') { + /* XXX FIXME: see notes in mesh_render_data_create() */ + GPU_vertformat_safe_attr_name(attr->name, &name[1], GPU_MAX_SAFE_ATTR_NAME); + } + } + SNPRINTF(info.name_buffer->var_names[slot], "v%d", attr->id); + + blender::StringRefNull attr_name = info.name_buffer->attr_names[slot]; + blender::StringRefNull var_name = info.name_buffer->var_names[slot]; + + eGPUType input_type, iface_type; + + load_ss << "var_attrs." << var_name; + switch (attr->type) { + case CD_ORCO: + /* Need vec4 to detect usage of default attribute. */ + input_type = GPU_VEC4; + iface_type = GPU_VEC3; + load_ss << " = attr_load_orco(" << attr_name << ");\n"; + break; + case CD_HAIRLENGTH: + iface_type = input_type = GPU_FLOAT; + load_ss << " = attr_load_" << input_type << "(" << attr_name << ");\n"; + break; + case CD_TANGENT: + iface_type = input_type = GPU_VEC4; + load_ss << " = attr_load_tangent(" << attr_name << ");\n"; + break; + case CD_MTFACE: + iface_type = input_type = GPU_VEC3; + load_ss << " = attr_load_uv(" << attr_name << ");\n"; + break; + case CD_MCOL: + iface_type = input_type = GPU_VEC4; + load_ss << " = attr_load_color(" << attr_name << ");\n"; + break; + default: + iface_type = input_type = GPU_VEC4; + load_ss << " = attr_load_" << input_type << "(" << attr_name << ");\n"; + break; + } + + info.vertex_in(slot--, to_type(input_type), attr_name); + iface.smooth(to_type(iface_type), var_name); + } + + output.attr_load = extract_c_str(load_ss); +} + +void GPUCodegen::generate_resources() +{ + GPUCodegenCreateInfo &info = *create_info; + + std::stringstream ss; + + /* Textures. */ + LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) { + if (tex->colorband) { + info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->sampler_name, Frequency::BATCH); + } + else if (tex->tiled_mapping_name[0] != '\0') { + info.sampler(0, ImageType::FLOAT_2D_ARRAY, tex->sampler_name, Frequency::BATCH); + info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->tiled_mapping_name, Frequency::BATCH); + } + else { + info.sampler(0, ImageType::FLOAT_2D, tex->sampler_name, Frequency::BATCH); + } + } + /* Volume Grids. */ + LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph.volume_grids) { + info.sampler(0, ImageType::FLOAT_3D, grid->sampler_name, Frequency::BATCH); + /* TODO(@fclem): Global uniform. To put in an UBO. */ + info.push_constant(Type::MAT4, grid->transform_name); + } + + if (!BLI_listbase_is_empty(&ubo_inputs_)) { + /* NOTE: generate_uniform_buffer() should have sorted the inputs before this. */ + ss << "struct NodeTree {\n"; + LISTBASE_FOREACH (LinkData *, link, &ubo_inputs_) { + GPUInput *input = (GPUInput *)(link->data); + ss << input->type << " u" << input->id << ";\n"; + } + ss << "};\n\n"; + + info.uniform_buf(0, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH); + } + + if (!BLI_listbase_is_empty(&graph.uniform_attrs.list)) { + ss << "struct UniformAttrs {\n"; + LISTBASE_FOREACH (GPUUniformAttr *, attr, &graph.uniform_attrs.list) { + ss << "vec4 attr" << attr->id << ";\n"; + } + ss << "};\n\n"; + + /* TODO(fclem): Use the macro for length. Currently not working for EEVEE. */ + /* DRW_RESOURCE_CHUNK_LEN = 512 */ + info.uniform_buf(0, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH); + } + + info.typedef_source_generated = ss.str(); +} + +void GPUCodegen::generate_library() +{ + GPUCodegenCreateInfo &info = *create_info; + + void *value; + GSetIterState pop_state = {}; + while (BLI_gset_pop(graph.used_libraries, &pop_state, &value)) { + auto deps = gpu_shader_dependency_get_resolved_source((const char *)value); + info.dependencies_generated.extend_non_duplicates(deps); + } +} + +void GPUCodegen::node_serialize(std::stringstream &eval_ss, const GPUNode *node) +{ + /* Declare constants. */ + LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { + switch (input->source) { + case GPU_SOURCE_FUNCTION_CALL: + eval_ss << input->type << " " << input << "; " << input->function_call << input << ");\n"; + break; + case GPU_SOURCE_STRUCT: + eval_ss << input->type << " " << input << " = CLOSURE_DEFAULT;\n"; + break; + case GPU_SOURCE_CONSTANT: + eval_ss << input->type << " " << input << " = " << (GPUConstant *)input << ";\n"; + break; + default: + break; + } + } + /* Declare temporary variables for node output storage. */ + LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) { + eval_ss << output->type << " " << output << ";\n"; + } + + /* Function call. */ + eval_ss << node->name << "("; + /* Input arguments. */ + LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { + switch (input->source) { + case GPU_SOURCE_OUTPUT: + case GPU_SOURCE_ATTR: { + /* These inputs can have non matching types. Do conversion. */ + eGPUType to = input->type; + eGPUType from = (input->source == GPU_SOURCE_ATTR) ? input->attr->gputype : + input->link->output->type; + if (from != to) { + /* Use defines declared inside codegen_lib (i.e: vec4_from_float). */ + eval_ss << to << "_from_" << from << "("; + } + + if (input->source == GPU_SOURCE_ATTR) { + eval_ss << input; + } + else { + eval_ss << input->link->output; + } + + if (from != to) { + eval_ss << ")"; + } + break; + } + default: + eval_ss << input; + break; + } + eval_ss << ", "; + } + /* Output arguments. */ + LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) { + eval_ss << output; + if (output->next) { + eval_ss << ", "; + } + } + eval_ss << ");\n\n"; +} + +char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link) +{ + if (output_link == nullptr) { + return nullptr; + } + + std::stringstream eval_ss; + /* NOTE: The node order is already top to bottom (or left to right in node editor) + * because of the evaluation order inside ntreeExecGPUNodes(). */ + LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) { + if ((node->tag & tree_tag) == 0) { + continue; + } + node_serialize(eval_ss, node); + } + eval_ss << "return " << output_link->output << ";\n"; + + char *eval_c_str = extract_c_str(eval_ss); + BLI_hash_mm2a_add(&hm2a_, (uchar *)eval_c_str, eval_ss.str().size()); + return eval_c_str; +} + +void GPUCodegen::generate_uniform_buffer() +{ + /* Extract uniform inputs. */ + LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) { + LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { + if (input->source == GPU_SOURCE_UNIFORM && !input->link) { + /* We handle the UBO uniforms separately. */ + BLI_addtail(&ubo_inputs_, BLI_genericNodeN(input)); + } + } + } + if (!BLI_listbase_is_empty(&ubo_inputs_)) { + /* This sorts the inputs based on size. */ + GPU_material_uniform_buffer_create(&mat, &ubo_inputs_); + } +} + +/* Sets id for unique names for all inputs, resources and temp variables. */ +void GPUCodegen::set_unique_ids() +{ + int id = 1; + LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) { + LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { + input->id = id++; + } + LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) { + output->id = id++; + } + } +} + +void GPUCodegen::generate_graphs() +{ + set_unique_ids(); + + output.surface = graph_serialize(GPU_NODE_TAG_SURFACE | GPU_NODE_TAG_AOV, graph.outlink_surface); + output.volume = graph_serialize(GPU_NODE_TAG_VOLUME, graph.outlink_volume); + output.displacement = graph_serialize(GPU_NODE_TAG_DISPLACEMENT, graph.outlink_displacement); + output.thickness = graph_serialize(GPU_NODE_TAG_THICKNESS, graph.outlink_thickness); + + if (!BLI_listbase_is_empty(&graph.material_functions)) { + std::stringstream eval_ss; + eval_ss << "\n/* Generated Functions */\n\n"; + LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, func_link, &graph.material_functions) { + char *fn = graph_serialize(GPU_NODE_TAG_FUNCTION, func_link->outlink); + eval_ss << "float " << func_link->name << "() {\n" << fn << "}\n\n"; + MEM_SAFE_FREE(fn); + } + output.material_functions = extract_c_str(eval_ss); + } + + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph.attributes) { + BLI_hash_mm2a_add(&hm2a_, (uchar *)attr->name, strlen(attr->name)); + } + + hash_ = BLI_hash_mm2a_end(&hm2a_); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name GPUPass + * \{ */ + +GPUPass *GPU_generate_pass(GPUMaterial *material, + GPUNodeGraph *graph, + GPUCodegenCallbackFn finalize_source_cb, + void *thunk) +{ + /* Prune the unused nodes and extract attributes before compiling so the + * generated VBOs are ready to accept the future shader. */ + gpu_node_graph_prune_unused(graph); + gpu_node_graph_finalize_uniform_attrs(graph); + + GPUCodegen codegen(material, graph); + codegen.generate_graphs(); + codegen.generate_uniform_buffer(); + + /* Cache lookup: Reuse shaders already compiled. */ + GPUPass *pass_hash = gpu_pass_cache_lookup(codegen.hash_get()); + + /* FIXME(fclem): This is broken. Since we only check for the hash and not the full source + * there is no way to have a collision currently. Some advocated to only use a bigger hash. */ + if (pass_hash && (pass_hash->next == nullptr || pass_hash->next->hash != codegen.hash_get())) { + if (!gpu_pass_is_valid(pass_hash)) { + /* Shader has already been created but failed to compile. */ + return nullptr; + } + /* No collision, just return the pass. */ + pass_hash->refcount += 1; + return pass_hash; + } + + /* Either the shader is not compiled or there is a hash collision... + * continue generating the shader strings. */ + codegen.generate_attribs(); + codegen.generate_resources(); + codegen.generate_library(); + + /* Make engine add its own code and implement the generated functions. */ + finalize_source_cb(thunk, material, &codegen.output); + + GPUPass *pass = nullptr; + if (pass_hash) { + /* Cache lookup: Reuse shaders already compiled. */ + pass = gpu_pass_cache_resolve_collision( + pass_hash, codegen.output.create_info, codegen.hash_get()); + } + + if (pass) { + /* Cache hit. Reuse the same GPUPass and GPUShader. */ + if (!gpu_pass_is_valid(pass)) { + /* Shader has already been created but failed to compile. */ + return nullptr; + } + pass->refcount += 1; + } + else { + /* We still create a pass even if shader compilation + * fails to avoid trying to compile again and again. */ + pass = (GPUPass *)MEM_callocN(sizeof(GPUPass), "GPUPass"); + pass->shader = nullptr; + pass->refcount = 1; + pass->create_info = codegen.create_info; + pass->hash = codegen.hash_get(); + pass->compiled = false; + + codegen.create_info = nullptr; + + gpu_pass_cache_insert_after(pass_hash, pass); + } + return pass; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Compilation + * \{ */ + +static int count_active_texture_sampler(GPUPass *pass, GPUShader *shader) +{ + int num_samplers = 0; + + for (const ShaderCreateInfo::Resource &res : pass->create_info->pass_resources_) { + if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) { + if (GPU_shader_get_uniform(shader, res.sampler.name.c_str()) != -1) { + num_samplers += 1; + } + } + } + + return num_samplers; +} + +static bool gpu_pass_shader_validate(GPUPass *pass, GPUShader *shader) +{ + if (shader == nullptr) { + return false; + } + + /* NOTE: The only drawback of this method is that it will count a sampler + * used in the fragment shader and only declared (but not used) in the vertex + * shader as used by both. But this corner case is not happening for now. */ + int active_samplers_len = count_active_texture_sampler(pass, shader); + + /* Validate against opengl limit. */ + if ((active_samplers_len > GPU_max_textures_frag()) || + (active_samplers_len > GPU_max_textures_vert())) { + return false; + } + + if (pass->create_info->geometry_source_.is_empty() == false) { + if (active_samplers_len > GPU_max_textures_geom()) { + return false; + } + } + + return (active_samplers_len * 3 <= GPU_max_textures()); +} + +bool GPU_pass_compile(GPUPass *pass, const char *shname) +{ + bool success = true; + if (!pass->compiled) { + GPUShaderCreateInfo *info = reinterpret_cast( + static_cast(pass->create_info)); + + pass->create_info->name_ = shname; + + GPUShader *shader = GPU_shader_create_from_info(info); + + /* NOTE: Some drivers / gpu allows more active samplers than the opengl limit. + * We need to make sure to count active samplers to avoid undefined behavior. */ + if (!gpu_pass_shader_validate(pass, shader)) { + success = false; + if (shader != nullptr) { + fprintf(stderr, "GPUShader: error: too many samplers in shader.\n"); + GPU_shader_free(shader); + shader = nullptr; + } + } + pass->shader = shader; + pass->compiled = true; + } + return success; +} + +GPUShader *GPU_pass_shader_get(GPUPass *pass) +{ + return pass->shader; +} + +void GPU_pass_release(GPUPass *pass) +{ + BLI_assert(pass->refcount > 0); + pass->refcount--; +} + +static void gpu_pass_free(GPUPass *pass) +{ + BLI_assert(pass->refcount == 0); + if (pass->shader) { + GPU_shader_free(pass->shader); + } + delete pass->create_info; + MEM_freeN(pass); +} + +void GPU_pass_cache_garbage_collect(void) +{ + static int lasttime = 0; + const int shadercollectrate = 60; /* hardcoded for now. */ + int ctime = (int)PIL_check_seconds_timer(); + + if (ctime < shadercollectrate + lasttime) { + return; + } + + lasttime = ctime; + + BLI_spin_lock(&pass_cache_spin); + GPUPass *next, **prev_pass = &pass_cache; + for (GPUPass *pass = pass_cache; pass; pass = next) { + next = pass->next; + if (pass->refcount == 0) { + /* Remove from list */ + *prev_pass = next; + gpu_pass_free(pass); + } + else { + prev_pass = &pass->next; + } + } + BLI_spin_unlock(&pass_cache_spin); +} + +void GPU_pass_cache_init(void) +{ + BLI_spin_init(&pass_cache_spin); +} + +void GPU_pass_cache_free(void) +{ + BLI_spin_lock(&pass_cache_spin); + while (pass_cache) { + GPUPass *next = pass_cache->next; + gpu_pass_free(pass_cache); + pass_cache = next; + } + BLI_spin_unlock(&pass_cache_spin); + + BLI_spin_end(&pass_cache_spin); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Module + * \{ */ + +void gpu_codegen_init(void) +{ +} + +void gpu_codegen_exit(void) +{ + // BKE_world_defaults_free_gpu(); + BKE_material_defaults_free_gpu(); + GPU_shader_free_builtin_shaders(); +} + +/** \} */ \ No newline at end of file diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 0e99476d3ea..95a672c0400 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -9,36 +9,24 @@ #pragma once +#include "GPU_material.h" +#include "GPU_shader.h" + #ifdef __cplusplus extern "C" { #endif -struct GPUMaterial; struct GPUNodeGraph; -struct GPUShader; - -typedef struct GPUPass { - struct GPUPass *next; - struct GPUShader *shader; - char *fragmentcode; - char *geometrycode; - char *vertexcode; - char *defines; - uint refcount; /* Orphaned GPUPasses gets freed by the garbage collector. */ - uint32_t hash; /* Identity hash generated from all GLSL code. */ - bool compiled; /* Did we already tried to compile the attached GPUShader. */ -} GPUPass; +typedef struct GPUPass GPUPass; /* Pass */ -GPUPass *GPU_generate_pass(struct GPUMaterial *material, +GPUPass *GPU_generate_pass(GPUMaterial *material, struct GPUNodeGraph *graph, - const char *vert_code, - const char *geom_code, - const char *frag_lib, - const char *defines); -struct GPUShader *GPU_pass_shader_get(GPUPass *pass); + GPUCodegenCallbackFn finalize_source_cb, + void *thunk); +GPUShader *GPU_pass_shader_get(GPUPass *pass); bool GPU_pass_compile(GPUPass *pass, const char *shname); void GPU_pass_release(GPUPass *pass); diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 7ccb0f89dc3..e97c9e9c829 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -39,7 +39,6 @@ void GPU_init(void) gpu_shader_create_info_init(); gpu_codegen_init(); - gpu_material_library_init(); gpu_batch_init(); @@ -56,7 +55,6 @@ void GPU_exit(void) gpu_batch_exit(); - gpu_material_library_exit(); gpu_codegen_exit(); gpu_shader_dependency_exit(); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 49732240125..711a3943a25 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -16,7 +16,6 @@ #include "DNA_scene_types.h" #include "DNA_world_types.h" -#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string.h" @@ -27,6 +26,7 @@ #include "BKE_material.h" #include "BKE_node.h" #include "BKE_scene.h" +#include "BKE_world.h" #include "NOD_shader.h" @@ -49,56 +49,50 @@ typedef struct GPUColorBandBuilder { } GPUColorBandBuilder; struct GPUMaterial { - Scene *scene; /* DEPRECATED was only useful for lights. */ - Material *ma; - + /* Contains GPUShader and source code for deferred compilation. + * Can be shared between similar material (i.e: sharing same nodetree topology). */ + GPUPass *pass; + /** UBOs for this material parameters. */ + GPUUniformBuf *ubo; + /** Compilation status. Do not use if shader is not GPU_MAT_SUCCESS. */ eGPUMaterialStatus status; - - const void *engine_type; /* attached engine type */ - int options; /* to identify shader variations (shadow, probe, world background...) */ - bool is_volume_shader; /* is volumetric shader */ - - /* Nodes */ + /** Some flags about the nodetree & the needed resources. */ + eGPUMaterialFlag flag; + /* Identify shader variations (shadow, probe, world background...). + * Should be unique even across render engines. */ + uint64_t uuid; + /* Number of generated function. */ + int generated_function_len; + /** Object type for attribute fetching. */ + bool is_volume_shader; + + /** DEPRECATED Currently only used for deferred compilation. */ + Scene *scene; + /** Source material, might be null. */ + Material *ma; + /** 1D Texture array containing all color bands. */ + GPUTexture *coba_tex; + /** Builder for coba_tex. */ + GPUColorBandBuilder *coba_builder; + /* Low level node graph(s). Also contains resources needed by the material. */ GPUNodeGraph graph; - /* for binding the material */ - GPUPass *pass; - - /* XXX: Should be in Material. But it depends on the output node - * used and since the output selection is different for GPUMaterial... - */ - bool has_volume_output; + /** DEPRECATED: To remove. */ bool has_surface_output; - - /* Only used by Eevee to know which BSDF are used. */ - eGPUMatFlag flag; - - /* Used by 2.8 pipeline */ - GPUUniformBuf *ubo; /* UBOs for shader uniforms. */ - - /* Eevee SSS */ + bool has_volume_output; + /** DEPRECATED: To remove. */ GPUUniformBuf *sss_profile; /* UBO containing SSS profile. */ GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */ - float sss_enabled; + bool sss_enabled; float sss_radii[3]; int sss_samples; bool sss_dirty; - GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */ - GPUColorBandBuilder *coba_builder; - - GSet *used_libraries; - #ifndef NDEBUG char name[64]; #endif }; -enum { - GPU_USE_SURFACE_OUTPUT = (1 << 0), - GPU_USE_VOLUME_OUTPUT = (1 << 1), -}; - /* Functions */ GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, @@ -159,17 +153,15 @@ static void gpu_material_free_single(GPUMaterial *material) if (material->ubo != NULL) { GPU_uniformbuf_free(material->ubo); } - if (material->sss_tex_profile != NULL) { - GPU_texture_free(material->sss_tex_profile); + if (material->coba_tex != NULL) { + GPU_texture_free(material->coba_tex); } if (material->sss_profile != NULL) { GPU_uniformbuf_free(material->sss_profile); } - if (material->coba_tex != NULL) { - GPU_texture_free(material->coba_tex); + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); } - - BLI_gset_free(material->used_libraries, NULL); } void GPU_material_free(ListBase *gpumaterial) @@ -217,17 +209,40 @@ void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs) material->ubo = GPU_uniformbuf_create_from_list(inputs, name); } +ListBase GPU_material_attributes(GPUMaterial *material) +{ + return material->graph.attributes; +} + +ListBase GPU_material_textures(GPUMaterial *material) +{ + return material->graph.textures; +} + +ListBase GPU_material_volume_grids(GPUMaterial *material) +{ + return material->graph.volume_grids; +} + +GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material) +{ + GPUUniformAttrList *attrs = &material->graph.uniform_attrs; + return attrs->count > 0 ? attrs : NULL; +} + +#if 1 /* End of life code. */ /* Eevee Subsurface scattering. */ /* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */ -#define SSS_SAMPLES 65 -#define SSS_EXPONENT 2.0f /* Importance sampling exponent */ +# define SSS_SAMPLES 65 +# define SSS_EXPONENT 2.0f /* Importance sampling exponent */ typedef struct GPUSssKernelData { float kernel[SSS_SAMPLES][4]; float param[3], max_radius; + float avg_inv_radius; int samples; - int pad[3]; + int pad[2]; } GPUSssKernelData; BLI_STATIC_ASSERT_ALIGN(GPUSssKernelData, 16) @@ -243,8 +258,8 @@ static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponen } } -#define BURLEY_TRUNCATE 16.0f -#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE) +# define BURLEY_TRUNCATE 16.0f +# define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE) static float burley_profile(float r, float d) { float exp_r_3_d = expf(-r / (3.0f * d)); @@ -259,7 +274,7 @@ static float eval_profile(float r, float param) } /* Resolution for each sample of the precomputed kernel profile */ -#define INTEGRAL_RESOLUTION 32 +# define INTEGRAL_RESOLUTION 32 static float eval_integral(float x0, float x1, float param) { const float range = x1 - x0; @@ -274,7 +289,7 @@ static float eval_integral(float x0, float x1, float param) return integral; } -#undef INTEGRAL_RESOLUTION +# undef INTEGRAL_RESOLUTION static void compute_sss_kernel(GPUSssKernelData *kd, const float radii[3], int sample_len) { @@ -284,6 +299,8 @@ static void compute_sss_kernel(GPUSssKernelData *kd, const float radii[3], int s rad[1] = MAX2(radii[1], 1e-15f); rad[2] = MAX2(radii[2], 1e-15f); + kd->avg_inv_radius = 3.0f / (rad[0] + rad[1] + rad[2]); + /* Christensen-Burley fitting */ float l[3], d[3]; @@ -358,7 +375,7 @@ static void compute_sss_kernel(GPUSssKernelData *kd, const float radii[3], int s kd->samples = sample_len; } -#define INTEGRAL_RESOLUTION 512 +# define INTEGRAL_RESOLUTION 512 static void compute_sss_translucence_kernel(const GPUSssKernelData *kd, int resolution, float **output) @@ -417,10 +434,14 @@ static void compute_sss_translucence_kernel(const GPUSssKernelData *kd, mul_v3_fl(texels[resolution - 3], 0.5f); mul_v3_fl(texels[resolution - 4], 0.75f); } -#undef INTEGRAL_RESOLUTION +# undef INTEGRAL_RESOLUTION -void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]) +bool GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]) { + /* Enable only once. */ + if (material->sss_enabled) { + return false; + } copy_v3_v3(material->sss_radii, radii); material->sss_dirty = true; material->sss_enabled = true; @@ -429,6 +450,7 @@ void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]) if (material->sss_profile == NULL) { material->sss_profile = GPU_uniformbuf_create(sizeof(GPUSssKernelData)); } + return true; } struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material, @@ -475,34 +497,37 @@ struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void) return GPU_uniformbuf_create(sizeof(GPUSssKernelData)); } -#undef SSS_EXPONENT -#undef SSS_SAMPLES - -ListBase GPU_material_attributes(GPUMaterial *material) -{ - return material->graph.attributes; -} +# undef SSS_EXPONENT +# undef SSS_SAMPLES +#endif -ListBase GPU_material_textures(GPUMaterial *material) +void GPU_material_output_surface(GPUMaterial *material, GPUNodeLink *link) { - return material->graph.textures; + if (!material->graph.outlink_surface) { + material->graph.outlink_surface = link; + material->has_surface_output = true; + } } -ListBase GPU_material_volume_grids(GPUMaterial *material) +void GPU_material_output_volume(GPUMaterial *material, GPUNodeLink *link) { - return material->graph.volume_grids; + if (!material->graph.outlink_volume) { + material->graph.outlink_volume = link; + material->has_volume_output = true; + } } -GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material) +void GPU_material_output_displacement(GPUMaterial *material, GPUNodeLink *link) { - GPUUniformAttrList *attrs = &material->graph.uniform_attrs; - return attrs->count > 0 ? attrs : NULL; + if (!material->graph.outlink_displacement) { + material->graph.outlink_displacement = link; + } } -void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link) +void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link) { - if (!material->graph.outlink) { - material->graph.outlink = link; + if (!material->graph.outlink_thickness) { + material->graph.outlink_thickness = link; } } @@ -514,23 +539,71 @@ void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, BLI_addtail(&material->graph.outlink_aovs, aov_link); } +char *GPU_material_split_sub_function(GPUMaterial *material, + eGPUType return_type, + GPUNodeLink **link) +{ + /* Force cast to return type. */ + switch (return_type) { + case GPU_FLOAT: + GPU_link(material, "set_value", *link, link); + break; + case GPU_VEC3: + GPU_link(material, "set_rgb", *link, link); + break; + case GPU_VEC4: + GPU_link(material, "set_rgba", *link, link); + break; + default: + BLI_assert(0); + break; + } + + GPUNodeGraphFunctionLink *func_link = MEM_callocN(sizeof(GPUNodeGraphFunctionLink), __func__); + func_link->outlink = *link; + SNPRINTF(func_link->name, "ntree_fn%d", material->generated_function_len++); + BLI_addtail(&material->graph.material_functions, func_link); + + /* Set value to break the link with the main graph. */ + switch (return_type) { + case GPU_FLOAT: + GPU_link(material, "set_value_one", link); + break; + case GPU_VEC3: + GPU_link(material, "set_rgb_one", link); + break; + case GPU_VEC4: + GPU_link(material, "set_rgba_one", link); + break; + default: + BLI_assert(0); + break; + } + return func_link->name; +} + GPUNodeGraph *gpu_material_node_graph(GPUMaterial *material) { return &material->graph; } -GSet *gpu_material_used_libraries(GPUMaterial *material) +eGPUMaterialStatus GPU_material_status(GPUMaterial *mat) { - return material->used_libraries; + return mat->status; } -eGPUMaterialStatus GPU_material_status(GPUMaterial *mat) +void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus status) { - return mat->status; + mat->status = status; } /* Code generation */ +bool GPU_material_is_volume_shader(GPUMaterial *mat) +{ + return mat->is_volume_shader; +} + bool GPU_material_has_surface_output(GPUMaterial *mat) { return mat->has_surface_output; @@ -541,100 +614,79 @@ bool GPU_material_has_volume_output(GPUMaterial *mat) return mat->has_volume_output; } -bool GPU_material_is_volume_shader(GPUMaterial *mat) +void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag) { - return mat->is_volume_shader; + mat->flag |= flag; } -void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag) +bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag) { - mat->flag |= flag; + return (mat->flag & flag) != 0; } -bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag) +eGPUMaterialFlag GPU_material_flag(const GPUMaterial *mat) { - return (mat->flag & flag) != 0; + return mat->flag; } -GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials, - const void *engine_type, - int options) +/* Note: Consumes the flags. */ +bool GPU_material_recalc_flag_get(GPUMaterial *mat) { - LISTBASE_FOREACH (LinkData *, link, gpumaterials) { - GPUMaterial *current_material = (GPUMaterial *)link->data; - if (current_material->engine_type == engine_type && current_material->options == options) { - return current_material; - } - } + bool updated = (mat->flag & GPU_MATFLAG_UPDATED) != 0; + mat->flag &= ~GPU_MATFLAG_UPDATED; + return updated; +} - return NULL; +uint64_t GPU_material_uuid_get(GPUMaterial *mat) +{ + return mat->uuid; } GPUMaterial *GPU_material_from_nodetree(Scene *scene, - struct Material *ma, - struct bNodeTree *ntree, + Material *ma, + 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) + uint64_t shader_uuid, + bool is_volume_shader, + bool is_lookdev, + GPUCodegenCallbackFn callback, + void *thunk) { - LinkData *link; - bool has_volume_output, has_surface_output; - - /* Caller must re-use materials. */ - BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL); - - /* HACK: Eevee assume this to create #GHash keys. */ - BLI_assert(sizeof(GPUPass) > 16); + /* Search if this material is not already compiled. */ + LISTBASE_FOREACH (LinkData *, link, gpumaterials) { + GPUMaterial *mat = (GPUMaterial *)link->data; + if (mat->uuid == shader_uuid) { + return mat; + } + } - /* allocate material */ GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); mat->ma = ma; mat->scene = scene; - mat->engine_type = engine_type; - mat->options = options; + mat->uuid = shader_uuid; + mat->flag = GPU_MATFLAG_UPDATED; mat->is_volume_shader = is_volume_shader; + mat->graph.used_libraries = BLI_gset_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries"); #ifndef NDEBUG BLI_snprintf(mat->name, sizeof(mat->name), "%s", name); #else UNUSED_VARS(name); #endif + if (is_lookdev) { + mat->flag |= GPU_MATFLAG_LOOKDEV_HACK; + } - mat->used_libraries = BLI_gset_new( - BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUMaterial.used_libraries"); - - /* localize tree to create links for reroute and mute */ + /* Localize tree to create links for reroute and mute. */ bNodeTree *localtree = ntreeLocalize(ntree); - ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output); + ntreeGPUMaterialNodes(localtree, mat); gpu_material_ramp_texture_build(mat); - mat->has_surface_output = has_surface_output; - mat->has_volume_output = has_volume_output; - - if (mat->graph.outlink) { - if (callback) { - callback(mat, options, &vert_code, &geom_code, &frag_lib, &defines); - } - /* HACK: this is only for eevee. We add the define here after the nodetree evaluation. */ - if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) { - defines = BLI_string_joinN(defines, - "#ifndef USE_ALPHA_BLEND\n" - "# define USE_SSS\n" - "#endif\n"); - } + { /* Create source code and search pass cache for an already compiled version. */ - mat->pass = GPU_generate_pass(mat, &mat->graph, vert_code, geom_code, frag_lib, defines); - - if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) { - MEM_freeN((char *)defines); - } + mat->pass = GPU_generate_pass(mat, &mat->graph, callback, thunk); if (mat->pass == NULL) { /* We had a cache hit and the shader has already failed to compile. */ @@ -649,26 +701,20 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, gpu_node_graph_free_nodes(&mat->graph); } else { - mat->status = GPU_MAT_QUEUED; + mat->status = GPU_MAT_CREATED; } } } - else { - mat->status = GPU_MAT_FAILED; - gpu_node_graph_free(&mat->graph); - } - /* Only free after GPU_pass_shader_get where GPUUniformBuf - * read data from the local tree. */ + /* Only free after GPU_pass_shader_get where GPUUniformBuf read data from the local tree. */ ntreeFreeLocalTree(localtree); BLI_assert(!localtree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ MEM_freeN(localtree); - /* note that even if building the shader fails in some way, we still keep + /* Note that even if building the shader fails in some way, we still keep * it to avoid trying to compile again and again, and simply do not use - * the actual shader on drawing */ - - link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); + * the actual shader on drawing. */ + LinkData *link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); link->data = mat; BLI_addtail(gpumaterials, link); @@ -690,6 +736,8 @@ void GPU_material_compile(GPUMaterial *mat) success = GPU_pass_compile(mat->pass, __func__); #endif + mat->flag |= GPU_MATFLAG_UPDATED; + if (success) { GPUShader *sh = GPU_pass_shader_get(mat->pass); if (sh != NULL) { @@ -715,5 +763,6 @@ void GPU_materials_free(Main *bmain) GPU_material_free(&wo->gpumaterial); } + // BKE_world_defaults_free_gpu(); BKE_material_defaults_free_gpu(); } diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c deleted file mode 100644 index ca5c3d4bb45..00000000000 --- a/source/blender/gpu/intern/gpu_material_library.c +++ /dev/null @@ -1,904 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2005 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup gpu - * - * GPU material library parsing and code generation. - */ - -#include -#include - -#include "MEM_guardedalloc.h" - -#include "BLI_dynstr.h" -#include "BLI_ghash.h" -#include "BLI_string.h" -#include "BLI_utildefines.h" - -#include "gpu_material_library.h" - -/* List of all gpu_shader_material_*.glsl files used by GLSL materials. These - * will be parsed to make all functions in them available to use for GPU_link(). - * - * If a file uses functions from another file, it must be added to the list of - * dependencies, and be placed after that file in the list. */ - -extern char datatoc_gpu_shader_material_add_shader_glsl[]; -extern char datatoc_gpu_shader_material_ambient_occlusion_glsl[]; -extern char datatoc_gpu_shader_material_anisotropic_glsl[]; -extern char datatoc_gpu_shader_material_attribute_glsl[]; -extern char datatoc_gpu_shader_material_background_glsl[]; -extern char datatoc_gpu_shader_material_bevel_glsl[]; -extern char datatoc_gpu_shader_material_wavelength_glsl[]; -extern char datatoc_gpu_shader_material_blackbody_glsl[]; -extern char datatoc_gpu_shader_material_bright_contrast_glsl[]; -extern char datatoc_gpu_shader_material_bump_glsl[]; -extern char datatoc_gpu_shader_material_camera_glsl[]; -extern char datatoc_gpu_shader_material_clamp_glsl[]; -extern char datatoc_gpu_shader_material_color_ramp_glsl[]; -extern char datatoc_gpu_shader_material_color_util_glsl[]; -extern char datatoc_gpu_shader_material_combine_hsv_glsl[]; -extern char datatoc_gpu_shader_material_combine_rgb_glsl[]; -extern char datatoc_gpu_shader_material_combine_xyz_glsl[]; -extern char datatoc_gpu_shader_material_diffuse_glsl[]; -extern char datatoc_gpu_shader_material_displacement_glsl[]; -extern char datatoc_gpu_shader_material_eevee_specular_glsl[]; -extern char datatoc_gpu_shader_material_emission_glsl[]; -extern char datatoc_gpu_shader_material_float_curve_glsl[]; -extern char datatoc_gpu_shader_material_fractal_noise_glsl[]; -extern char datatoc_gpu_shader_material_fresnel_glsl[]; -extern char datatoc_gpu_shader_material_gamma_glsl[]; -extern char datatoc_gpu_shader_material_geometry_glsl[]; -extern char datatoc_gpu_shader_material_glass_glsl[]; -extern char datatoc_gpu_shader_material_glossy_glsl[]; -extern char datatoc_gpu_shader_material_hair_info_glsl[]; -extern char datatoc_gpu_shader_material_hash_glsl[]; -extern char datatoc_gpu_shader_material_holdout_glsl[]; -extern char datatoc_gpu_shader_material_hue_sat_val_glsl[]; -extern char datatoc_gpu_shader_material_invert_glsl[]; -extern char datatoc_gpu_shader_material_layer_weight_glsl[]; -extern char datatoc_gpu_shader_material_light_falloff_glsl[]; -extern char datatoc_gpu_shader_material_light_path_glsl[]; -extern char datatoc_gpu_shader_material_mapping_glsl[]; -extern char datatoc_gpu_shader_material_map_range_glsl[]; -extern char datatoc_gpu_shader_material_math_glsl[]; -extern char datatoc_gpu_shader_material_math_util_glsl[]; -extern char datatoc_gpu_shader_material_mix_rgb_glsl[]; -extern char datatoc_gpu_shader_material_mix_shader_glsl[]; -extern char datatoc_gpu_shader_material_noise_glsl[]; -extern char datatoc_gpu_shader_material_normal_glsl[]; -extern char datatoc_gpu_shader_material_normal_map_glsl[]; -extern char datatoc_gpu_shader_material_object_info_glsl[]; -extern char datatoc_gpu_shader_material_output_aov_glsl[]; -extern char datatoc_gpu_shader_material_output_material_glsl[]; -extern char datatoc_gpu_shader_material_output_world_glsl[]; -extern char datatoc_gpu_shader_material_particle_info_glsl[]; -extern char datatoc_gpu_shader_material_point_info_glsl[]; -extern char datatoc_gpu_shader_material_principled_glsl[]; -extern char datatoc_gpu_shader_material_refraction_glsl[]; -extern char datatoc_gpu_shader_material_rgb_curves_glsl[]; -extern char datatoc_gpu_shader_material_rgb_to_bw_glsl[]; -extern char datatoc_gpu_shader_material_separate_hsv_glsl[]; -extern char datatoc_gpu_shader_material_separate_rgb_glsl[]; -extern char datatoc_gpu_shader_material_separate_xyz_glsl[]; -extern char datatoc_gpu_shader_material_set_glsl[]; -extern char datatoc_gpu_shader_material_shader_to_rgba_glsl[]; -extern char datatoc_gpu_shader_material_squeeze_glsl[]; -extern char datatoc_gpu_shader_material_subsurface_scattering_glsl[]; -extern char datatoc_gpu_shader_material_tangent_glsl[]; -extern char datatoc_gpu_shader_material_tex_brick_glsl[]; -extern char datatoc_gpu_shader_material_tex_checker_glsl[]; -extern char datatoc_gpu_shader_material_tex_environment_glsl[]; -extern char datatoc_gpu_shader_material_tex_gradient_glsl[]; -extern char datatoc_gpu_shader_material_tex_image_glsl[]; -extern char datatoc_gpu_shader_material_tex_magic_glsl[]; -extern char datatoc_gpu_shader_material_tex_musgrave_glsl[]; -extern char datatoc_gpu_shader_material_tex_noise_glsl[]; -extern char datatoc_gpu_shader_material_tex_sky_glsl[]; -extern char datatoc_gpu_shader_material_texture_coordinates_glsl[]; -extern char datatoc_gpu_shader_material_tex_voronoi_glsl[]; -extern char datatoc_gpu_shader_material_tex_wave_glsl[]; -extern char datatoc_gpu_shader_material_tex_white_noise_glsl[]; -extern char datatoc_gpu_shader_material_toon_glsl[]; -extern char datatoc_gpu_shader_material_translucent_glsl[]; -extern char datatoc_gpu_shader_material_transparent_glsl[]; -extern char datatoc_gpu_shader_material_uv_map_glsl[]; -extern char datatoc_gpu_shader_material_vector_curves_glsl[]; -extern char datatoc_gpu_shader_material_vector_displacement_glsl[]; -extern char datatoc_gpu_shader_material_vector_math_glsl[]; -extern char datatoc_gpu_shader_material_vector_rotate_glsl[]; -extern char datatoc_gpu_shader_material_velvet_glsl[]; -extern char datatoc_gpu_shader_material_vertex_color_glsl[]; -extern char datatoc_gpu_shader_material_volume_absorption_glsl[]; -extern char datatoc_gpu_shader_material_volume_info_glsl[]; -extern char datatoc_gpu_shader_material_volume_principled_glsl[]; -extern char datatoc_gpu_shader_material_volume_scatter_glsl[]; -extern char datatoc_gpu_shader_material_wireframe_glsl[]; -extern char datatoc_gpu_shader_material_world_normals_glsl[]; - -static GPUMaterialLibrary gpu_shader_material_math_util_library = { - .code = datatoc_gpu_shader_material_math_util_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_color_util_library = { - .code = datatoc_gpu_shader_material_color_util_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_hash_library = { - .code = datatoc_gpu_shader_material_hash_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_noise_library = { - .code = datatoc_gpu_shader_material_noise_glsl, - .dependencies = {&gpu_shader_material_hash_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_fractal_noise_library = { - .code = datatoc_gpu_shader_material_fractal_noise_glsl, - .dependencies = {&gpu_shader_material_noise_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_add_shader_library = { - .code = datatoc_gpu_shader_material_add_shader_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_ambient_occlusion_library = { - .code = datatoc_gpu_shader_material_ambient_occlusion_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_glossy_library = { - .code = datatoc_gpu_shader_material_glossy_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_anisotropic_library = { - .code = datatoc_gpu_shader_material_anisotropic_glsl, - .dependencies = {&gpu_shader_material_glossy_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_attribute_library = { - .code = datatoc_gpu_shader_material_attribute_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_background_library = { - .code = datatoc_gpu_shader_material_background_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_bevel_library = { - .code = datatoc_gpu_shader_material_bevel_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_wavelength_library = { - .code = datatoc_gpu_shader_material_wavelength_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_blackbody_library = { - .code = datatoc_gpu_shader_material_blackbody_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_bright_contrast_library = { - .code = datatoc_gpu_shader_material_bright_contrast_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_bump_library = { - .code = datatoc_gpu_shader_material_bump_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_camera_library = { - .code = datatoc_gpu_shader_material_camera_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_clamp_library = { - .code = datatoc_gpu_shader_material_clamp_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_color_ramp_library = { - .code = datatoc_gpu_shader_material_color_ramp_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_combine_hsv_library = { - .code = datatoc_gpu_shader_material_combine_hsv_glsl, - .dependencies = {&gpu_shader_material_color_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_combine_rgb_library = { - .code = datatoc_gpu_shader_material_combine_rgb_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_combine_xyz_library = { - .code = datatoc_gpu_shader_material_combine_xyz_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_diffuse_library = { - .code = datatoc_gpu_shader_material_diffuse_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_displacement_library = { - .code = datatoc_gpu_shader_material_displacement_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_eevee_specular_library = { - .code = datatoc_gpu_shader_material_eevee_specular_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_emission_library = { - .code = datatoc_gpu_shader_material_emission_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_float_curve_library = { - .code = datatoc_gpu_shader_material_float_curve_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_fresnel_library = { - .code = datatoc_gpu_shader_material_fresnel_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_gamma_library = { - .code = datatoc_gpu_shader_material_gamma_glsl, - .dependencies = {&gpu_shader_material_math_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tangent_library = { - .code = datatoc_gpu_shader_material_tangent_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_geometry_library = { - .code = datatoc_gpu_shader_material_geometry_glsl, - .dependencies = {&gpu_shader_material_tangent_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_glass_library = { - .code = datatoc_gpu_shader_material_glass_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_hair_info_library = { - .code = datatoc_gpu_shader_material_hair_info_glsl, - .dependencies = {&gpu_shader_material_hash_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_holdout_library = { - .code = datatoc_gpu_shader_material_holdout_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_hue_sat_val_library = { - .code = datatoc_gpu_shader_material_hue_sat_val_glsl, - .dependencies = {&gpu_shader_material_color_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_invert_library = { - .code = datatoc_gpu_shader_material_invert_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_layer_weight_library = { - .code = datatoc_gpu_shader_material_layer_weight_glsl, - .dependencies = {&gpu_shader_material_fresnel_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_light_falloff_library = { - .code = datatoc_gpu_shader_material_light_falloff_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_light_path_library = { - .code = datatoc_gpu_shader_material_light_path_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_mapping_library = { - .code = datatoc_gpu_shader_material_mapping_glsl, - .dependencies = {&gpu_shader_material_math_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_map_range_library = { - .code = datatoc_gpu_shader_material_map_range_glsl, - .dependencies = {&gpu_shader_material_math_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_math_library = { - .code = datatoc_gpu_shader_material_math_glsl, - .dependencies = {&gpu_shader_material_math_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_mix_rgb_library = { - .code = datatoc_gpu_shader_material_mix_rgb_glsl, - .dependencies = {&gpu_shader_material_color_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_mix_shader_library = { - .code = datatoc_gpu_shader_material_mix_shader_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_normal_library = { - .code = datatoc_gpu_shader_material_normal_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_normal_map_library = { - .code = datatoc_gpu_shader_material_normal_map_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_object_info_library = { - .code = datatoc_gpu_shader_material_object_info_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_output_aov_library = { - .code = datatoc_gpu_shader_material_output_aov_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_output_material_library = { - .code = datatoc_gpu_shader_material_output_material_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_output_world_library = { - .code = datatoc_gpu_shader_material_output_world_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_particle_info_library = { - .code = datatoc_gpu_shader_material_particle_info_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_point_info_library = { - .code = datatoc_gpu_shader_material_point_info_glsl, - .dependencies = {&gpu_shader_material_hash_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_principled_library = { - .code = datatoc_gpu_shader_material_principled_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_refraction_library = { - .code = datatoc_gpu_shader_material_refraction_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_rgb_curves_library = { - .code = datatoc_gpu_shader_material_rgb_curves_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_rgb_to_bw_library = { - .code = datatoc_gpu_shader_material_rgb_to_bw_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_separate_hsv_library = { - .code = datatoc_gpu_shader_material_separate_hsv_glsl, - .dependencies = {&gpu_shader_material_color_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_separate_rgb_library = { - .code = datatoc_gpu_shader_material_separate_rgb_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_separate_xyz_library = { - .code = datatoc_gpu_shader_material_separate_xyz_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_set_library = { - .code = datatoc_gpu_shader_material_set_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_shader_to_rgba_library = { - .code = datatoc_gpu_shader_material_shader_to_rgba_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_squeeze_library = { - .code = datatoc_gpu_shader_material_squeeze_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_subsurface_scattering_library = { - .code = datatoc_gpu_shader_material_subsurface_scattering_glsl, - .dependencies = {&gpu_shader_material_diffuse_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_brick_library = { - .code = datatoc_gpu_shader_material_tex_brick_glsl, - .dependencies = {&gpu_shader_material_math_util_library, - &gpu_shader_material_hash_library, - NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_checker_library = { - .code = datatoc_gpu_shader_material_tex_checker_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_environment_library = { - .code = datatoc_gpu_shader_material_tex_environment_glsl, - .dependencies = {&gpu_shader_material_math_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_gradient_library = { - .code = datatoc_gpu_shader_material_tex_gradient_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_image_library = { - .code = datatoc_gpu_shader_material_tex_image_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_magic_library = { - .code = datatoc_gpu_shader_material_tex_magic_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_musgrave_library = { - .code = datatoc_gpu_shader_material_tex_musgrave_glsl, - .dependencies = {&gpu_shader_material_noise_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_noise_library = { - .code = datatoc_gpu_shader_material_tex_noise_glsl, - .dependencies = {&gpu_shader_material_fractal_noise_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_sky_library = { - .code = datatoc_gpu_shader_material_tex_sky_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_texture_coordinates_library = { - .code = datatoc_gpu_shader_material_texture_coordinates_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_voronoi_library = { - .code = datatoc_gpu_shader_material_tex_voronoi_glsl, - .dependencies = {&gpu_shader_material_math_util_library, - &gpu_shader_material_hash_library, - NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_wave_library = { - .code = datatoc_gpu_shader_material_tex_wave_glsl, - .dependencies = {&gpu_shader_material_fractal_noise_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_tex_white_noise_library = { - .code = datatoc_gpu_shader_material_tex_white_noise_glsl, - .dependencies = {&gpu_shader_material_hash_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_toon_library = { - .code = datatoc_gpu_shader_material_toon_glsl, - .dependencies = {&gpu_shader_material_diffuse_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_translucent_library = { - .code = datatoc_gpu_shader_material_translucent_glsl, - .dependencies = {&gpu_shader_material_diffuse_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_transparent_library = { - .code = datatoc_gpu_shader_material_transparent_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_uv_map_library = { - .code = datatoc_gpu_shader_material_uv_map_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_vector_curves_library = { - .code = datatoc_gpu_shader_material_vector_curves_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_vector_displacement_library = { - .code = datatoc_gpu_shader_material_vector_displacement_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_vector_math_library = { - .code = datatoc_gpu_shader_material_vector_math_glsl, - .dependencies = {&gpu_shader_material_math_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_vector_rotate_library = { - .code = datatoc_gpu_shader_material_vector_rotate_glsl, - .dependencies = {&gpu_shader_material_math_util_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_velvet_library = { - .code = datatoc_gpu_shader_material_velvet_glsl, - .dependencies = {&gpu_shader_material_diffuse_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_vertex_color_library = { - .code = datatoc_gpu_shader_material_vertex_color_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_volume_absorption_library = { - .code = datatoc_gpu_shader_material_volume_absorption_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_volume_info_library = { - .code = datatoc_gpu_shader_material_volume_info_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_volume_principled_library = { - .code = datatoc_gpu_shader_material_volume_principled_glsl, - .dependencies = {&gpu_shader_material_blackbody_library, NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_volume_scatter_library = { - .code = datatoc_gpu_shader_material_volume_scatter_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_wireframe_library = { - .code = datatoc_gpu_shader_material_wireframe_glsl, - .dependencies = {NULL}, -}; - -static GPUMaterialLibrary gpu_shader_material_world_normals_library = { - .code = datatoc_gpu_shader_material_world_normals_glsl, - .dependencies = {&gpu_shader_material_texture_coordinates_library, NULL}, -}; - -static GPUMaterialLibrary *gpu_material_libraries[] = { - &gpu_shader_material_math_util_library, - &gpu_shader_material_color_util_library, - &gpu_shader_material_hash_library, - &gpu_shader_material_noise_library, - &gpu_shader_material_float_curve_library, - &gpu_shader_material_fractal_noise_library, - &gpu_shader_material_add_shader_library, - &gpu_shader_material_ambient_occlusion_library, - &gpu_shader_material_glossy_library, - &gpu_shader_material_anisotropic_library, - &gpu_shader_material_attribute_library, - &gpu_shader_material_background_library, - &gpu_shader_material_bevel_library, - &gpu_shader_material_wavelength_library, - &gpu_shader_material_blackbody_library, - &gpu_shader_material_bright_contrast_library, - &gpu_shader_material_bump_library, - &gpu_shader_material_camera_library, - &gpu_shader_material_clamp_library, - &gpu_shader_material_color_ramp_library, - &gpu_shader_material_combine_hsv_library, - &gpu_shader_material_combine_rgb_library, - &gpu_shader_material_combine_xyz_library, - &gpu_shader_material_diffuse_library, - &gpu_shader_material_displacement_library, - &gpu_shader_material_eevee_specular_library, - &gpu_shader_material_emission_library, - &gpu_shader_material_fresnel_library, - &gpu_shader_material_gamma_library, - &gpu_shader_material_tangent_library, - &gpu_shader_material_geometry_library, - &gpu_shader_material_glass_library, - &gpu_shader_material_hair_info_library, - &gpu_shader_material_holdout_library, - &gpu_shader_material_hue_sat_val_library, - &gpu_shader_material_invert_library, - &gpu_shader_material_layer_weight_library, - &gpu_shader_material_light_falloff_library, - &gpu_shader_material_light_path_library, - &gpu_shader_material_mapping_library, - &gpu_shader_material_map_range_library, - &gpu_shader_material_math_library, - &gpu_shader_material_mix_rgb_library, - &gpu_shader_material_mix_shader_library, - &gpu_shader_material_normal_library, - &gpu_shader_material_normal_map_library, - &gpu_shader_material_object_info_library, - &gpu_shader_material_output_aov_library, - &gpu_shader_material_output_material_library, - &gpu_shader_material_output_world_library, - &gpu_shader_material_particle_info_library, - &gpu_shader_material_point_info_library, - &gpu_shader_material_principled_library, - &gpu_shader_material_refraction_library, - &gpu_shader_material_rgb_curves_library, - &gpu_shader_material_rgb_to_bw_library, - &gpu_shader_material_separate_hsv_library, - &gpu_shader_material_separate_rgb_library, - &gpu_shader_material_separate_xyz_library, - &gpu_shader_material_set_library, - &gpu_shader_material_shader_to_rgba_library, - &gpu_shader_material_squeeze_library, - &gpu_shader_material_subsurface_scattering_library, - &gpu_shader_material_tex_brick_library, - &gpu_shader_material_tex_checker_library, - &gpu_shader_material_tex_environment_library, - &gpu_shader_material_tex_gradient_library, - &gpu_shader_material_tex_image_library, - &gpu_shader_material_tex_magic_library, - &gpu_shader_material_tex_musgrave_library, - &gpu_shader_material_tex_noise_library, - &gpu_shader_material_tex_sky_library, - &gpu_shader_material_texture_coordinates_library, - &gpu_shader_material_tex_voronoi_library, - &gpu_shader_material_tex_wave_library, - &gpu_shader_material_tex_white_noise_library, - &gpu_shader_material_toon_library, - &gpu_shader_material_translucent_library, - &gpu_shader_material_transparent_library, - &gpu_shader_material_uv_map_library, - &gpu_shader_material_vector_curves_library, - &gpu_shader_material_vector_displacement_library, - &gpu_shader_material_vector_math_library, - &gpu_shader_material_vector_rotate_library, - &gpu_shader_material_velvet_library, - &gpu_shader_material_vertex_color_library, - &gpu_shader_material_volume_absorption_library, - &gpu_shader_material_volume_info_library, - &gpu_shader_material_volume_principled_library, - &gpu_shader_material_volume_scatter_library, - &gpu_shader_material_wireframe_library, - &gpu_shader_material_world_normals_library, - NULL}; - -/* GLSL code parsing for finding function definitions. - * These are stored in a hash for lookup when creating a material. */ - -static GHash *FUNCTION_HASH = NULL; - -const char *gpu_str_skip_token(const char *str, char *token, int max) -{ - int len = 0; - - /* skip a variable/function name */ - while (*str) { - if (ELEM(*str, ' ', '(', ')', ',', ';', '\t', '\n', '\r')) { - break; - } - - if (token && len < max - 1) { - *token = *str; - token++; - len++; - } - str++; - } - - if (token) { - *token = '\0'; - } - - /* skip the next special characters: - * note the missing ')' */ - while (*str) { - if (ELEM(*str, ' ', '(', ',', ';', '\t', '\n', '\r')) { - str++; - } - else { - break; - } - } - - return str; -} - -/* Indices match the eGPUType enum */ -static const char *GPU_DATATYPE_STR[17] = { - "", - "float", - "vec2", - "vec3", - "vec4", - NULL, - NULL, - NULL, - NULL, - "mat3", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "mat4", -}; - -const char *gpu_data_type_to_string(const eGPUType type) -{ - return GPU_DATATYPE_STR[type]; -} - -static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library) -{ - GPUFunction *function; - eGPUType type; - GPUFunctionQual qual; - int i; - const char *code = library->code; - - while ((code = strstr(code, "void "))) { - function = MEM_callocN(sizeof(GPUFunction), "GPUFunction"); - function->library = library; - - code = gpu_str_skip_token(code, NULL, 0); - code = gpu_str_skip_token(code, function->name, MAX_FUNCTION_NAME); - - /* get parameters */ - while (*code && *code != ')') { - if (BLI_str_startswith(code, "const ")) { - code = gpu_str_skip_token(code, NULL, 0); - } - - /* test if it's an input or output */ - qual = FUNCTION_QUAL_IN; - if (BLI_str_startswith(code, "out ")) { - qual = FUNCTION_QUAL_OUT; - } - if (BLI_str_startswith(code, "inout ")) { - qual = FUNCTION_QUAL_INOUT; - } - if ((qual != FUNCTION_QUAL_IN) || BLI_str_startswith(code, "in ")) { - code = gpu_str_skip_token(code, NULL, 0); - } - - /* test for type */ - type = GPU_NONE; - for (i = 1; i < ARRAY_SIZE(GPU_DATATYPE_STR); i++) { - if (GPU_DATATYPE_STR[i] && BLI_str_startswith(code, GPU_DATATYPE_STR[i])) { - type = i; - break; - } - } - - if (!type && BLI_str_startswith(code, "samplerCube")) { - type = GPU_TEXCUBE; - } - if (!type && BLI_str_startswith(code, "sampler2DShadow")) { - type = GPU_SHADOW2D; - } - if (!type && BLI_str_startswith(code, "sampler1DArray")) { - type = GPU_TEX1D_ARRAY; - } - if (!type && BLI_str_startswith(code, "sampler2DArray")) { - type = GPU_TEX2D_ARRAY; - } - if (!type && BLI_str_startswith(code, "sampler2D")) { - type = GPU_TEX2D; - } - if (!type && BLI_str_startswith(code, "sampler3D")) { - type = GPU_TEX3D; - } - - if (!type && BLI_str_startswith(code, "Closure")) { - type = GPU_CLOSURE; - } - - if (type) { - /* add parameter */ - code = gpu_str_skip_token(code, NULL, 0); - code = gpu_str_skip_token(code, NULL, 0); - function->paramqual[function->totparam] = qual; - function->paramtype[function->totparam] = type; - function->totparam++; - } - else { - fprintf(stderr, "GPU invalid function parameter in %s.\n", function->name); - break; - } - } - - if (function->name[0] == '\0' || function->totparam == 0) { - fprintf(stderr, "GPU functions parse error.\n"); - MEM_freeN(function); - break; - } - - BLI_ghash_insert(hash, function->name, function); - } -} - -/* Module */ - -void gpu_material_library_init(void) -{ - /* Only parse GLSL shader files once. */ - if (FUNCTION_HASH) { - return; - } - - FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh"); - for (int i = 0; gpu_material_libraries[i]; i++) { - gpu_parse_material_library(FUNCTION_HASH, gpu_material_libraries[i]); - } -} - -void gpu_material_library_exit(void) -{ - if (FUNCTION_HASH) { - BLI_ghash_free(FUNCTION_HASH, NULL, MEM_freeN); - FUNCTION_HASH = NULL; - } -} - -/* Code Generation */ - -static void gpu_material_use_library_with_dependencies(GSet *used_libraries, - GPUMaterialLibrary *library) -{ - if (BLI_gset_add(used_libraries, library->code)) { - for (int i = 0; library->dependencies[i]; i++) { - gpu_material_use_library_with_dependencies(used_libraries, library->dependencies[i]); - } - } -} - -GPUFunction *gpu_material_library_use_function(GSet *used_libraries, const char *name) -{ - GPUFunction *function = BLI_ghash_lookup(FUNCTION_HASH, (const void *)name); - if (function) { - gpu_material_use_library_with_dependencies(used_libraries, function->library); - } - return function; -} - -char *gpu_material_library_generate_code(GSet *used_libraries, const char *frag_lib) -{ - DynStr *ds = BLI_dynstr_new(); - - if (frag_lib) { - BLI_dynstr_append(ds, frag_lib); - } - - /* Always include those because they may be needed by the execution function. */ - gpu_material_use_library_with_dependencies(used_libraries, - &gpu_shader_material_world_normals_library); - - /* Add library code in order, for dependencies. */ - for (int i = 0; gpu_material_libraries[i]; i++) { - GPUMaterialLibrary *library = gpu_material_libraries[i]; - if (BLI_gset_haskey(used_libraries, library->code)) { - BLI_dynstr_append(ds, library->code); - } - } - - char *result = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return result; -} diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h index 96e1a265c72..ffc2228a49b 100644 --- a/source/blender/gpu/intern/gpu_material_library.h +++ b/source/blender/gpu/intern/gpu_material_library.h @@ -10,16 +10,15 @@ #include "GPU_material.h" +#ifdef __cplusplus +extern "C" { +#endif + #define MAX_FUNCTION_NAME 64 #define MAX_PARAMETER 36 struct GSet; -typedef struct GPUMaterialLibrary { - char *code; - struct GPUMaterialLibrary *dependencies[8]; -} GPUMaterialLibrary; - typedef enum { FUNCTION_QUAL_IN, FUNCTION_QUAL_OUT, @@ -31,20 +30,12 @@ typedef struct GPUFunction { eGPUType paramtype[MAX_PARAMETER]; GPUFunctionQual paramqual[MAX_PARAMETER]; int totparam; - GPUMaterialLibrary *library; + /* TOOD(@fclem): Clean that void pointer. */ + void *source; /* GPUSource */ } GPUFunction; -/* Module */ - -void gpu_material_library_init(void); -void gpu_material_library_exit(void); - -/* Code Generation */ - GPUFunction *gpu_material_library_use_function(struct GSet *used_libraries, const char *name); -char *gpu_material_library_generate_code(struct GSet *used_libraries, const char *frag_lib); - -/* Code Parsing */ -const char *gpu_str_skip_token(const char *str, char *token, int max); -const char *gpu_data_type_to_string(eGPUType type); +#ifdef __cplusplus +} +#endif diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 57e415a8183..d9143a12d5b 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -87,10 +87,6 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType input->type = type; switch (link->link_type) { - case GPU_NODE_LINK_BUILTIN: - input->source = GPU_SOURCE_BUILTIN; - input->builtin = link->builtin; - break; case GPU_NODE_LINK_OUTPUT: input->source = GPU_SOURCE_OUTPUT; input->link = link; @@ -132,6 +128,11 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType case GPU_NODE_LINK_UNIFORM: input->source = GPU_SOURCE_UNIFORM; break; + case GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN: + input->source = GPU_SOURCE_FUNCTION_CALL; + /* NOTE(@fclem): End of function call is the return variable set during codegen. */ + SNPRINTF(input->function_call, "dF_branch(%s(), ", link->function_name); + break; default: break; } @@ -478,6 +479,11 @@ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const ch GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name); + if (type == CD_ORCO) { + /* OPTI: orco might be computed from local positions and needs object infos. */ + GPU_material_flag_set(mat, GPU_MATFLAG_OBJECT_INFO); + } + /* Dummy fallback if out of slots. */ if (attr == NULL) { static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f}; @@ -523,6 +529,14 @@ GPUNodeLink *GPU_uniform(const float *num) return link; } +GPUNodeLink *GPU_differentiate_float_function(const char *function_name) +{ + GPUNodeLink *link = gpu_node_link_create(); + link->link_type = GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN; + link->function_name = function_name; + return link; +} + GPUNodeLink *GPU_image(GPUMaterial *mat, Image *ima, ImageUser *iuser, @@ -588,41 +602,35 @@ GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, transform_link->volume_grid = link->volume_grid; transform_link->volume_grid->users++; + GPUNodeLink *cos_link = GPU_attribute(mat, CD_ORCO, ""); + /* Two special cases, where we adjust the output values of smoke grids to * bring the into standard range without having to modify the grid values. */ if (STREQ(name, "color")) { - GPU_link(mat, "node_attribute_volume_color", link, transform_link, &link); + GPU_link(mat, "node_attribute_volume_color", link, transform_link, cos_link, &link); } else if (STREQ(name, "temperature")) { - GPU_link(mat, "node_attribute_volume_temperature", link, transform_link, &link); + GPU_link(mat, "node_attribute_volume_temperature", link, transform_link, cos_link, &link); } else { - GPU_link(mat, "node_attribute_volume", link, transform_link, &link); + GPU_link(mat, "node_attribute_volume", link, transform_link, cos_link, &link); } return link; } -GPUNodeLink *GPU_builtin(eGPUBuiltin builtin) -{ - GPUNodeLink *link = gpu_node_link_create(); - link->link_type = GPU_NODE_LINK_BUILTIN; - link->builtin = builtin; - return link; -} - /* Creating Nodes */ bool GPU_link(GPUMaterial *mat, const char *name, ...) { - GSet *used_libraries = gpu_material_used_libraries(mat); + GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUNode *node; GPUFunction *function; GPUNodeLink *link, **linkptr; va_list params; int i; - function = gpu_material_library_use_function(used_libraries, name); + function = gpu_material_library_use_function(graph->used_libraries, name); if (!function) { fprintf(stderr, "GPU failed to find function %s\n", name); return false; @@ -643,27 +651,25 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...) } va_end(params); - GPUNodeGraph *graph = gpu_material_node_graph(mat); BLI_addtail(&graph->nodes, node); return true; } -bool GPU_stack_link(GPUMaterial *material, - bNode *bnode, - const char *name, - GPUNodeStack *in, - GPUNodeStack *out, - ...) +static bool gpu_stack_link_v(GPUMaterial *material, + bNode *bnode, + const char *name, + GPUNodeStack *in, + GPUNodeStack *out, + va_list params) { - GSet *used_libraries = gpu_material_used_libraries(material); + GPUNodeGraph *graph = gpu_material_node_graph(material); GPUNode *node; GPUFunction *function; GPUNodeLink *link, **linkptr; - va_list params; int i, totin, totout; - function = gpu_material_library_use_function(used_libraries, name); + function = gpu_material_library_use_function(graph->used_libraries, name); if (!function) { fprintf(stderr, "GPU failed to find function %s\n", name); return false; @@ -691,7 +697,6 @@ bool GPU_stack_link(GPUMaterial *material, } } - va_start(params, out); for (i = 0; i < function->totparam; i++) { if (function->paramqual[i] != FUNCTION_QUAL_IN) { if (totout == 0) { @@ -717,14 +722,27 @@ bool GPU_stack_link(GPUMaterial *material, } } } - va_end(params); - GPUNodeGraph *graph = gpu_material_node_graph(material); BLI_addtail(&graph->nodes, node); return true; } +bool GPU_stack_link(GPUMaterial *material, + bNode *bnode, + const char *name, + GPUNodeStack *in, + GPUNodeStack *out, + ...) +{ + va_list params; + va_start(params, out); + bool valid = gpu_stack_link_v(material, bnode, name, in, out, params); + va_end(params); + + return valid; +} + GPUNodeLink *GPU_uniformbuf_link_out(GPUMaterial *mat, bNode *node, GPUNodeStack *stack, @@ -786,12 +804,16 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph) gpu_node_free(node); } - graph->outlink = NULL; + graph->outlink_surface = NULL; + graph->outlink_volume = NULL; + graph->outlink_displacement = NULL; + graph->outlink_thickness = NULL; } void gpu_node_graph_free(GPUNodeGraph *graph) { BLI_freelistN(&graph->outlink_aovs); + BLI_freelistN(&graph->material_functions); gpu_node_graph_free_nodes(graph); LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) { @@ -801,28 +823,32 @@ void gpu_node_graph_free(GPUNodeGraph *graph) BLI_freelistN(&graph->textures); BLI_freelistN(&graph->attributes); GPU_uniform_attr_list_free(&graph->uniform_attrs); + + if (graph->used_libraries) { + BLI_gset_free(graph->used_libraries, NULL); + graph->used_libraries = NULL; + } } /* Prune Unused Nodes */ -static void gpu_nodes_tag(GPUNodeLink *link) +static void gpu_nodes_tag(GPUNodeLink *link, eGPUNodeTag tag) { GPUNode *node; - GPUInput *input; - if (!link->output) { + if (!link || !link->output) { return; } node = link->output->node; - if (node->tag) { + if (node->tag & tag) { return; } - node->tag = true; - for (input = node->inputs.first; input; input = input->next) { + node->tag |= tag; + LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { if (input->link) { - gpu_nodes_tag(input->link); + gpu_nodes_tag(input->link, tag); } } } @@ -830,18 +856,25 @@ static void gpu_nodes_tag(GPUNodeLink *link) void gpu_node_graph_prune_unused(GPUNodeGraph *graph) { LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) { - node->tag = false; + node->tag = GPU_NODE_TAG_NONE; } - gpu_nodes_tag(graph->outlink); + gpu_nodes_tag(graph->outlink_surface, GPU_NODE_TAG_SURFACE); + gpu_nodes_tag(graph->outlink_volume, GPU_NODE_TAG_VOLUME); + gpu_nodes_tag(graph->outlink_displacement, GPU_NODE_TAG_DISPLACEMENT); + gpu_nodes_tag(graph->outlink_thickness, GPU_NODE_TAG_THICKNESS); + LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) { - gpu_nodes_tag(aovlink->outlink); + gpu_nodes_tag(aovlink->outlink, GPU_NODE_TAG_AOV); + } + LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, funclink, &graph->material_functions) { + gpu_nodes_tag(funclink->outlink, GPU_NODE_TAG_FUNCTION); } for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) { next = node->next; - if (!node->tag) { + if (node->tag == GPU_NODE_TAG_NONE) { BLI_remlink(&graph->nodes, node); gpu_node_free(node); } diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index 5856001d548..024119e1c24 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -12,9 +12,15 @@ #include "DNA_customdata_types.h" #include "DNA_listBase.h" +#include "BLI_ghash.h" + #include "GPU_material.h" #include "GPU_shader.h" +#ifdef __cplusplus +extern "C" { +#endif + struct GPUNode; struct GPUOutput; struct ListBase; @@ -25,19 +31,18 @@ typedef enum eGPUDataSource { GPU_SOURCE_UNIFORM, GPU_SOURCE_ATTR, GPU_SOURCE_UNIFORM_ATTR, - GPU_SOURCE_BUILTIN, GPU_SOURCE_STRUCT, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING, GPU_SOURCE_VOLUME_GRID, GPU_SOURCE_VOLUME_GRID_TRANSFORM, + GPU_SOURCE_FUNCTION_CALL, } eGPUDataSource; typedef enum { GPU_NODE_LINK_NONE = 0, GPU_NODE_LINK_ATTR, GPU_NODE_LINK_UNIFORM_ATTR, - GPU_NODE_LINK_BUILTIN, GPU_NODE_LINK_COLORBAND, GPU_NODE_LINK_CONSTANT, GPU_NODE_LINK_IMAGE, @@ -47,15 +52,28 @@ typedef enum { GPU_NODE_LINK_VOLUME_GRID_TRANSFORM, GPU_NODE_LINK_OUTPUT, GPU_NODE_LINK_UNIFORM, + GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN, } GPUNodeLinkType; +typedef enum { + GPU_NODE_TAG_NONE = 0, + GPU_NODE_TAG_SURFACE = (1 << 0), + GPU_NODE_TAG_VOLUME = (1 << 1), + GPU_NODE_TAG_DISPLACEMENT = (1 << 2), + GPU_NODE_TAG_THICKNESS = (1 << 3), + GPU_NODE_TAG_AOV = (1 << 4), + GPU_NODE_TAG_FUNCTION = (1 << 5), +} eGPUNodeTag; + +ENUM_OPERATORS(eGPUNodeTag, GPU_NODE_TAG_FUNCTION) + struct GPUNode { struct GPUNode *next, *prev; const char *name; /* Internal flag to mark nodes during pruning */ - bool tag; + eGPUNodeTag tag; ListBase inputs; ListBase outputs; @@ -70,8 +88,6 @@ struct GPUNodeLink { union { /* GPU_NODE_LINK_CONSTANT | GPU_NODE_LINK_UNIFORM */ const float *data; - /* GPU_NODE_LINK_BUILTIN */ - eGPUBuiltin builtin; /* GPU_NODE_LINK_COLORBAND */ struct GPUTexture **colorband; /* GPU_NODE_LINK_VOLUME_GRID */ @@ -84,6 +100,8 @@ struct GPUNodeLink { struct GPUUniformAttr *uniform_attr; /* GPU_NODE_LINK_IMAGE_BLENDER */ struct GPUMaterialTexture *texture; + /* GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN */ + const char *function_name; }; }; @@ -110,8 +128,6 @@ typedef struct GPUInput { union { /* GPU_SOURCE_CONSTANT | GPU_SOURCE_UNIFORM */ float vec[16]; /* vector data */ - /* GPU_SOURCE_BUILTIN */ - eGPUBuiltin builtin; /* builtin uniform */ /* GPU_SOURCE_TEX | GPU_SOURCE_TEX_TILED_MAPPING */ struct GPUMaterialTexture *texture; /* GPU_SOURCE_ATTR */ @@ -120,6 +136,8 @@ typedef struct GPUInput { struct GPUUniformAttr *uniform_attr; /* GPU_SOURCE_VOLUME_GRID | GPU_SOURCE_VOLUME_GRID_TRANSFORM */ struct GPUMaterialVolumeGrid *volume_grid; + /* GPU_SOURCE_FUNCTION_CALL */ + char function_call[64]; }; } GPUInput; @@ -129,14 +147,25 @@ typedef struct GPUNodeGraphOutputLink { GPUNodeLink *outlink; } GPUNodeGraphOutputLink; +typedef struct GPUNodeGraphFunctionLink { + struct GPUNodeGraphFunctionLink *next, *prev; + char name[16]; + GPUNodeLink *outlink; +} GPUNodeGraphFunctionLink; + typedef struct GPUNodeGraph { /* Nodes */ ListBase nodes; - /* Main Output. */ - GPUNodeLink *outlink; + /* Main Outputs. */ + GPUNodeLink *outlink_surface; + GPUNodeLink *outlink_volume; + GPUNodeLink *outlink_displacement; + GPUNodeLink *outlink_thickness; /* List of GPUNodeGraphOutputLink */ ListBase outlink_aovs; + /* List of GPUNodeGraphFunctionLink */ + ListBase material_functions; /* Requested attributes and textures. */ ListBase attributes; @@ -145,6 +174,9 @@ typedef struct GPUNodeGraph { /* The list of uniform attributes. */ GPUUniformAttrList uniform_attrs; + + /** Set of all the GLSL lib code blocks . */ + GSet *used_libraries; } GPUNodeGraph; /* Node Graph */ @@ -171,4 +203,6 @@ struct GPUTexture **gpu_material_ramp_texture_row_set(struct GPUMaterial *mat, float *pixels, float *row); -struct GSet *gpu_material_used_libraries(struct GPUMaterial *material); +#ifdef __cplusplus +} +#endif diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 76b3402435a..fe9aacb95f9 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -294,7 +294,9 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) std::string defines = shader->defines_declare(info); std::string resources = shader->resources_declare(info); - defines += "#define USE_GPU_SHADER_CREATE_INFO\n"; + if (info.legacy_resource_location_ == false) { + defines += "#define USE_GPU_SHADER_CREATE_INFO\n"; + } Vector typedefs; if (!info.typedef_sources_.is_empty() || !info.typedef_source_generated.empty()) { @@ -362,6 +364,7 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) sources.append(resources.c_str()); sources.append(layout.c_str()); sources.append(interface.c_str()); + sources.append(info.geometry_source_generated.c_str()); sources.extend(code); shader->geometry_shader_from_glsl(sources); diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc index 95f9b031fe8..515f65adb73 100644 --- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc +++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc @@ -202,10 +202,7 @@ int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *UNUSED(subdiv_ccg), /* -------------------------------------------------------------------- */ /** \name Stubs of BKE_node.h * \{ */ -void ntreeGPUMaterialNodes(struct bNodeTree *UNUSED(localtree), - struct GPUMaterial *UNUSED(mat), - bool *UNUSED(has_surface_output), - bool *UNUSED(has_volume_output)) +void ntreeGPUMaterialNodes(struct bNodeTree *UNUSED(localtree), struct GPUMaterial *UNUSED(mat)) { BLI_assert_unreachable(); } diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh index dfd73219d1b..3ab96d0d84a 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info.hh @@ -284,6 +284,8 @@ struct ShaderCreateInfo { bool auto_resource_location_ = false; /** If true, force depth and stencil tests to always happen before fragment shader invocation. */ bool early_fragment_test_ = false; + /** If true, force the use of the GL shader introspection for resource location. */ + bool legacy_resource_location_ = false; /** Allow optimization when fragment shader writes to `gl_FragDepth`. */ DepthWrite depth_write_ = DepthWrite::ANY; /** @@ -296,6 +298,7 @@ struct ShaderCreateInfo { /** Manually set generated code. */ std::string vertex_source_generated = ""; std::string fragment_source_generated = ""; + std::string geometry_source_generated = ""; std::string typedef_source_generated = ""; /** Manually set generated dependencies. */ Vector dependencies_generated; @@ -721,6 +724,12 @@ struct ShaderCreateInfo { return *(Self *)this; } + Self &legacy_resource_location(bool value) + { + legacy_resource_location_ = value; + return *(Self *)this; + } + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc index 2c6845334d3..7ee64d7e80f 100644 --- a/source/blender/gpu/intern/gpu_shader_dependency.cc +++ b/source/blender/gpu/intern/gpu_shader_dependency.cc @@ -10,11 +10,14 @@ #include #include +#include +#include "BLI_ghash.h" #include "BLI_map.hh" #include "BLI_set.hh" #include "BLI_string_ref.hh" +#include "gpu_material_library.h" #include "gpu_shader_create_info.hh" #include "gpu_shader_dependency_private.h" @@ -31,6 +34,7 @@ extern "C" { namespace blender::gpu { using GPUSourceDictionnary = Map; +using GPUFunctionDictionnary = Map; struct GPUSource { StringRefNull fullpath; @@ -41,7 +45,10 @@ struct GPUSource { shader::BuiltinBits builtins = (shader::BuiltinBits)0; std::string processed_source; - GPUSource(const char *path, const char *file, const char *datatoc) + GPUSource(const char *path, + const char *file, + const char *datatoc, + GPUFunctionDictionnary *g_functions) : fullpath(path), filename(file), source(datatoc) { /* Scan for builtins. */ @@ -92,16 +99,20 @@ struct GPUSource { if (filename.endswith(".h") || filename.endswith(".hh")) { enum_preprocess(); } + + if (is_from_material_library()) { + material_functions_parse(g_functions); + } }; - bool is_in_comment(const StringRef &input, int64_t offset) + static bool is_in_comment(const StringRef &input, int64_t offset) { return (input.rfind("/*", offset) > input.rfind("*/", offset)) || (input.rfind("//", offset) > input.rfind("\n", offset)); } template - int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0) + static int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0) { while (true) { if constexpr (reversed) { @@ -114,7 +125,7 @@ struct GPUSource { if constexpr (check_whole_word) { /* Fix false positive if something has "enum" as suffix. */ char previous_char = input[offset - 1]; - if (!(ELEM(previous_char, '\n', '\t', ' ', ':'))) { + if (!(ELEM(previous_char, '\n', '\t', ' ', ':', '(', ','))) { offset += (reversed) ? -1 : 1; continue; } @@ -129,9 +140,13 @@ struct GPUSource { } } +#define find_keyword find_str +#define rfind_keyword find_str +#define find_token find_str +#define rfind_token find_str + void print_error(const StringRef &input, int64_t offset, const StringRef message) { - std::cout << " error: " << message << "\n"; StringRef sub = input.substr(0, offset); int64_t line_number = std::count(sub.begin(), sub.end(), '\n') + 1; int64_t line_end = input.find("\n", offset); @@ -152,6 +167,12 @@ struct GPUSource { std::cout << "^\n"; } +#define CHECK(test_value, str, ofs, msg) \ + if ((test_value) == -1) { \ + print_error(str, ofs, msg); \ + continue; \ + } + /** * Transform C,C++ enum declaration into GLSL compatible defines and constants: * @@ -193,16 +214,6 @@ struct GPUSource { int64_t last_pos = 0; const bool is_cpp = filename.endswith(".hh"); -#define find_keyword find_str -#define find_token find_str -#define rfind_token find_str -#define CHECK(test_value, str, ofs, msg) \ - if ((test_value) == -1) { \ - print_error(str, ofs, msg); \ - cursor++; \ - continue; \ - } - while (true) { cursor = find_keyword(input, "enum ", cursor + 1); if (cursor == -1) { @@ -268,10 +279,6 @@ struct GPUSource { return; } -#undef find_keyword -#undef find_token -#undef rfind_token - if (last_pos != 0) { output += input.substr(last_pos); } @@ -279,37 +286,241 @@ struct GPUSource { source = processed_source.c_str(); }; + void material_functions_parse(GPUFunctionDictionnary *g_functions) + { + const StringRefNull input = source; + + const char whitespace_chars[] = " \n\t"; + + auto function_parse = [&](const StringRef &input, + int64_t &cursor, + StringRef &out_return_type, + StringRef &out_name, + StringRef &out_args) -> bool { + cursor = find_keyword(input, "void ", cursor + 1); + if (cursor == -1) { + return false; + } + int64_t arg_start = find_token(input, '(', cursor); + if (arg_start == -1) { + return false; + } + int64_t arg_end = find_token(input, ')', arg_start); + if (arg_end == -1) { + return false; + } + int64_t body_start = find_token(input, '{', arg_end); + int64_t next_semicolon = find_token(input, ';', arg_end); + if (body_start != -1 && next_semicolon != -1 && body_start > next_semicolon) { + /* Assert no prototypes but could also just skip them. */ + BLI_assert_msg(false, "No prototypes allowed in node GLSL libraries."); + } + int64_t name_start = input.find_first_not_of(whitespace_chars, input.find(' ', cursor)); + if (name_start == -1) { + return false; + } + int64_t name_end = input.find_last_not_of(whitespace_chars, arg_start); + if (name_end == -1) { + return false; + } + /* Only support void type for now. */ + out_return_type = "void"; + out_name = input.substr(name_start, name_end - name_start); + out_args = input.substr(arg_start + 1, arg_end - (arg_start + 1)); + return true; + }; + + auto keyword_parse = [&](const StringRef &str, int64_t &cursor) -> const StringRef { + int64_t keyword_start = str.find_first_not_of(whitespace_chars, cursor); + if (keyword_start == -1) { + /* No keyword found. */ + return str.substr(0, 0); + } + int64_t keyword_end = str.find_first_of(whitespace_chars, keyword_start); + if (keyword_end == -1) { + /* Last keyword. */ + keyword_end = str.size(); + } + cursor = keyword_end + 1; + return str.substr(keyword_start, keyword_end - keyword_start); + }; + + auto arg_parse = [&](const StringRef &str, + int64_t &cursor, + StringRef &out_qualifier, + StringRef &out_type, + StringRef &out_name) -> bool { + int64_t arg_start = cursor + 1; + if (arg_start >= str.size()) { + return false; + } + cursor = find_token(str, ',', arg_start); + if (cursor == -1) { + /* Last argument. */ + cursor = str.size(); + } + const StringRef arg = str.substr(arg_start, cursor - arg_start); + + int64_t keyword_cursor = 0; + out_qualifier = keyword_parse(arg, keyword_cursor); + out_type = keyword_parse(arg, keyword_cursor); + out_name = keyword_parse(arg, keyword_cursor); + if (out_name.is_empty()) { + /* No qualifier case. */ + out_name = out_type; + out_type = out_qualifier; + out_qualifier = arg.substr(0, 0); + } + return true; + }; + + int64_t cursor = -1; + StringRef func_return_type, func_name, func_args; + while (function_parse(input, cursor, func_return_type, func_name, func_args)) { + GPUFunction *func = MEM_new(__func__); + func_name.copy(func->name, sizeof(func->name)); + func->source = reinterpret_cast(this); + + bool insert = g_functions->add(func->name, func); + + /* NOTE: We allow overloading non void function, but only if the function comes from the + * same file. Otherwise the dependency system breaks. */ + if (!insert) { + GPUSource *other_source = reinterpret_cast( + g_functions->lookup(func_name)->source); + if (other_source != this) { + print_error(input, + source.find(func_name), + "Function redefinition or overload in two different files ..."); + print_error( + input, other_source->source.find(func_name), "... previous definition was here"); + } + else { + /* Non-void function overload. */ + MEM_delete(func); + } + continue; + } + + if (func_return_type != "void") { + continue; + } + + func->totparam = 0; + int64_t args_cursor = -1; + StringRef arg_qualifier, arg_type, arg_name; + while (arg_parse(func_args, args_cursor, arg_qualifier, arg_type, arg_name)) { + + if (func->totparam >= ARRAY_SIZE(func->paramtype)) { + print_error(input, source.find(func_name), "Too much parameter in function"); + break; + } + + auto parse_qualifier = [](StringRef &qualifier) -> GPUFunctionQual { + if (qualifier == "out") { + return FUNCTION_QUAL_OUT; + } + else if (qualifier == "inout") { + return FUNCTION_QUAL_INOUT; + } + else { + return FUNCTION_QUAL_IN; + } + }; + + auto parse_type = [](StringRef &type) -> eGPUType { + if (type == "float") { + return GPU_FLOAT; + } + else if (type == "vec2") { + return GPU_VEC2; + } + else if (type == "vec3") { + return GPU_VEC3; + } + else if (type == "vec4") { + return GPU_VEC4; + } + else if (type == "mat3") { + return GPU_MAT3; + } + else if (type == "mat4") { + return GPU_MAT4; + } + else if (type == "sampler1DArray") { + return GPU_TEX1D_ARRAY; + } + else if (type == "sampler2DArray") { + return GPU_TEX2D_ARRAY; + } + else if (type == "sampler2D") { + return GPU_TEX2D; + } + else if (type == "sampler3D") { + return GPU_TEX3D; + } + else if (type == "Closure") { + return GPU_CLOSURE; + } + else { + return GPU_NONE; + } + }; + + func->paramqual[func->totparam] = parse_qualifier(arg_qualifier); + func->paramtype[func->totparam] = parse_type(arg_type); + + if (func->paramtype[func->totparam] == GPU_NONE) { + std::string err = "Unknown parameter type \"" + arg_type + "\""; + int64_t err_ofs = source.find(func_name); + err_ofs = find_keyword(source, arg_name, err_ofs); + err_ofs = rfind_keyword(source, arg_type, err_ofs); + print_error(input, err_ofs, err); + } + + func->totparam++; + } + } + } + +#undef find_keyword +#undef rfind_keyword +#undef find_token +#undef rfind_token + /* Return 1 one error. */ - int init_dependencies(const GPUSourceDictionnary &dict) + int init_dependencies(const GPUSourceDictionnary &dict, + const GPUFunctionDictionnary &g_functions) { - if (dependencies_init) { + if (this->dependencies_init) { return 0; } - dependencies_init = true; - int64_t pos = 0; + this->dependencies_init = true; + int64_t pos = -1; + while (true) { - pos = source.find("pragma BLENDER_REQUIRE(", pos); - if (pos == -1) { - return 0; - } - int64_t start = source.find('(', pos) + 1; - int64_t end = source.find(')', pos); - if (end == -1) { - /* TODO Use clog. */ - std::cout << "Error: " << filename << " : Malformed BLENDER_REQUIRE: Missing \")\"." - << std::endl; - return 1; - } - StringRef dependency_name = source.substr(start, end - start); - GPUSource *dependency_source = dict.lookup_default(dependency_name, nullptr); - if (dependency_source == nullptr) { - /* TODO Use clog. */ - std::cout << "Error: " << filename << " : Dependency not found \"" << dependency_name - << "\"." << std::endl; - return 1; + GPUSource *dependency_source = nullptr; + + { + pos = source.find("pragma BLENDER_REQUIRE(", pos + 1); + if (pos == -1) { + return 0; + } + int64_t start = source.find('(', pos) + 1; + int64_t end = source.find(')', pos); + if (end == -1) { + print_error(source, start, "Malformed BLENDER_REQUIRE: Missing \")\" token"); + return 1; + } + StringRef dependency_name = source.substr(start, end - start); + dependency_source = dict.lookup_default(dependency_name, nullptr); + if (dependency_source == nullptr) { + print_error(source, start, "Dependency not found"); + return 1; + } } /* Recursive. */ - int result = dependency_source->init_dependencies(dict); + int result = dependency_source->init_dependencies(dict, g_functions); if (result != 0) { return 1; } @@ -318,8 +529,8 @@ struct GPUSource { dependencies.append_non_duplicates(dep); } dependencies.append_non_duplicates(dependency_source); - pos++; - }; + } + return 0; } /* Returns the final string with all includes done. */ @@ -339,6 +550,11 @@ struct GPUSource { } return out_builtins; } + + bool is_from_material_library() const + { + return filename.startswith("gpu_shader_material_") && filename.endswith(".glsl"); + } }; } // namespace blender::gpu @@ -346,13 +562,15 @@ struct GPUSource { using namespace blender::gpu; static GPUSourceDictionnary *g_sources = nullptr; +static GPUFunctionDictionnary *g_functions = nullptr; void gpu_shader_dependency_init() { g_sources = new GPUSourceDictionnary(); + g_functions = new GPUFunctionDictionnary(); #define SHADER_SOURCE(datatoc, filename, filepath) \ - g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc)); + g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc, g_functions)); #include "glsl_draw_source_list.h" #include "glsl_gpu_source_list.h" #ifdef WITH_OCIO @@ -362,7 +580,7 @@ void gpu_shader_dependency_init() int errors = 0; for (auto *value : g_sources->values()) { - errors += value->init_dependencies(*g_sources); + errors += value->init_dependencies(*g_sources, *g_functions); } BLI_assert_msg(errors == 0, "Dependency errors detected: Aborting"); UNUSED_VARS_NDEBUG(errors); @@ -373,7 +591,20 @@ void gpu_shader_dependency_exit() for (auto *value : g_sources->values()) { delete value; } + for (auto *value : g_functions->values()) { + MEM_delete(value); + } delete g_sources; + delete g_functions; +} + +GPUFunction *gpu_material_library_use_function(GSet *used_libraries, const char *name) +{ + GPUFunction *function = g_functions->lookup_default(name, nullptr); + BLI_assert_msg(function != nullptr, "Requested function not in the function library"); + GPUSource *source = reinterpret_cast(function->source); + BLI_gset_add(used_libraries, const_cast(source->filename.c_str())); + return function; } namespace blender::gpu::shader { diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 5938444ce49..9768318f3b6 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -572,10 +572,13 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c } if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) { if (!GLContext::native_barycentric_support) { + ss << "flat in vec4 gpu_pos[3];\n"; ss << "smooth in vec3 gpu_BaryCoord;\n"; ss << "noperspective in vec3 gpu_BaryCoordNoPersp;\n"; + ss << "#define gpu_position_at_vertex(v) gpu_pos[v]\n"; } else if (GLEW_AMD_shader_explicit_vertex_parameter) { + std::cout << "native" << std::endl; /* NOTE(fclem): This won't work with geometry shader. Hopefully, we don't need geometry * shader workaround if this extension/feature is detected. */ ss << "\n/* Stable Barycentric Coordinates. */\n"; @@ -591,6 +594,12 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { return bary.yzx; }\n"; ss << " return bary.xyz;\n"; ss << "}\n"; + ss << "\n"; + ss << "vec4 gpu_position_at_vertex(int v) {\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 0) == gpu_pos_flat) { v = (v + 2) % 3; }\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { v = (v + 1) % 3; }\n"; + ss << " return interpolateAtVertexAMD(gpu_pos, v);\n"; + ss << "}\n"; pre_main += " gpu_BaryCoord = stable_bary_(gl_BaryCoordSmoothAMD);\n"; pre_main += " gpu_BaryCoordNoPersp = stable_bary_(gl_BaryCoordNoPerspAMD);\n"; @@ -730,6 +739,7 @@ std::string GLShader::workaround_geometry_shader_source_create( ss << "in int gpu_Layer[];\n"; } if (do_barycentric_workaround) { + ss << "flat out vec4 gpu_pos[3];\n"; ss << "smooth out vec3 gpu_BaryCoord;\n"; ss << "noperspective out vec3 gpu_BaryCoordNoPersp;\n"; } @@ -740,6 +750,11 @@ std::string GLShader::workaround_geometry_shader_source_create( if (do_layer_workaround) { ss << " gl_Layer = gpu_Layer[0];\n"; } + if (do_barycentric_workaround) { + ss << " gpu_pos[0] = gl_in[0].gl_Position;\n"; + ss << " gpu_pos[1] = gl_in[1].gl_Position;\n"; + ss << " gpu_pos[2] = gl_in[2].gl_Position;\n"; + } for (auto i : IndexRange(3)) { for (StageInterfaceInfo *iface : info_modified.vertex_out_interfaces_) { for (auto &inout : iface->inouts) { @@ -977,7 +992,7 @@ bool GLShader::finalize(const shader::ShaderCreateInfo *info) return false; } - if (info != nullptr) { + if (info != nullptr && info->legacy_resource_location_ == false) { interface = new GLShaderInterface(shader_program_, *info); } else { diff --git a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl index 193a4190cbf..5c97eada77d 100644 --- a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl @@ -95,3 +95,176 @@ vec4 tangent_get(vec4 attr, mat3 normalmat) } #endif + +/* Assumes GPU_VEC4 is color data. So converting to luminance like cycles. */ +#define float_from_vec4(v) dot(v.rgb, vec3(0.2126, 0.7152, 0.0722)) +#define float_from_vec3(v) avg(v.rgb) +#define float_from_vec2(v) v.r + +#define vec2_from_vec4(v) vec2(avg(v.rgb), v.a) +#define vec2_from_vec3(v) vec2(avg(v.rgb), 1.0) +#define vec2_from_float(v) vec2(v) + +#define vec3_from_vec4(v) v.rgb +#define vec3_from_vec2(v) v.rrr +#define vec3_from_float(v) vec3(v) + +#define vec4_from_vec3(v) vec4(v, 1.0) +#define vec4_from_vec2(v) v.rrrg +#define vec4_from_float(v) vec4(vec3(v), 1.0) + +/* TODO: Move to shader_shared. */ +#define RAY_TYPE_CAMERA 0 +#define RAY_TYPE_SHADOW 1 +#define RAY_TYPE_DIFFUSE 2 +#define RAY_TYPE_GLOSSY 3 + +#ifdef GPU_FRAGMENT_SHADER +# define FrontFacing gl_FrontFacing +#else +# define FrontFacing true +#endif + +struct ClosureDiffuse { + float weight; + vec3 color; + vec3 N; + vec3 sss_radius; + uint sss_id; +}; + +struct ClosureTranslucent { + float weight; + vec3 color; + vec3 N; +}; + +struct ClosureReflection { + float weight; + vec3 color; + vec3 N; + float roughness; +}; + +struct ClosureRefraction { + float weight; + vec3 color; + vec3 N; + float roughness; + float ior; +}; + +struct ClosureHair { + float weight; + vec3 color; + float offset; + vec2 roughness; + vec3 T; +}; + +struct ClosureVolumeScatter { + float weight; + vec3 scattering; + float anisotropy; +}; + +struct ClosureVolumeAbsorption { + float weight; + vec3 absorption; +}; + +struct ClosureEmission { + float weight; + vec3 emission; +}; + +struct ClosureTransparency { + float weight; + vec3 transmittance; + float holdout; +}; + +struct GlobalData { + /** World position. */ + vec3 P; + /** Surface Normal. */ + vec3 N; + /** Geometric Normal. */ + vec3 Ng; + /** Surface default Tangent. */ + vec3 T; + /** Barycentric coordinates. */ + vec2 barycentric_coords; + vec3 barycentric_dists; + /** Ray properties (approximation). */ + int ray_type; + float ray_depth; + float ray_length; + /** Hair time along hair length. 0 at base 1 at tip. */ + float hair_time; + /** Hair time along width of the hair. */ + float hair_time_width; + /** Hair thickness in world space. */ + float hair_thickness; + /** Index of the strand for per strand effects. */ + int hair_strand_id; + /** Is hair. */ + bool is_strand; +}; + +GlobalData g_data; + +#ifndef GPU_FRAGMENT_SHADER +/* Stubs. */ +vec3 dF_impl(vec3 v) +{ + return vec3(0.0); +} + +void dF_branch(float fn, out vec2 result) +{ + result = vec2(0.0); +} + +#elif 0 /* TODO(@fclem): User Option? */ +/* Fast derivatives */ +vec3 dF_impl(vec3 v) +{ + return vec3(0.0); +} + +void dF_branch(float fn, out vec2 result) +{ + result.x = DFDX_SIGN * dFdx(fn); + result.y = DFDY_SIGN * dFdy(fn); +} + +#else +/* Precise derivatives */ +int g_derivative_flag = 0; + +vec3 dF_impl(vec3 v) +{ + if (g_derivative_flag > 0) { + return DFDX_SIGN * dFdx(v); + } + else if (g_derivative_flag < 0) { + return DFDY_SIGN * dFdy(v); + } + return vec3(0.0); +} + +# define dF_branch(fn, result) \ + if (true) { \ + g_derivative_flag = 1; \ + result.x = (fn); \ + g_derivative_flag = -1; \ + result.y = (fn); \ + g_derivative_flag = 0; \ + result -= vec2((fn)); \ + } + +#endif + +/* TODO(fclem): Remove. */ +#define CODEGEN_LIB diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl index 12921a31b23..4ba1f6f7368 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl @@ -1,4 +1,4 @@ -#ifndef VOLUMETRICS + void node_ambient_occlusion(vec4 color, float dist, vec3 normal, @@ -7,20 +7,6 @@ void node_ambient_occlusion(vec4 color, out vec4 result_color, out float result_ao) { - vec3 bent_normal; - vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); - OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, sample_count); - - vec3 V = cameraVec(worldPosition); - vec3 N = normalize(normal); - vec3 Ng = safe_normalize(cross(dFdx(worldPosition), dFdy(worldPosition))); - - float unused_error; - vec3 unused; - occlusion_eval(data, V, N, Ng, inverted, result_ao, unused_error, unused); + result_ao = ambient_occlusion_eval(normal, dist, inverted, sample_count); result_color = result_ao * color; } -#else -/* Stub ambient occlusion because it is not compatible with volumetrics. */ -# define node_ambient_occlusion(a, b, c, d, e, f) (e = vec4(0); f = 0.0) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl index ec49cc86761..77de9e096a6 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl @@ -1,17 +1,27 @@ -#ifndef VOLUMETRICS + void node_bsdf_anisotropic(vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T, - const float use_multiscatter, - const float ssr_id, + float weight, + const float do_multiscatter, out Closure result) { - node_bsdf_glossy(color, roughness, N, use_multiscatter, ssr_id, result); + N = safe_normalize(N); + vec3 V = cameraVec(g_data.P); + float NV = dot(N, V); + + vec2 split_sum = brdf_lut(NV, roughness); + + ClosureReflection reflection_data; + reflection_data.weight = weight; + reflection_data.color = (do_multiscatter != 0.0) ? + F_brdf_multi_scatter(color.rgb, color.rgb, split_sum) : + F_brdf_single_scatter(color.rgb, color.rgb, split_sum); + reflection_data.N = N; + reflection_data.roughness = roughness; + + result = closure_eval(reflection_data); } -#else -/* Stub anisotropic because it is not compatible with volumetrics. */ -# define node_bsdf_anisotropic(a, b, c, d, e, f, g, h, result) (result = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl index 69ef4dcb7c7..2460bd63b38 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl @@ -1,11 +1,9 @@ -void node_background(vec4 color, float strength, out Closure result) + +void node_background(vec4 color, float strength, float weight, out Closure result) { -#ifndef VOLUMETRICS - color *= strength; - result = CLOSURE_DEFAULT; - result.radiance = color.rgb; - result.transmittance = vec3(0.0); -#else - result = CLOSURE_DEFAULT; -#endif + ClosureEmission emission_data; + emission_data.weight = weight; + emission_data.emission = color.rgb * strength; + + result = closure_eval(emission_data); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl index 9f73f654217..e0931128485 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl @@ -1,28 +1,19 @@ -void dfdx_v3(vec3 v, out vec3 dy) -{ - dy = v + DFDX_SIGN * dFdx(v); -} -void dfdy_v3(vec3 v, out vec3 dy) +void differentiate_texco(vec3 v, out vec3 df) { - dy = v + DFDY_SIGN * dFdy(v); + /* Implementation defined. */ + df = v + dF_impl(v); } -void node_bump(float strength, - float dist, - float height, - float height_dx, - float height_dy, - vec3 N, - vec3 surf_pos, - float invert, - out vec3 result) +void node_bump( + float strength, float dist, float height, vec3 N, vec2 dHd, float invert, out vec3 result) { - N = mat3(ViewMatrix) * normalize(N); - dist *= gl_FrontFacing ? invert : -invert; + N = normalize(N); + dist *= FrontFacing ? invert : -invert; - vec3 dPdx = dFdx(surf_pos); - vec3 dPdy = dFdy(surf_pos); +#ifdef GPU_FRAGMENT_SHADER + vec3 dPdx = dFdx(g_data.P); + vec3 dPdy = dFdy(g_data.P); /* Get surface tangents from normal. */ vec3 Rx = cross(dPdy, N); @@ -31,14 +22,13 @@ void node_bump(float strength, /* Compute surface gradient and determinant. */ float det = dot(dPdx, Rx); - float dHdx = height_dx - height; - float dHdy = height_dy - height; - vec3 surfgrad = dHdx * Rx + dHdy * Ry; + vec3 surfgrad = dHd.x * Rx + dHd.y * Ry; strength = max(strength, 0.0); result = normalize(abs(det) * N - dist * sign(det) * surfgrad); result = normalize(mix(N, result, strength)); - - result = mat3(ViewMatrixInverse) * result; +#else + result = N; +#endif } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl index 03e61e9f472..ff84a0a334c 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl @@ -1,6 +1,6 @@ -void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist) +void camera(out vec3 outview, out float outdepth, out float outdist) { - outdepth = abs(co.z); - outdist = length(co); - outview = normalize(co); + outdepth = abs(transform_point(ViewMatrix, g_data.P).z); + outdist = distance(g_data.P, cameraPos); + outview = normalize(g_data.P - cameraPos); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl index 2ce061da3cb..e8f444080b9 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl) + void combine_hsv(float h, float s, float v, out vec4 col) { hsv_to_rgb(vec4(h, s, v, 1.0), col); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl index ab6024b073d..bbdd86bd664 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl @@ -1,28 +1,11 @@ -#ifndef VOLUMETRICS -CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_diffuse, Diffuse) - -void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result) +void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, float weight, out Closure result) { - CLOSURE_VARS_DECLARE_1(Diffuse); - - in_Diffuse_0.N = N; /* Normalized during eval. */ - in_Diffuse_0.albedo = color.rgb; - - CLOSURE_EVAL_FUNCTION_1(node_bsdf_diffuse, Diffuse); - - result = CLOSURE_DEFAULT; + ClosureDiffuse diffuse_data; + diffuse_data.weight = weight; + diffuse_data.color = color.rgb; + diffuse_data.N = N; + diffuse_data.sss_id = 0u; - out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1.0), out_Diffuse_0.radiance); - out_Diffuse_0.radiance *= color.rgb; - - result.radiance = out_Diffuse_0.radiance; - - /* TODO(@fclem): Try to not use this. */ - closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result); + result = closure_eval(diffuse_data); } - -#else -/* Stub diffuse because it is not compatible with volumetrics. */ -# define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl index 0838b5c8b71..cdcdbe50917 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl @@ -1,9 +1,9 @@ -void node_displacement_object( - float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result) +void node_displacement_object(float height, float midlevel, float scale, vec3 N, out vec3 result) { - N = (vec4(N, 0.0) * obmat).xyz; + N = transform_direction(ModelMatrix, N); result = (height - midlevel) * scale * normalize(N); - result = (obmat * vec4(result, 0.0)).xyz; + /* Apply object scale and orientation. */ + result = transform_direction(ModelMatrix, result); } void node_displacement_world(float height, float midlevel, float scale, vec3 N, out vec3 result) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl index 0941482df45..c81880184e3 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl @@ -1,80 +1,69 @@ -#ifndef VOLUMETRICS - -CLOSURE_EVAL_FUNCTION_DECLARE_3(node_eevee_specular, Diffuse, Glossy, Glossy) void node_eevee_specular(vec4 diffuse, vec4 specular, float roughness, vec4 emissive, float transp, - vec3 normal, + vec3 N, float clearcoat, float clearcoat_roughness, - vec3 clearcoat_normal, + vec3 CN, float occlusion, - float ssr_id, + float weight, + const float use_clearcoat, out Closure result) { - CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy); - - in_common.occlusion = occlusion; - - in_Diffuse_0.N = normal; /* Normalized during eval. */ - in_Diffuse_0.albedo = diffuse.rgb; + N = safe_normalize(N); + CN = safe_normalize(CN); + vec3 V = cameraVec(g_data.P); - in_Glossy_1.N = normal; /* Normalized during eval. */ - in_Glossy_1.roughness = roughness; + ClosureEmission emission_data; + emission_data.weight = weight; + emission_data.emission = emissive.rgb; - in_Glossy_2.N = clearcoat_normal; /* Normalized during eval. */ - in_Glossy_2.roughness = clearcoat_roughness; + ClosureTransparency transparency_data; + transparency_data.weight = weight; + transparency_data.transmittance = vec3(transp); + transparency_data.holdout = 0.0; - CLOSURE_EVAL_FUNCTION_3(node_eevee_specular, Diffuse, Glossy, Glossy); + float alpha = (1.0 - transp) * weight; - result = CLOSURE_DEFAULT; + ClosureDiffuse diffuse_data; + diffuse_data.weight = alpha; + diffuse_data.color = diffuse.rgb; + diffuse_data.N = N; + diffuse_data.sss_id = 0u; - vec3 V = cameraVec(worldPosition); - - { - /* Diffuse. */ - out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1), out_Diffuse_0.radiance); - out_Diffuse_0.radiance *= in_Diffuse_0.albedo; - result.radiance += out_Diffuse_0.radiance; - } - { - /* Glossy. */ - float NV = dot(in_Glossy_1.N, V); - vec2 split_sum = brdf_lut(NV, in_Glossy_1.roughness); + ClosureReflection reflection_data; + reflection_data.weight = alpha; + if (true) { + float NV = dot(N, V); + vec2 split_sum = brdf_lut(NV, roughness); vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum); - out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id); - out_Glossy_1.radiance *= brdf; - out_Glossy_1.radiance = render_pass_glossy_mask(specular.rgb, out_Glossy_1.radiance); - closure_load_ssr_data( - out_Glossy_1.radiance, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result); + reflection_data.color = specular.rgb * brdf; + reflection_data.N = N; + reflection_data.roughness = roughness; } - { - /* Clearcoat. */ - float NV = dot(in_Glossy_2.N, V); - vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness); + + ClosureReflection clearcoat_data; + clearcoat_data.weight = alpha * clearcoat * 0.25; + if (true) { + float NV = dot(CN, V); + vec2 split_sum = brdf_lut(NV, clearcoat_roughness); vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum); - out_Glossy_2.radiance *= brdf * clearcoat * 0.25; - out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance); - result.radiance += out_Glossy_2.radiance; - } - { - /* Emission. */ - vec3 out_emission_radiance = render_pass_emission_mask(emissive.rgb); - result.radiance += out_emission_radiance; + clearcoat_data.color = brdf; + clearcoat_data.N = CN; + clearcoat_data.roughness = clearcoat_roughness; } - float alpha = 1.0 - transp; - result.transmittance = vec3(transp); - result.radiance *= alpha; - result.ssr_data.rgb *= alpha; + if (use_clearcoat != 0.0f) { + result = closure_eval(diffuse_data, reflection_data, clearcoat_data); + } + else { + result = closure_eval(diffuse_data, reflection_data); + } + result = closure_add(result, closure_eval(emission_data)); + result = closure_add(result, closure_eval(transparency_data)); } - -#else -/* Stub specular because it is not compatible with volumetrics. */ -# define node_eevee_specular(a, b, c, d, e, f, g, h, i, j, k, result) (result = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl index f2de7c2da39..32484491abd 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl @@ -1,10 +1,9 @@ -void node_emission(vec4 color, float strength, vec3 vN, out Closure result) + +void node_emission(vec4 color, float strength, float weight, out Closure result) { - result = CLOSURE_DEFAULT; -#ifndef VOLUMETRICS - result.radiance = render_pass_emission_mask(color.rgb) * strength; - result.ssr_normal = normal_encode(vN, viewCameraVec(viewPosition)); -#else - result.emission = color.rgb * strength; -#endif + ClosureEmission emission_data; + emission_data.weight = weight; + emission_data.emission = color.rgb * strength; + + result = closure_eval(emission_data); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl index 95f2be4bd44..7f502f74c0c 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl @@ -1,3 +1,6 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl) + /* The fractal_noise functions are all exactly the same except for the input type. */ float fractal_noise(float p, float octaves, float roughness) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl index 7a4d28f2dd6..9fb98d598ab 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl @@ -26,12 +26,11 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) return fresnel_dielectric_cos(dot(Incoming, Normal), eta); } -void node_fresnel(float ior, vec3 N, vec3 I, out float result) +void node_fresnel(float ior, vec3 N, out float result) { N = normalize(N); - /* handle perspective/orthographic */ - vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); + vec3 V = cameraVec(g_data.P); float eta = max(ior, 0.00001); - result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta); + result = fresnel_dielectric(V, N, (FrontFacing) ? eta : 1.0 / eta); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl index 5733992f8dd..29fb09ceebd 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) + void node_gamma(vec4 col, float gamma, out vec4 outcol) { outcol = col; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl index a14ff5021bf..5e86a4577ee 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl @@ -1,9 +1,6 @@ -void node_geometry(vec3 I, - vec3 N, - vec3 orco, - mat4 objmat, - mat4 toworld, - vec2 barycentric, +#pragma BLENDER_REQUIRE(gpu_shader_material_tangent.glsl) + +void node_geometry(vec3 orco, out vec3 position, out vec3 normal, out vec3 tangent, @@ -15,39 +12,21 @@ void node_geometry(vec3 I, out float random_per_island) { /* handle perspective/orthographic */ - vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); - incoming = -(toworld * vec4(I_view, 0.0)).xyz; - -#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) - position = -incoming; - true_normal = normal = incoming; - tangent = parametric = vec3(0.0); - vec3(0.0); - backfacing = 0.0; - pointiness = 0.0; -#else - - position = worldPosition; -# ifndef VOLUMETRICS - normal = normalize(N); - vec3 B = dFdx(worldPosition); - vec3 T = dFdy(worldPosition); - true_normal = normalize(cross(B, T)); -# else - normal = (toworld * vec4(N, 0.0)).xyz; - true_normal = normal; -# endif + incoming = coordinate_incoming(g_data.P); + position = g_data.P; + normal = g_data.N; + true_normal = g_data.Ng; -# ifdef HAIR_SHADER - tangent = -hairTangent; -# else - tangent_orco_z(orco, orco); - node_tangent(N, orco, objmat, tangent); -# endif + if (g_data.is_strand) { + tangent = g_data.T; + } + else { + tangent_orco_z(orco, orco); + node_tangent(orco, tangent); + } - parametric = vec3(barycentric, 0.0); - backfacing = (gl_FrontFacing) ? 0.0 : 1.0; + parametric = vec3(g_data.barycentric_coords, 0.0); + backfacing = (FrontFacing) ? 0.0 : 1.0; pointiness = 0.5; random_per_island = 0.0; -#endif } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl index aa0a8873596..36c71c27837 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl @@ -1,57 +1,33 @@ -#ifndef VOLUMETRICS - -CLOSURE_EVAL_FUNCTION_DECLARE_2(node_bsdf_glass, Glossy, Refraction) void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, - const float do_multiscatter, - const float ssr_id, + float weight, + float do_multiscatter, out Closure result) { - CLOSURE_VARS_DECLARE_2(Glossy, Refraction); - - in_Glossy_0.N = N; /* Normalized during eval. */ - in_Glossy_0.roughness = roughness; - - in_Refraction_1.N = N; /* Normalized during eval. */ - in_Refraction_1.roughness = roughness; - in_Refraction_1.ior = ior; + N = safe_normalize(N); + vec3 V = cameraVec(g_data.P); + float NV = dot(N, V); - CLOSURE_EVAL_FUNCTION_2(node_bsdf_glass, Glossy, Refraction); + vec2 split_sum = btdf_lut(NV, roughness, ior); - result = CLOSURE_DEFAULT; + float fresnel = (do_multiscatter != 0.0) ? split_sum.y : F_eta(ior, NV); + float btdf = (do_multiscatter != 0.0) ? 1.0 : split_sum.x; - float NV = dot(in_Refraction_1.N, cameraVec(worldPosition)); + ClosureReflection reflection_data; + reflection_data.weight = fresnel * weight; + reflection_data.color = color.rgb; + reflection_data.N = N; + reflection_data.roughness = roughness; - float fresnel = (do_multiscatter != 0.0) ? - btdf_lut(NV, in_Refraction_1.roughness, in_Refraction_1.ior).y : - F_eta(in_Refraction_1.ior, NV); + ClosureRefraction refraction_data; + refraction_data.weight = (1.0 - fresnel) * weight; + refraction_data.color = color.rgb * btdf; + refraction_data.N = N; + refraction_data.roughness = roughness; + refraction_data.ior = ior; - vec2 split_sum = brdf_lut(NV, in_Glossy_0.roughness); - vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) : - F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum); - - out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id); - out_Glossy_0.radiance *= brdf; - out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance); - out_Glossy_0.radiance *= color.rgb * fresnel; - closure_load_ssr_data( - out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result); - - float btdf = (do_multiscatter != 0.0) ? - 1.0 : - btdf_lut(NV, in_Refraction_1.roughness, in_Refraction_1.ior).x; - out_Refraction_1.radiance *= btdf; - out_Refraction_1.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_1.radiance); - out_Refraction_1.radiance *= color.rgb * (1.0 - fresnel); - /* Simulate 2nd absorption event. */ - out_Refraction_1.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); - result.radiance += out_Refraction_1.radiance; + result = closure_eval(reflection_data, refraction_data); } - -#else -/* Stub glass because it is not compatible with volumetrics. */ -# define node_bsdf_glass(a, b, c, d, e, f, result) (result = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl index fa83bfb6c7a..2e48ddd1c5e 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl @@ -1,33 +1,20 @@ -#ifndef VOLUMETRICS - -CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_glossy, Glossy) void node_bsdf_glossy( - vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result) + vec4 color, float roughness, vec3 N, float weight, float do_multiscatter, out Closure result) { - bool do_ssr = (ssrToggle && int(ssr_id) == outputSsrId); - - CLOSURE_VARS_DECLARE_1(Glossy); + N = safe_normalize(N); + vec3 V = cameraVec(g_data.P); + float NV = dot(N, V); - in_Glossy_0.N = N; /* Normalized during eval. */ - in_Glossy_0.roughness = roughness; + vec2 split_sum = brdf_lut(NV, roughness); - CLOSURE_EVAL_FUNCTION_1(node_bsdf_glossy, Glossy); + ClosureReflection reflection_data; + reflection_data.weight = weight; + reflection_data.color = (do_multiscatter != 0.0) ? + F_brdf_multi_scatter(color.rgb, color.rgb, split_sum) : + F_brdf_single_scatter(color.rgb, color.rgb, split_sum); + reflection_data.N = N; + reflection_data.roughness = roughness; - result = CLOSURE_DEFAULT; - - vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec(worldPosition)), in_Glossy_0.roughness); - vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) : - F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum); - out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id); - out_Glossy_0.radiance *= brdf; - out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance); - out_Glossy_0.radiance *= color.rgb; - closure_load_ssr_data( - out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result); + result = closure_eval(reflection_data); } - -#else -/* Stub glossy because it is not compatible with volumetrics. */ -# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl new file mode 100644 index 00000000000..7bf8795495a --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl @@ -0,0 +1,46 @@ + +void node_bsdf_hair(vec4 color, + float offset, + float roughness_u, + float roughness_v, + vec3 T, + float weight, + out Closure result) +{ + ClosureHair hair_data; + hair_data.weight = weight; + hair_data.color = color.rgb; + hair_data.offset = offset; + hair_data.roughness = vec2(roughness_u, roughness_v); + hair_data.T = T; + + result = closure_eval(hair_data); +} + +void node_bsdf_hair_principled(vec4 color, + float melanin, + float melanin_redness, + vec4 tint, + vec3 absorption_coefficient, + float roughness, + float radial_roughness, + float coat, + float ior, + float offset, + float random_color, + float random_roughness, + float random, + float weight, + out Closure result) +{ + /* Placeholder closure. + * Some computation will have to happen here just like the Principled BSDF. */ + ClosureHair hair_data; + hair_data.weight = weight; + hair_data.color = color.rgb; + hair_data.offset = offset; + hair_data.roughness = vec2(0.0); + hair_data.T = g_data.T; + + result = closure_eval(hair_data); +} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl index 59f0377869b..2885bf4e082 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl @@ -1,25 +1,19 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) + void node_hair_info(float hair_length, out float is_strand, out float intercept, - out float length, + out float out_length, out float thickness, out vec3 tangent, out float random) { - length = hair_length; -#ifdef HAIR_SHADER - is_strand = 1.0; - intercept = hairTime; - thickness = hairThickness; - tangent = normalize(worldNormal); - random = wang_hash_noise( - uint(hairStrandID)); /* TODO: could be precomputed per strand instead. */ -#else - is_strand = 0.0; - intercept = 0.0; - thickness = 0.0; - tangent = vec3(1.0); - random = 0.0; -#endif + is_strand = float(g_data.is_strand); + intercept = g_data.hair_time; + thickness = g_data.hair_thickness; + out_length = hair_length; + tangent = g_data.T; + /* TODO: could be precomputed per strand instead. */ + random = wang_hash_noise(uint(g_data.hair_strand_id)); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl index 50ce2bf2ab8..d022c1ced59 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl @@ -1,8 +1,10 @@ -void node_holdout(out Closure result) + +void node_holdout(float weight, out Closure result) { - result = CLOSURE_DEFAULT; -#ifndef VOLUMETRICS - result.holdout = 1.0; - result.flag = CLOSURE_HOLDOUT_FLAG; -#endif + ClosureTransparency transparency_data; + transparency_data.weight = weight; + transparency_data.transmittance = vec3(0.0); + transparency_data.holdout = 1.0; + + result = closure_eval(transparency_data); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl index 64ac73ecdf3..30b808508e9 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl) + void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol) { vec4 hsv; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl index 588d295bcc4..2b61343a200 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl @@ -1,15 +1,17 @@ -void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float facing) +#pragma BLENDER_REQUIRE(gpu_shader_material_fresnel.glsl) + +void node_layer_weight(float blend, vec3 N, out float fresnel, out float facing) { N = normalize(N); /* fresnel */ float eta = max(1.0 - blend, 0.00001); - vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); + vec3 V = cameraVec(g_data.P); - fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta); + fresnel = fresnel_dielectric(V, N, (FrontFacing) ? 1.0 / eta : eta); /* facing */ - facing = abs(dot(I_view, N)); + facing = abs(dot(V, N)); if (blend != 0.5) { blend = clamp(blend, 0.0, 0.99999); blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl index 50c87e3f105..628a3d5e0e5 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl @@ -13,19 +13,19 @@ void node_light_path(out float is_camera_ray, out float transmission_depth) { /* Supported. */ - is_camera_ray = (rayType == EEVEE_RAY_CAMERA) ? 1.0 : 0.0; - is_shadow_ray = (rayType == EEVEE_RAY_SHADOW) ? 1.0 : 0.0; - is_diffuse_ray = (rayType == EEVEE_RAY_DIFFUSE) ? 1.0 : 0.0; - is_glossy_ray = (rayType == EEVEE_RAY_GLOSSY) ? 1.0 : 0.0; + is_camera_ray = float(g_data.ray_type == RAY_TYPE_CAMERA); + is_shadow_ray = float(g_data.ray_type == RAY_TYPE_SHADOW); + is_diffuse_ray = float(g_data.ray_type == RAY_TYPE_DIFFUSE); + is_glossy_ray = float(g_data.ray_type == RAY_TYPE_GLOSSY); /* Kind of supported. */ is_singular_ray = is_glossy_ray; is_reflection_ray = is_glossy_ray; is_transmission_ray = is_glossy_ray; - ray_depth = rayDepth; - diffuse_depth = (is_diffuse_ray == 1.0) ? rayDepth : 0.0; - glossy_depth = (is_glossy_ray == 1.0) ? rayDepth : 0.0; + ray_depth = g_data.ray_depth; + diffuse_depth = (is_diffuse_ray == 1.0) ? g_data.ray_depth : 0.0; + glossy_depth = (is_glossy_ray == 1.0) ? g_data.ray_depth : 0.0; transmission_depth = (is_transmission_ray == 1.0) ? glossy_depth : 0.0; + ray_length = g_data.ray_length; /* Not supported. */ - ray_length = 1.0; transparent_depth = 0.0; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl index 1def3abec26..119ee3c0eaa 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) + float smootherstep(float edge0, float edge1, float x) { x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl index 07f152439fe..312c57231c5 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) + void mapping_mat4( vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl index f200d666e28..0948ce2c9fa 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) + void math_add(float a, float b, float c, out float result) { result = a + b; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl index 2a98d9fadd0..91a8996939a 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl @@ -140,17 +140,74 @@ mat3 euler_to_mat3(vec3 euler) return mat; } -void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout) +void normal_transform_object_to_world(vec3 vin, out vec3 vout) { - vout = (mat * vec4(vin, 0.0)).xyz; + vout = normal_object_to_world(vin); } -void normal_transform_transposed_m4v3(vec3 vin, mat4 mat, out vec3 vout) +void normal_transform_world_to_object(vec3 vin, out vec3 vout) { - vout = transpose(mat3(mat)) * vin; + vout = normal_world_to_object(vin); } -void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout) +void direction_transform_object_to_world(vec3 vin, out vec3 vout) { - vout = (mat * vec4(vin, 1.0)).xyz; + vout = transform_direction(ModelMatrix, vin); +} + +void direction_transform_object_to_view(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ModelMatrix, vin); + vout = transform_direction(ViewMatrix, vout); +} + +void direction_transform_view_to_world(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ViewMatrixInverse, vin); +} + +void direction_transform_view_to_object(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ViewMatrixInverse, vin); + vout = transform_direction(ModelMatrixInverse, vout); +} + +void direction_transform_world_to_view(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ViewMatrix, vin); +} + +void direction_transform_world_to_object(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ModelMatrixInverse, vin); +} + +void point_transform_object_to_world(vec3 vin, out vec3 vout) +{ + vout = point_object_to_world(vin); +} + +void point_transform_object_to_view(vec3 vin, out vec3 vout) +{ + vout = point_object_to_view(vin); +} + +void point_transform_view_to_world(vec3 vin, out vec3 vout) +{ + vout = point_view_to_world(vin); +} + +void point_transform_view_to_object(vec3 vin, out vec3 vout) +{ + vout = point_view_to_object(vin); +} + +void point_transform_world_to_view(vec3 vin, out vec3 vout) +{ + vout = point_world_to_view(vin); +} + +void point_transform_world_to_object(vec3 vin, out vec3 vout) +{ + vout = point_world_to_object(vin); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl index e089aec1d92..157a6a27c15 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl) + void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol) { fac = clamp(fac, 0.0, 1.0); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl index cc65b1eb57c..c84f34a834c 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) + /* clang-format off */ #define FLOORFRAC(x, x_int, x_fract) { float x_floor = floor(x); x_int = int(x_floor); x_fract = x - x_floor; } /* clang-format on */ diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl index 2b4a0204d97..e219e2b9bbe 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl @@ -1,13 +1,13 @@ -void node_normal_map(vec4 info, vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal) +void node_normal_map(vec4 tangent, vec3 texnormal, out vec3 outnormal) { if (all(equal(tangent, vec4(0.0, 0.0, 0.0, 1.0)))) { - outnormal = normal; + outnormal = g_data.N; return; } - tangent *= (gl_FrontFacing ? 1.0 : -1.0); - vec3 B = tangent.w * cross(normal, tangent.xyz) * sign(info.w); + tangent *= (FrontFacing ? 1.0 : -1.0); + vec3 B = tangent.w * cross(g_data.N, tangent.xyz) * sign(ObjectInfo.w); - outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal; + outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * g_data.N; outnormal = normalize(outnormal); } @@ -21,7 +21,7 @@ void color_to_blender_normal_new_shading(vec3 color, out vec3 normal) normal = vec3(2.0, -2.0, -2.0) * color - vec3(1.0); } -void node_normal_map_mix(float strength, vec3 newnormal, vec3 oldnormal, out vec3 outnormal) +void node_normal_map_mix(float strength, vec3 newnormal, out vec3 outnormal) { - outnormal = normalize(mix(oldnormal, newnormal, max(strength, 0.0))); + outnormal = normalize(mix(g_data.N, newnormal, max(strength, 0.0))); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl index 607cf119b36..2dd2993ceb0 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl @@ -1,7 +1,4 @@ -void node_object_info(mat4 obmat, - vec4 obcolor, - vec4 info, - float mat_index, +void node_object_info(float mat_index, out vec3 location, out vec4 color, out float alpha, @@ -9,10 +6,11 @@ void node_object_info(mat4 obmat, out float material_index, out float random) { - location = obmat[3].xyz; - color = obcolor; - alpha = obcolor.w; - object_index = info.x; + location = ModelMatrix[3].xyz; + color = ObjectColor; + alpha = ObjectColor.a; + object_index = ObjectInfo.x; + /* TODO(fclem): Put that inside the Material UBO. */ material_index = mat_index; - random = info.z; + random = ObjectInfo.z; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl index 648994739bf..b166c3e4e9f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl @@ -1,13 +1,5 @@ -void node_output_aov(vec4 color, float value, out Closure result) +void node_output_aov(vec4 color, float value, float hash, out Closure dummy) { - result = CLOSURE_DEFAULT; -#ifndef VOLUMETRICS - if (render_pass_aov_is_color()) { - result.radiance = color.rgb; - } - else { - result.radiance = vec3(value); - } -#endif + output_aov(color, value, floatBitsToUint(hash)); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl index 14271f9d107..2c24f50264c 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl @@ -1,20 +1,20 @@ -void node_output_material(Closure surface, - Closure volume, - vec3 displacement, - float alpha_threshold, - float shadow_threshold, - out Closure result) + +void node_output_material_surface(Closure surface, out Closure out_surface) { -#ifdef VOLUMETRICS - result = volume; -#else - result = surface; -# if defined(USE_ALPHA_HASH) - /* Alpha clip emulation. */ - if ((rayType != EEVEE_RAY_SHADOW) ? (alpha_threshold >= 0.0) : (shadow_threshold >= 0.0)) { - float alpha = saturate(1.0 - avg(result.transmittance)); - result.transmittance = vec3(step(alpha, max(alpha_threshold, shadow_threshold))); - } -# endif -#endif + out_surface = surface; +} + +void node_output_material_volume(Closure volume, out Closure out_volume) +{ + out_volume = volume; +} + +void node_output_material_displacement(vec3 displacement, out vec3 out_displacement) +{ + out_displacement = displacement; +} + +void node_output_material_thickness(float thickness, out float out_thickness) +{ + out_thickness = thickness; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl index 5eb853a4c1a..37c34a4f0d7 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl @@ -1,14 +1,10 @@ -uniform float backgroundAlpha; -void node_output_world(Closure surface, Closure volume, out Closure result) +void node_output_world_surface(Closure surface, out Closure out_surface) { -#ifndef VOLUMETRICS - float alpha = renderPassEnvironment ? 1.0 : backgroundAlpha; - result = CLOSURE_DEFAULT; - result.radiance = surface.radiance * alpha; - result.transmittance = vec3(0.0); - result.holdout = (1.0 - alpha); -#else - result = volume; -#endif /* VOLUMETRICS */ + out_surface = surface; +} + +void node_output_world_volume(Closure volume, out Closure out_volume) +{ + out_volume = volume; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl index bdd60c20a81..5602345ea4a 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl @@ -1,8 +1,4 @@ -void particle_info(vec4 sprops, - vec4 loc, - vec3 vel, - vec3 avel, - out float index, +void particle_info(out float index, out float random, out float age, out float life_time, @@ -11,13 +7,14 @@ void particle_info(vec4 sprops, out vec3 velocity, out vec3 angular_velocity) { - index = sprops.x; - random = loc.w; - age = sprops.y; - life_time = sprops.z; - size = sprops.w; + /* Unsupported for now. */ + index = 0.0; + random = 0.0; + age = 0.0; + life_time = 0.0; + size = 0.0; - location = loc.xyz; - velocity = vel; - angular_velocity = avel; + location = vec3(0.0); + velocity = vec3(0.0); + angular_velocity = vec3(0.0); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl index d717ac97b28..1b1fed9502e 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) + void node_point_info(out vec3 position, out float radius, out float random) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index c97fc090fe2..033dc05c57d 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -1,4 +1,4 @@ -#ifndef VOLUMETRICS + vec3 tint_from_color(vec3 color) { float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */ @@ -13,8 +13,6 @@ float principled_sheen(float NV) return sheen; } -CLOSURE_EVAL_FUNCTION_DECLARE_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction) - void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, @@ -40,169 +38,137 @@ void node_bsdf_principled(vec4 base_color, vec3 N, vec3 CN, vec3 T, + float weight, const float do_diffuse, const float do_clearcoat, const float do_refraction, const float do_multiscatter, - float ssr_id, - float sss_id, - vec3 sss_scale, + float do_sss, out Closure result) { /* Match cycles. */ - metallic = saturate(metallic); - transmission = saturate(transmission); + metallic = clamp(metallic, 0.0, 1.0); + transmission = clamp(transmission, 0.0, 1.0) * (1.0 - metallic); float diffuse_weight = (1.0 - transmission) * (1.0 - metallic); - transmission *= (1.0 - metallic); float specular_weight = (1.0 - transmission); - clearcoat = max(clearcoat, 0.0); + float clearcoat_weight = max(clearcoat, 0.0) * 0.25; transmission_roughness = 1.0 - (1.0 - roughness) * (1.0 - transmission_roughness); specular = max(0.0, specular); - CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction); - - in_Diffuse_0.N = N; /* Normalized during eval. */ - in_Diffuse_0.albedo = mix(base_color.rgb, subsurface_color.rgb, subsurface); - - in_Glossy_1.N = N; /* Normalized during eval. */ - in_Glossy_1.roughness = roughness; - - in_Glossy_2.N = CN; /* Normalized during eval. */ - in_Glossy_2.roughness = clearcoat_roughness; - - in_Refraction_3.N = N; /* Normalized during eval. */ - in_Refraction_3.roughness = do_multiscatter != 0.0 ? roughness : transmission_roughness; - in_Refraction_3.ior = ior; + N = safe_normalize(N); + CN = safe_normalize(CN); + vec3 V = cameraVec(g_data.P); + float NV = dot(N, V); - CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction); + float fresnel = (do_multiscatter != 0.0) ? btdf_lut(NV, roughness, ior).y : F_eta(ior, NV); + float glass_reflection_weight = fresnel * transmission; + float glass_transmission_weight = (1.0 - fresnel) * transmission; - result = CLOSURE_DEFAULT; + vec3 base_color_tint = tint_from_color(base_color.rgb); - /* This will tag the whole eval for optimisation. */ - if (do_diffuse == 0.0) { - out_Diffuse_0.radiance = vec3(0); - } - if (do_clearcoat == 0.0) { - out_Glossy_2.radiance = vec3(0); - } - if (do_refraction == 0.0) { - out_Refraction_3.radiance = vec3(0); + vec2 split_sum = brdf_lut(NV, roughness); + + ClosureTransparency transparency_data; + transparency_data.weight = weight; + transparency_data.transmittance = vec3(1.0 - alpha); + transparency_data.holdout = 0.0; + + weight *= alpha; + + ClosureEmission emission_data; + emission_data.weight = weight; + emission_data.emission = emission.rgb * emission_strength; + + /* Diffuse. */ + ClosureDiffuse diffuse_data; + diffuse_data.weight = diffuse_weight * weight; + diffuse_data.color = mix(base_color.rgb, subsurface_color.rgb, subsurface); + /* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */ + vec3 sheen_color = mix(vec3(1.0), base_color_tint, sheen_tint); + diffuse_data.color += sheen * sheen_color * principled_sheen(NV); + diffuse_data.N = N; + diffuse_data.sss_radius = subsurface_radius * subsurface; + diffuse_data.sss_id = uint(do_sss); + + /* NOTE(@fclem): We need to blend the reflection color but also need to avoid applying the + * weights so we compule the ratio. */ + float reflection_weight = specular_weight + glass_reflection_weight; + float reflection_weight_inv = safe_rcp(reflection_weight); + specular_weight *= reflection_weight_inv; + glass_reflection_weight *= reflection_weight_inv; + + /* Reflection. */ + ClosureReflection reflection_data; + reflection_data.weight = reflection_weight * weight; + reflection_data.N = N; + reflection_data.roughness = roughness; + if (true) { + vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint); + vec3 metallic_f0_color = base_color.rgb; + vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic); + /* Cycles does this blending using the microfacet fresnel factor. However, our fresnel + * is already baked inside the split sum LUT. We approximate by changing the f90 color + * directly in a non linear fashion. */ + vec3 f90 = mix(f0, vec3(1.0), fast_sqrt(specular)); + + vec3 reflection_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) : + F_brdf_single_scatter(f0, f90, split_sum); + reflection_data.color = reflection_brdf * specular_weight; } + if (true) { + /* Poor approximation since we baked the LUT using a fixed IOR. */ + vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint); + vec3 f90 = vec3(1.0); - vec3 V = cameraVec(worldPosition); + vec3 glass_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) : + F_brdf_single_scatter(f0, f90, split_sum); - /* Glossy_1 will always be evaluated. */ - float NV = dot(in_Glossy_1.N, V); - - vec3 base_color_tint = tint_from_color(base_color.rgb); + /* Avoid 3 glossy evaluation. Use the same closure for glass reflection. */ + reflection_data.color += glass_brdf * glass_reflection_weight; + } - float fresnel = (do_multiscatter != 0.0) ? - btdf_lut(NV, in_Glossy_1.roughness, in_Refraction_3.ior).y : - F_eta(in_Refraction_3.ior, NV); - - { - /* Glossy reflections. - * Separate Glass reflections and main specular reflections to match Cycles renderpasses. */ - out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id); - - vec2 split_sum = brdf_lut(NV, roughness); - - vec3 glossy_radiance_final = vec3(0.0); - if (transmission > 1e-5) { - /* Glass Reflection: Reuse radiance from Glossy1. */ - vec3 out_glass_refl_radiance = out_Glossy_1.radiance; - - /* Poor approximation since we baked the LUT using a fixed IOR. */ - vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint); - vec3 f90 = vec3(1); - - vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) : - F_brdf_single_scatter(f0, f90, split_sum); - - out_glass_refl_radiance *= brdf; - out_glass_refl_radiance = render_pass_glossy_mask(vec3(1), out_glass_refl_radiance); - out_glass_refl_radiance *= fresnel * transmission; - glossy_radiance_final += out_glass_refl_radiance; - } - if (specular_weight > 1e-5) { - vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint); - vec3 metallic_f0_color = base_color.rgb; - vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic); - /* Cycles does this blending using the microfacet fresnel factor. However, our fresnel - * is already baked inside the split sum LUT. We approximate using by modifying the - * changing the f90 color directly in a non linear fashion. */ - vec3 f90 = mix(f0, vec3(1), fast_sqrt(specular)); - - vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) : - F_brdf_single_scatter(f0, f90, split_sum); - - out_Glossy_1.radiance *= brdf; - out_Glossy_1.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_1.radiance); - out_Glossy_1.radiance *= specular_weight; - glossy_radiance_final += out_Glossy_1.radiance; - } - - closure_load_ssr_data( - glossy_radiance_final, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result); + ClosureReflection clearcoat_data; + clearcoat_data.weight = clearcoat_weight * weight; + clearcoat_data.N = CN; + clearcoat_data.roughness = clearcoat_roughness; + if (true) { + float NV = dot(clearcoat_data.N, V); + vec2 split_sum = brdf_lut(NV, clearcoat_data.roughness); + vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum); + clearcoat_data.color = brdf; } - if (diffuse_weight > 1e-5) { - /* Mask over all diffuse radiance. */ - out_Diffuse_0.radiance *= diffuse_weight; + /* Refraction. */ + ClosureRefraction refraction_data; + refraction_data.weight = glass_transmission_weight * weight; + float btdf = (do_multiscatter != 0.0) ? 1.0 : btdf_lut(NV, roughness, ior).x; - /* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */ - vec3 sheen_color = mix(vec3(1), base_color_tint, sheen_tint); - vec3 out_sheen_radiance = out_Diffuse_0.radiance * principled_sheen(NV); - out_sheen_radiance = render_pass_diffuse_mask(vec3(1), out_sheen_radiance); - out_sheen_radiance *= sheen * sheen_color; - result.radiance += out_sheen_radiance; + refraction_data.color = base_color.rgb * btdf; + refraction_data.N = N; + refraction_data.roughness = do_multiscatter != 0.0 ? roughness : + max(roughness, transmission_roughness); + refraction_data.ior = ior; - /* Diffuse / Subsurface. */ - float scale = avg(sss_scale) * subsurface; - closure_load_sss_data(scale, out_Diffuse_0.radiance, in_Diffuse_0.albedo, int(sss_id), result); + if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat != 0.0) { + /* Metallic & Clearcoat case. */ + result = closure_eval(reflection_data, clearcoat_data); } - - if (transmission > 1e-5) { - float btdf = (do_multiscatter != 0.0) ? - 1.0 : - btdf_lut(NV, in_Refraction_3.roughness, in_Refraction_3.ior).x; - /* TODO(@fclem): This could be going to a transmission render pass instead. */ - out_Refraction_3.radiance *= btdf; - out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance); - out_Refraction_3.radiance *= base_color.rgb; - /* Simulate 2nd transmission event. */ - out_Refraction_3.radiance *= (refractionDepth > 0.0) ? base_color.rgb : vec3(1); - out_Refraction_3.radiance *= (1.0 - fresnel) * transmission; - result.radiance += out_Refraction_3.radiance; + else if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) { + /* Metallic case. */ + result = closure_eval(reflection_data); } - - if (clearcoat > 1e-5) { - float NV = dot(in_Glossy_2.N, V); - vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness); - vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum); - - out_Glossy_2.radiance *= brdf * clearcoat * 0.25; - out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance); - result.radiance += out_Glossy_2.radiance; + else if (do_diffuse != 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) { + /* Dielectric case. */ + result = closure_eval(diffuse_data, reflection_data); } - - { - vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb); - out_emission_radiance *= emission_strength; - result.radiance += out_emission_radiance; + else if (do_diffuse == 0.0 && do_refraction != 0.0 && do_clearcoat == 0.0) { + /* Glass case. */ + result = closure_eval(reflection_data, refraction_data); } - - result.transmittance = vec3(1.0 - alpha); - result.radiance *= alpha; - result.ssr_data.rgb *= alpha; -# ifdef USE_SSS - result.sss_albedo *= alpha; -# endif + else { + /* Un-optimized case. */ + result = closure_eval(diffuse_data, reflection_data, clearcoat_data, refraction_data); + } + result = closure_add(result, closure_eval(emission_data)); + result = closure_add(result, closure_eval(transparency_data)); } - -#else -/* clang-format off */ -/* Stub principled because it is not compatible with volumetrics. */ -# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, cc, dd, ee, ff, result) (result = CLOSURE_DEFAULT) -/* clang-format on */ -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl index 8a42a131f43..871fa00b3d4 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl @@ -1,32 +1,15 @@ -#ifndef VOLUMETRICS -CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_refraction, Refraction) - -void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result) +void node_bsdf_refraction( + vec4 color, float roughness, float ior, vec3 N, float weight, out Closure result) { - CLOSURE_VARS_DECLARE_1(Refraction); - - in_Refraction_0.N = N; /* Normalized during eval. */ - in_Refraction_0.roughness = roughness; - in_Refraction_0.ior = ior; - - CLOSURE_EVAL_FUNCTION_1(node_bsdf_refraction, Refraction); + N = safe_normalize(N); - result = CLOSURE_DEFAULT; + ClosureRefraction refraction_data; + refraction_data.weight = weight; + refraction_data.color = color.rgb; + refraction_data.N = N; + refraction_data.roughness = roughness; + refraction_data.ior = ior; - out_Refraction_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_0.radiance); - out_Refraction_0.radiance *= color.rgb; - /* Simulate 2nd absorption event. */ - out_Refraction_0.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); - - result.radiance = out_Refraction_0.radiance; - - /* TODO(@fclem): Try to not use this. */ - result.ssr_normal = normal_encode(mat3(ViewMatrix) * in_Refraction_0.N, - viewCameraVec(viewPosition)); + result = closure_eval(refraction_data); } - -#else -/* Stub refraction because it is not compatible with volumetrics. */ -# define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl index fb64e424c6c..180e0fd1940 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl) + void separate_hsv(vec4 col, out float h, out float s, out float v) { vec4 hsv; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl index f0f2f79c60e..d791f067821 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl @@ -1,29 +1,6 @@ -#ifndef VOLUMETRICS - -CLOSURE_EVAL_FUNCTION_DECLARE_1(node_shader_to_rgba, Glossy) void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha) { - vec4 spec_accum = vec4(0.0); - if (ssrToggle && FLAG_TEST(cl.flag, CLOSURE_SSR_FLAG)) { - CLOSURE_VARS_DECLARE_1(Glossy); - - vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec(viewPosition)); - vec3 N = transform_direction(ViewMatrixInverse, vN); - - in_Glossy_0.N = N; /* Normalized during eval. */ - in_Glossy_0.roughness = cl.ssr_data.a; - - CLOSURE_EVAL_FUNCTION_1(node_shader_to_rgba, Glossy); - - spec_accum.rgb = out_Glossy_0.radiance; - } - - outalpha = saturate(1.0 - avg(cl.transmittance)); - outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0); - -# ifdef USE_SSS - outcol.rgb += cl.sss_irradiance.rgb * cl.sss_albedo; -# endif + outcol = closure_to_rgba(cl); + outalpha = outcol.a; } -#endif /* VOLUMETRICS */ diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl index 20b634aa801..c560dd01c4f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl @@ -1,6 +1,3 @@ -#ifndef VOLUMETRICS - -CLOSURE_EVAL_FUNCTION_DECLARE_1(node_subsurface_scattering, Diffuse) void node_subsurface_scattering(vec4 color, float scale, @@ -8,25 +5,18 @@ void node_subsurface_scattering(vec4 color, float ior, float anisotropy, vec3 N, - float sss_id, + float weight, + float do_sss, out Closure result) { - CLOSURE_VARS_DECLARE_1(Diffuse); - - in_Diffuse_0.N = N; /* Normalized during eval. */ - in_Diffuse_0.albedo = color.rgb; - - CLOSURE_EVAL_FUNCTION_1(node_subsurface_scattering, Diffuse); + N = safe_normalize(N); - result = CLOSURE_DEFAULT; + ClosureDiffuse diffuse_data; + diffuse_data.weight = weight; + diffuse_data.color = color.rgb; + diffuse_data.N = N; + diffuse_data.sss_radius = radius * scale; + diffuse_data.sss_id = uint(do_sss); - closure_load_sss_data(scale, out_Diffuse_0.radiance, color.rgb, int(sss_id), result); - - /* TODO(@fclem): Try to not use this. */ - closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result); + result = closure_eval(diffuse_data); } - -#else -/* Stub subsurface scattering because it is not compatible with volumetrics. */ -# define node_subsurface_scattering(a, b, c, d, e, f, g, h) (h = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl index ff2dbc7ead3..4e4bf759ec9 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl @@ -18,8 +18,8 @@ void node_tangentmap(vec4 attr_tangent, out vec3 tangent) tangent = normalize(attr_tangent.xyz); } -void node_tangent(vec3 N, vec3 orco, mat4 objmat, out vec3 T) +void node_tangent(vec3 orco, out vec3 T) { - T = (objmat * vec4(orco, 0.0)).xyz; - T = cross(N, normalize(cross(T, N))); + T = transform_direction(ModelMatrix, orco); + T = cross(g_data.N, normalize(cross(T, g_data.N))); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl index e252e5ba726..edc2fa32177 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl @@ -1,3 +1,6 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) + vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl index 434e07e7b86..89091316823 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl @@ -1,19 +1,5 @@ -void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec) -{ -#ifdef MESH_SHADER - worldvec = worldPosition; -#else - vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); - vec4 co_homogeneous = (ProjectionMatrixInverse * v); +#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) - vec3 co = co_homogeneous.xyz / co_homogeneous.w; -# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) - worldvec = mat3(ViewMatrixInverse) * co; -# else - worldvec = mat3(ModelMatrixInverse) * (mat3(ViewMatrixInverse) * co); -# endif -#endif -} void node_tex_environment_equirectangular(vec3 co, out vec3 uv) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl index 586385b7e86..1552a2facc3 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl @@ -1,3 +1,6 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl) + /* 1D Musgrave fBm * * H: fractal increment parameter diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl index 5745f11ede4..c90b2211dcf 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl @@ -1,3 +1,7 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl) + /* The following offset functions generate random offsets to be added to texture * coordinates to act as a seed since the noise functions don't have seed values. * A seed value is needed for generating distortion textures and color outputs. diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl index c8219848e29..dd12b602edf 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl @@ -1,3 +1,6 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) + /* * Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez. * diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl index 070f42a5e30..eed98232d0b 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl @@ -1,3 +1,7 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl) + float calc_wave(vec3 p, float distortion, float detail, diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl index b11d13a0413..030b58f0736 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) + /* White Noise */ void node_white_noise_1d(vec3 vector, float w, out float value, out vec4 color) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl index a8ef9687b0a..a3666164cf7 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl @@ -1,38 +1,5 @@ -vec3 mtex_2d_mapping(vec3 vec) -{ - return vec3(vec.xy * 0.5 + vec2(0.5), vec.z); -} - -void generated_from_orco(vec3 orco, out vec3 generated) -{ -#ifdef VOLUMETRICS -# ifdef MESH_SHADER - generated = volumeObjectLocalCoord; -# else - generated = worldPosition; -# endif -#else - generated = orco; -#endif -} -void generated_texco(vec3 I, vec3 attr_orco, out vec3 generated) -{ - vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); - vec4 co_homogeneous = (ProjectionMatrixInverse * v); - vec4 co = vec4(co_homogeneous.xyz / co_homogeneous.w, 0.0); - co.xyz = normalize(co.xyz); -#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) - generated = (ViewMatrixInverse * co).xyz; -#else - generated_from_orco(attr_orco, generated); -#endif -} - -void node_tex_coord(vec3 I, - vec3 wN, - mat4 obmatinv, - vec4 camerafac, +void node_tex_coord(mat4 obmatinv, vec3 attr_orco, vec3 attr_uv, out vec3 generated, @@ -44,49 +11,10 @@ void node_tex_coord(vec3 I, out vec3 reflection) { generated = attr_orco; - normal = normalize(normal_world_to_object(wN)); + normal = normal_world_to_object(g_data.N); uv = attr_uv; - object = (obmatinv * (ViewMatrixInverse * vec4(I, 1.0))).xyz; - camera = vec3(I.xy, -I.z); - vec4 projvec = ProjectionMatrix * vec4(I, 1.0); - window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0); - reflection = -reflect(cameraVec(worldPosition), normalize(wN)); -} - -void node_tex_coord_background(vec3 I, - vec3 N, - mat4 obmatinv, - vec4 camerafac, - vec3 attr_orco, - vec3 attr_uv, - out vec3 generated, - out vec3 normal, - out vec3 uv, - out vec3 object, - out vec3 camera, - out vec3 window, - out vec3 reflection) -{ - vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); - vec4 co_homogeneous = (ProjectionMatrixInverse * v); - - vec4 co = vec4(co_homogeneous.xyz / co_homogeneous.w, 0.0); - - co = normalize(co); - - vec3 coords = (ViewMatrixInverse * co).xyz; - - generated = coords; - normal = -coords; - uv = vec3(attr_uv.xy, 0.0); - object = (obmatinv * vec4(coords, 1.0)).xyz; - - camera = vec3(co.xy, -co.z); - window = vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0); - - reflection = -coords; + object = transform_point((obmatinv[3][3] == 0.0) ? ModelMatrixInverse : obmatinv, g_data.P); + camera = coordinate_camera(g_data.P); + window = coordinate_screen(g_data.P); + reflection = coordinate_reflect(g_data.P, g_data.N); } - -#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER)) -# define node_tex_coord node_tex_coord_background -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl index bbfc99ccc73..ae7d4fc5631 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl @@ -1,9 +1,15 @@ -#ifndef VOLUMETRICS -void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result) + +void node_bsdf_toon( + vec4 color, float size, float tsmooth, vec3 N, float weight, out Closure result) { - node_bsdf_diffuse(color, 0.0, N, result); + N = safe_normalize(N); + + /* Fallback to diffuse. */ + ClosureDiffuse diffuse_data; + diffuse_data.weight = weight; + diffuse_data.color = color.rgb; + diffuse_data.N = N; + diffuse_data.sss_id = 0u; + + result = closure_eval(diffuse_data); } -#else -/* Stub toon because it is not compatible with volumetrics. */ -# define node_bsdf_toon(a, b, c, d, e) (e = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl index 80bd3941b22..0cc162f42f5 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl @@ -1,21 +1,12 @@ -#ifndef VOLUMETRICS -CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_translucent, Translucent) - -void node_bsdf_translucent(vec4 color, vec3 N, out Closure result) +void node_bsdf_translucent(vec4 color, vec3 N, float weight, out Closure result) { - CLOSURE_VARS_DECLARE_1(Translucent); - - in_Translucent_0.N = -N; /* Normalized during eval. */ + N = safe_normalize(N); - CLOSURE_EVAL_FUNCTION_1(node_bsdf_translucent, Translucent); + ClosureTranslucent translucent_data; + translucent_data.weight = weight; + translucent_data.color = color.rgb; + translucent_data.N = -N; - result = CLOSURE_DEFAULT; - closure_load_ssr_data(vec3(0.0), 0.0, -in_Translucent_0.N, -1.0, result); - result.radiance = render_pass_diffuse_mask(color.rgb, out_Translucent_0.radiance * color.rgb); + result = closure_eval(translucent_data); } - -#else -/* Stub translucent because it is not compatible with volumetrics. */ -# define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl index 9040f62bd3f..c650f10b6e4 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl @@ -1,11 +1,10 @@ -#ifndef VOLUMETRICS -void node_bsdf_transparent(vec4 color, out Closure result) + +void node_bsdf_transparent(vec4 color, float weight, out Closure result) { - result = CLOSURE_DEFAULT; - result.radiance = vec3(0.0); - result.transmittance = abs(color.rgb); + ClosureTransparency transparency_data; + transparency_data.weight = weight; + transparency_data.transmittance = color.rgb; + transparency_data.holdout = 0.0; + + result = closure_eval(transparency_data); } -#else -/* Stub transparent because it is not compatible with volumetrics. */ -# define node_bsdf_transparent(a, b) (b = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl index 4b5ed172081..0ff074bc04f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl @@ -1,30 +1,22 @@ -void node_vector_displacement_tangent(vec4 vector, - float midlevel, - float scale, - vec4 tangent, - vec3 normal, - mat4 obmat, - mat4 viewmat, - out vec3 result) +void node_vector_displacement_tangent( + vec4 vector, float midlevel, float scale, vec4 T, out vec3 result) { - /* TODO(fclem): this is broken. revisit latter. */ - vec3 N_object = normalize(((vec4(normal, 0.0) * viewmat) * obmat).xyz); - vec3 T_object = normalize(((vec4(tangent.xyz, 0.0) * viewmat) * obmat).xyz); - vec3 B_object = tangent.w * normalize(cross(N_object, T_object)); + vec3 oN = normalize(normal_world_to_object(g_data.N)); + vec3 oT = normalize(normal_world_to_object(T.xyz)); + vec3 oB = T.w * normalize(cross(oN, oT)); - vec3 offset = (vector.xyz - vec3(midlevel)) * scale; - result = offset.x * T_object + offset.y * N_object + offset.z * B_object; - result = (obmat * vec4(result, 0.0)).xyz; + result = (vector.xyz - midlevel) * scale; + result = result.x * oT + result.y * oN + result.z * oB; + result = transform_point(ModelMatrix, result); } -void node_vector_displacement_object( - vec4 vector, float midlevel, float scale, mat4 obmat, out vec3 result) +void node_vector_displacement_object(vec4 vector, float midlevel, float scale, out vec3 result) { - result = (vector.xyz - vec3(midlevel)) * scale; - result = (obmat * vec4(result, 0.0)).xyz; + result = (vector.xyz - midlevel) * scale; + result = transform_point(ModelMatrix, result); } void node_vector_displacement_world(vec4 vector, float midlevel, float scale, out vec3 result) { - result = (vector.xyz - vec3(midlevel)) * scale; + result = (vector.xyz - midlevel) * scale; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl index 4ad5d4232de..8f6bf17f195 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) + void vector_math_add(vec3 a, vec3 b, vec3 c, float scale, out vec3 outVector, out float outValue) { outVector = a + b; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl index 41ad16cce0b..ff0fb1c0418 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) + vec3 rotate_around_axis(vec3 p, vec3 axis, float angle) { float costheta = cos(angle); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl index 989f18b881a..97726bfe66f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl @@ -1,9 +1,14 @@ -#ifndef VOLUMETRICS -void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result) + +void node_bsdf_velvet(vec4 color, float roughness, vec3 N, float weight, out Closure result) { - node_bsdf_diffuse(color, 0.0, N, result); + N = safe_normalize(N); + + /* Fallback to diffuse. */ + ClosureDiffuse diffuse_data; + diffuse_data.weight = weight; + diffuse_data.color = color.rgb; + diffuse_data.N = N; + diffuse_data.sss_id = 0u; + + result = closure_eval(diffuse_data); } -#else -/* Stub velvet because it is not compatible with volumetrics. */ -# define node_bsdf_velvet(a, b, c, d) (d = CLOSURE_DEFAULT) -#endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl index e6c0880cd07..8fd2e179187 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl @@ -1,8 +1,9 @@ -void node_volume_absorption(vec4 color, float density, out Closure result) + +void node_volume_absorption(vec4 color, float density, float weight, out Closure result) { -#ifdef VOLUMETRICS - result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0); -#else - result = CLOSURE_DEFAULT; -#endif + ClosureVolumeAbsorption volume_absorption_data; + volume_absorption_data.weight = weight; + volume_absorption_data.absorption = (1.0 - color.rgb) * density; + + result = closure_eval(volume_absorption_data); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl index e6d7b9d3721..464cf5227b4 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl @@ -4,14 +4,8 @@ uniform vec3 volumeColor = vec3(1.0); uniform vec2 volumeTemperature = vec2(0.0); /* Generic volume attribute. */ -void node_attribute_volume(sampler3D tex, mat4 transform, out vec3 outvec) +void node_attribute_volume(sampler3D tex, mat4 transform, vec3 cos, out vec3 outvec) { -#if defined(MESH_SHADER) && defined(VOLUMETRICS) - vec3 cos = volumeObjectLocalCoord; -#else - vec3 cos = vec3(0.0); -#endif - /* Optional per-grid transform. */ if (transform[3][3] != 0.0) { cos = (transform * vec4(cos, 1.0)).xyz; @@ -21,14 +15,8 @@ void node_attribute_volume(sampler3D tex, mat4 transform, out vec3 outvec) } /* Special color attribute for smoke. */ -void node_attribute_volume_color(sampler3D tex, mat4 transform, out vec3 outvec) +void node_attribute_volume_color(sampler3D tex, mat4 transform, vec3 cos, out vec3 outvec) { -#if defined(MESH_SHADER) && defined(VOLUMETRICS) - vec3 cos = volumeObjectLocalCoord; -#else - vec3 cos = vec3(0.0); -#endif - /* Optional per-grid transform. */ if (transform[3][3] != 0.0) { cos = (transform * vec4(cos, 1.0)).xyz; @@ -44,14 +32,8 @@ void node_attribute_volume_color(sampler3D tex, mat4 transform, out vec3 outvec) } /* Special temperature attribute for smoke. */ -void node_attribute_volume_temperature(sampler3D tex, mat4 transform, out float outf) +void node_attribute_volume_temperature(sampler3D tex, mat4 transform, vec3 cos, out float outf) { -#if defined(MESH_SHADER) && defined(VOLUMETRICS) - vec3 cos = volumeObjectLocalCoord; -#else - vec3 cos = vec3(0.0); -#endif - /* Optional per-grid transform. */ if (transform[3][3] != 0.0) { cos = (transform * vec4(cos, 1.0)).xyz; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl index 884d5415c51..1127c34b3ac 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_material_blackbody.glsl) + void node_volume_principled(vec4 color, float density, float anisotropy, @@ -7,6 +9,7 @@ void node_volume_principled(vec4 color, float blackbody_intensity, vec4 blackbody_tint, float temperature, + float weight, float density_attribute, vec4 color_attribute, float temperature_attribute, @@ -14,7 +17,6 @@ void node_volume_principled(vec4 color, float layer, out Closure result) { -#ifdef VOLUMETRICS vec3 absorption_coeff = vec3(0.0); vec3 scatter_coeff = vec3(0.0); vec3 emission_coeff = vec3(0.0); @@ -60,8 +62,18 @@ void node_volume_principled(vec4 color, } } - result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy); -#else - result = CLOSURE_DEFAULT; -#endif + ClosureVolumeScatter volume_scatter_data; + volume_scatter_data.weight = weight; + volume_scatter_data.scattering = scatter_coeff; + volume_scatter_data.anisotropy = anisotropy; + + ClosureVolumeAbsorption volume_absorption_data; + volume_absorption_data.weight = weight; + volume_absorption_data.absorption = absorption_coeff; + + ClosureEmission emission_data; + emission_data.weight = weight; + emission_data.emission = emission_coeff; + + result = closure_eval(volume_scatter_data, volume_absorption_data, emission_data); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl index 02c54658be5..f01ead3618f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl @@ -1,8 +1,11 @@ -void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result) + +void node_volume_scatter( + vec4 color, float density, float anisotropy, float weight, out Closure result) { -#ifdef VOLUMETRICS - result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy); -#else - result = CLOSURE_DEFAULT; -#endif + ClosureVolumeScatter volume_scatter_data; + volume_scatter_data.weight = weight; + volume_scatter_data.scattering = color.rgb * density; + volume_scatter_data.anisotropy = anisotropy; + + result = closure_eval(volume_scatter_data); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl index e2789e046e1..0c02dab3ae4 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl @@ -1,20 +1,21 @@ -#ifndef VOLUMETRICS -void node_wireframe(float size, vec2 barycentric, vec3 barycentric_dist, out float fac) + +void node_wireframe(float size, out float fac) { - vec3 barys = barycentric.xyy; - barys.z = 1.0 - barycentric.x - barycentric.y; + vec3 barys = g_data.barycentric_coords.xyy; + barys.z = 1.0 - barys.x - barys.y; size *= 0.5; - vec3 s = step(-size, -barys * barycentric_dist); + vec3 s = step(-size, -barys * g_data.barycentric_dists); fac = max(s.x, max(s.y, s.z)); } -void node_wireframe_screenspace(float size, vec2 barycentric, out float fac) +void node_wireframe_screenspace(float size, out float fac) { - vec3 barys = barycentric.xyy; - barys.z = 1.0 - barycentric.x - barycentric.y; + vec3 barys = g_data.barycentric_coords.xyy; + barys.z = 1.0 - barys.x - barys.y; +#ifdef GPU_FRAGMENT_SHADER size *= (1.0 / 3.0); vec3 dx = dFdx(barys); vec3 dy = dFdy(barys); @@ -23,9 +24,7 @@ void node_wireframe_screenspace(float size, vec2 barycentric, out float fac) vec3 s = step(-deltas * size, -barys); fac = max(s.x, max(s.y, s.z)); -} #else -/* Stub wireframe because it is not compatible with volumetrics. */ -# define node_wireframe(a, b, c, d) (d = 0.0) -# define node_wireframe_screenspace(a, b, c) (c = 0.0) + fac = 1.0; #endif +} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl index 40e46bc250c..5a0aeb2f932 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl @@ -1,25 +1,5 @@ -/* TODO: clean this `ifdef` mess. */ + void world_normals_get(out vec3 N) { -#ifndef VOLUMETRICS -# ifdef HAIR_SHADER - vec3 B = normalize(cross(worldNormal, hairTangent)); - float cos_theta; - if (hairThicknessRes == 1) { - vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); - /* Random cosine normal distribution on the hair surface. */ - cos_theta = rand.x * 2.0 - 1.0; - } - else { - /* Shade as a cylinder. */ - cos_theta = hairThickTime / hairThickness; - } - float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta)); - N = normalize(worldNormal * sin_theta + B * cos_theta); -# else - N = gl_FrontFacing ? worldNormal : -worldNormal; -# endif -#else - generated_from_orco(vec3(0.0), N); -#endif + N = g_data.N; } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 5f909ea325b..1b9192c75cf 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -318,22 +318,11 @@ typedef struct bNode { short preview_xsize, preview_ysize; /** Used at runtime when going through the tree. Initialize before use. */ short tmp_flag; - /** Used at runtime to tag derivatives branches. EEVEE only. */ - char branch_tag; + + char _pad0; /** Used at runtime when iterating over node branches. */ char iter_flag; - /** - * XXX: eevee only, id of screen space reflection layer, - * needs to be a float to feed GPU_uniform. - */ - float ssr_id; - /** - * XXX: eevee only, id of screen subsurface scatter layer, - * needs to be a float to feed GPU_uniform. - */ - float sss_id; - /** * Describes the desired interface of the node. This is run-time data only. * The actual interface of the node may deviate from the declaration temporarily. diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index f1c08f6a589..4996f12e27d 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -144,10 +144,7 @@ struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target); /** * This one needs to work on a local tree. */ -void ntreeGPUMaterialNodes(struct bNodeTree *localtree, - struct GPUMaterial *mat, - bool *has_surface_output, - bool *has_volume_output); +void ntreeGPUMaterialNodes(struct bNodeTree *localtree, struct GPUMaterial *mat); #ifdef __cplusplus } diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc index 03baebfd28b..42a31f39041 100644 --- a/source/blender/nodes/shader/node_shader_tree.cc +++ b/source/blender/nodes/shader/node_shader_tree.cc @@ -21,6 +21,7 @@ #include "BLI_listbase.h" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLI_vector.hh" #include "BLT_translation.h" @@ -47,11 +48,7 @@ #include "node_shader_util.hh" #include "node_util.h" -struct nTreeTags { - float ssr_id, sss_id; -}; - -static void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags); +using blender::Vector; static bool shader_tree_poll(const bContext *C, bNodeTreeType *UNUSED(treetype)) { @@ -250,6 +247,18 @@ static bNodeSocket *ntree_shader_node_find_output(bNode *node, const char *ident return ntree_shader_node_find_socket(&node->outputs, identifier); } +/* Find input socket at a specific position. */ +static bNodeSocket *ntree_shader_node_input_get(bNode *node, int n) +{ + return reinterpret_cast(BLI_findlink(&node->inputs, n)); +} + +/* Find output socket at a specific position. */ +static bNodeSocket *ntree_shader_node_output_get(bNode *node, int n) +{ + return reinterpret_cast(BLI_findlink(&node->outputs, n)); +} + /* Return true on success. */ static bool ntree_shader_expand_socket_default(bNodeTree *localtree, bNode *node, @@ -522,125 +531,21 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree) BKE_ntree_update_main_tree(G.main, localtree, nullptr); } -/* Check whether shader has a displacement. - * - * Will also return a node and its socket which is connected to a displacement - * output. Additionally, link which is attached to the displacement output is - * also returned. - */ -static bool ntree_shader_has_displacement(bNodeTree *ntree, - bNode *output_node, - bNode **r_node, - bNodeSocket **r_socket, - bNodeLink **r_link) -{ - if (output_node == nullptr) { - /* We can't have displacement without output node, apparently. */ - return false; - } - /* Make sure sockets links pointers are correct. */ - BKE_ntree_update_main_tree(G.main, ntree, nullptr); - bNodeSocket *displacement = ntree_shader_node_find_input(output_node, "Displacement"); - - if (displacement == nullptr) { - /* Non-cycles node is used as an output. */ - return false; - } - - if ((displacement->link != nullptr) && !(displacement->link->flag & NODE_LINK_MUTED)) { - *r_node = displacement->link->fromnode; - *r_socket = displacement->link->fromsock; - *r_link = displacement->link; - return true; - } - return false; -} - -static void ntree_shader_relink_node_normal(bNodeTree *ntree, - bNode *node, - bNode *node_from, - bNodeSocket *socket_from) -{ - /* TODO(sergey): Can we do something smarter here than just a name-based - * matching? - */ - LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - if (STREQ(sock->identifier, "Normal") && sock->link == nullptr) { - /* It's a normal input and nothing is connected to it. */ - nodeAddLink(ntree, node_from, socket_from, node, sock); - } - else if (sock->link) { - bNodeLink *link = sock->link; - if (ELEM(link->fromnode->type, SH_NODE_NEW_GEOMETRY, SH_NODE_TEX_COORD) && - STREQ(link->fromsock->identifier, "Normal")) { - /* Linked to a geometry node normal output. */ - nodeAddLink(ntree, node_from, socket_from, node, sock); - } - } - } -} - -/* Use specified node and socket as an input for unconnected normal sockets. */ -static void ntree_shader_link_builtin_normal(bNodeTree *ntree, - bNode *node_from, - bNodeSocket *socket_from) -{ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node == node_from) { - /* Don't connect node itself! */ - continue; - } - if (node->tmp_flag == -2) { - /* This node is used inside the displacement tree. Skip to avoid cycles. */ - continue; - } - ntree_shader_relink_node_normal(ntree, node, node_from, socket_from); - } -} - -static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bNodeLink *bump_link) -{ - /* Bypass bump nodes. This replicates cycles "implicit" behavior. */ - bNodeSocket *bump_normal_input = ntree_shader_node_find_input(bump_node, "Normal"); - bNode *fromnode; - bNodeSocket *fromsock; - /* Default to builtin normals if there is no link. */ - if (bump_normal_input->link) { - fromsock = bump_normal_input->link->fromsock; - fromnode = bump_normal_input->link->fromnode; - } - else { - fromnode = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY); - fromsock = ntree_shader_node_find_output(fromnode, "Normal"); - } - /* Bypass the bump node by creating a link between the previous and next node. */ - nodeAddLink(ntree, fromnode, fromsock, bump_link->tonode, bump_link->tosock); - nodeRemLink(ntree, bump_link); -} - -static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree) -{ - /* Bypass bump links inside copied nodes */ - LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { - bNode *node = link->fromnode; - /* If node is a copy. */ - if (node->tmp_flag == -2 && node->type == SH_NODE_BUMP) { - ntree_shader_bypass_bump_link(ntree, node, link); - } - } - BKE_ntree_update_main_tree(G.main, ntree, nullptr); -} +struct branchIterData { + bool (*node_filter)(const bNode *node); + int node_count; +}; static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata) { - int *node_count = (int *)userdata; - if (fromnode->tmp_flag == -1) { - fromnode->tmp_flag = *node_count; - (*node_count)++; + branchIterData *iter = (branchIterData *)userdata; + if (fromnode->tmp_flag == -1 && (iter->node_filter == nullptr || iter->node_filter(fromnode))) { + fromnode->tmp_flag = iter->node_count; + iter->node_count++; } - if (tonode->tmp_flag == -1) { - tonode->tmp_flag = *node_count; - (*node_count)++; + if (tonode->tmp_flag == -1 && (iter->node_filter == nullptr || iter->node_filter(tonode))) { + tonode->tmp_flag = iter->node_count; + iter->node_count++; } return true; } @@ -650,6 +555,7 @@ static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, voi * Returns input node copy. */ static bNode *ntree_shader_copy_branch(bNodeTree *ntree, bNode *start_node, + bool (*node_filter)(const bNode *node), void (*callback)(bNode *node, int user_data), int user_data) { @@ -659,10 +565,13 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree, } /* Count and tag all nodes inside the displacement branch of the tree. */ start_node->tmp_flag = 0; - int node_count = 1; - nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, 1); + branchIterData iter_data; + iter_data.node_filter = node_filter; + iter_data.node_count = 1; + nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &iter_data, 1); /* Make a full copy of the branch */ - bNode **nodes_copy = static_cast(MEM_mallocN(sizeof(bNode *) * node_count, __func__)); + bNode **nodes_copy = static_cast( + MEM_mallocN(sizeof(bNode *) * iter_data.node_count, __func__)); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->tmp_flag >= 0) { int id = node->tmp_flag; @@ -690,7 +599,7 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree, } /* Per node callback. */ if (callback) { - for (int i = 0; i < node_count; i++) { + for (int i = 0; i < iter_data.node_count; i++) { callback(nodes_copy[i], user_data); } } @@ -699,216 +608,441 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree, return start_node_copy; } -static void ntree_shader_copy_branch_displacement(bNodeTree *ntree, - bNode *displacement_node, - bNodeSocket *displacement_socket, - bNodeLink *displacement_link) +/* Generate emission node to convert regular data to closure sockets. + * Returns validity of the tree. + */ +static bool ntree_shader_implicit_closure_cast(bNodeTree *ntree) { - /* Replace displacement socket/node/link. */ - bNode *tonode = displacement_link->tonode; - bNodeSocket *tosock = displacement_link->tosock; - displacement_node = ntree_shader_copy_branch(ntree, displacement_node, nullptr, 0); - displacement_socket = ntree_shader_node_find_output(displacement_node, - displacement_socket->identifier); - nodeRemLink(ntree, displacement_link); - nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock); - - BKE_ntree_update_main_tree(G.main, ntree, nullptr); + bool modified = false; + LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { + if ((link->fromsock->type != SOCK_SHADER) && (link->tosock->type == SOCK_SHADER)) { + bNode *emission_node = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION); + bNodeSocket *in_sock = ntree_shader_node_find_input(emission_node, "Color"); + bNodeSocket *out_sock = ntree_shader_node_find_output(emission_node, "Emission"); + nodeAddLink(ntree, link->fromnode, link->fromsock, emission_node, in_sock); + nodeAddLink(ntree, emission_node, out_sock, link->tonode, link->tosock); + nodeRemLink(ntree, link); + modified = true; + } + else if ((link->fromsock->type == SOCK_SHADER) && (link->tosock->type != SOCK_SHADER)) { + /* Meh. Not directly visible to the user. But better than nothing. */ + fprintf(stderr, "Shader Nodetree Error: Invalid implicit socket conversion\n"); + BKE_ntree_update_main_tree(G.main, ntree, nullptr); + return false; + } + } + if (modified) { + BKE_ntree_update_main_tree(G.main, ntree, nullptr); + } + return true; } -/* Re-link displacement output to unconnected normal sockets via bump node. - * This way material with have proper displacement in the viewport. - */ -static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_node) -{ - bNode *displacement_node; - bNodeSocket *displacement_socket; - bNodeLink *displacement_link; - if (!ntree_shader_has_displacement( - ntree, output_node, &displacement_node, &displacement_socket, &displacement_link)) { - /* There is no displacement output connected, nothing to re-link. */ - return; - } - - /* Copy the whole displacement branch to avoid cyclic dependency - * and issue when bypassing bump nodes. */ - ntree_shader_copy_branch_displacement( - ntree, displacement_node, displacement_socket, displacement_link); - /* Bypass bump nodes inside the copied branch to mimic cycles behavior. */ - ntree_shader_bypass_tagged_bump_nodes(ntree); - - /* Displacement Node may have changed because of branch copy and bump bypass. */ - ntree_shader_has_displacement( - ntree, output_node, &displacement_node, &displacement_socket, &displacement_link); - - /* We have to disconnect displacement output socket, otherwise we'll have - * cycles in the Cycles material :) - */ - nodeRemLink(ntree, displacement_link); - - /* Convert displacement vector to bump height. */ - bNode *dot_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_VECTOR_MATH); - bNode *geo_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY); - bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal"); - bNodeSocket *dot_input1 = static_cast(dot_node->inputs.first); - bNodeSocket *dot_input2 = static_cast(dot_input1->next); - dot_node->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT; - - nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_input1); - nodeAddLink(ntree, geo_node, normal_socket, dot_node, dot_input2); - displacement_node = dot_node; - displacement_socket = ntree_shader_node_find_output(dot_node, "Value"); - - /* We can't connect displacement to normal directly, use bump node for that - * and hope that it gives good enough approximation. - */ - bNode *bump_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_BUMP); - bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height"); - bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal"); - BLI_assert(bump_input_socket != nullptr); - BLI_assert(bump_output_socket != nullptr); - /* Connect bump node to where displacement output was originally - * connected to. - */ - nodeAddLink(ntree, displacement_node, displacement_socket, bump_node, bump_input_socket); - - /* Tag as part of the new displacement tree. */ - dot_node->tmp_flag = -2; - geo_node->tmp_flag = -2; - bump_node->tmp_flag = -2; - - BKE_ntree_update_main_tree(G.main, ntree, nullptr); - - /* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */ - ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket); - /* We modified the tree, it needs to be updated now. */ - BKE_ntree_update_main_tree(G.main, ntree, nullptr); +/* Socket already has a link to it. Add weights together. */ +static void ntree_weight_tree_merge_weight(bNodeTree *ntree, + bNode *UNUSED(fromnode), + bNodeSocket *fromsock, + bNode **tonode, + bNodeSocket **tosock) +{ + bNode *addnode = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH); + addnode->custom1 = NODE_MATH_ADD; + addnode->tmp_flag = -2; /* Copy */ + bNodeSocket *addsock_out = ntree_shader_node_output_get(addnode, 0); + bNodeSocket *addsock_in0 = ntree_shader_node_input_get(addnode, 0); + bNodeSocket *addsock_in1 = ntree_shader_node_input_get(addnode, 1); + bNodeLink *oldlink = fromsock->link; + nodeAddLink(ntree, oldlink->fromnode, oldlink->fromsock, addnode, addsock_in0); + nodeAddLink(ntree, *tonode, *tosock, addnode, addsock_in1); + nodeRemLink(ntree, oldlink); + *tonode = addnode; + *tosock = addsock_out; } -static void node_tag_branch_as_derivative(bNode *node, int dx) +static bool ntree_weight_tree_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata) { - if (dx) { - node->branch_tag = 1; + int *node_count = (int *)userdata; + bool to_node_from_weight_tree = ELEM(tonode->type, + SH_NODE_ADD_SHADER, + SH_NODE_MIX_SHADER, + SH_NODE_OUTPUT_WORLD, + SH_NODE_OUTPUT_MATERIAL, + SH_NODE_SHADERTORGB); + if (tonode->tmp_flag == -1 && to_node_from_weight_tree) { + tonode->tmp_flag = *node_count; + *node_count += (tonode->type == SH_NODE_MIX_SHADER) ? 4 : 1; } - else { - node->branch_tag = 2; + if (fromnode->tmp_flag == -1 && ELEM(fromnode->type, SH_NODE_ADD_SHADER, SH_NODE_MIX_SHADER)) { + fromnode->tmp_flag = *node_count; + *node_count += (fromnode->type == SH_NODE_MIX_SHADER) ? 4 : 1; } + return to_node_from_weight_tree; } -static bool ntree_shader_bump_branches(bNode *fromnode, bNode *UNUSED(tonode), void *userdata) +/* Invert evaluation order of the weight tree (add & mix closure nodes) to feed the closure nodes + * with their respective weights. */ +static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node) { - bNodeTree *ntree = (bNodeTree *)userdata; + bNodeLink *displace_link = NULL; + bNodeSocket *displace_output = ntree_shader_node_find_input(output_node, "Displacement"); + if (displace_output && displace_output->link) { + /* Remove any displacement link to avoid tagging it later on. */ + displace_link = displace_output->link; + displace_output->link = NULL; + } + bNodeLink *thickness_link = NULL; + bNodeSocket *thickness_output = ntree_shader_node_find_input(output_node, "Thickness"); + if (thickness_output && thickness_output->link) { + /* Remove any thickness link to avoid tagging it later on. */ + thickness_link = thickness_output->link; + thickness_output->link = NULL; + } + /* Init tmp flag. */ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + node->tmp_flag = -1; + } + /* Tag nodes from the weight tree. Only tag output node and mix/add shader nodes. */ + output_node->tmp_flag = 0; + int node_count = 1; + nodeChainIterBackwards(ntree, output_node, ntree_weight_tree_tag_nodes, &node_count, 0); + /* Make a mirror copy of the weight tree. */ + bNode **nodes_copy = static_cast(MEM_mallocN(sizeof(bNode *) * node_count, __func__)); + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->tmp_flag >= 0) { + int id = node->tmp_flag; - if (fromnode->type == SH_NODE_BUMP) { - bNodeSocket *height_dx_sock, *height_dy_sock, *bump_socket, *bump_dx_socket, *bump_dy_socket; - bNode *bump = fromnode; - bump_socket = ntree_shader_node_find_input(bump, "Height"); - bump_dx_socket = ntree_shader_node_find_input(bump, "Height_dx"); - bump_dy_socket = ntree_shader_node_find_input(bump, "Height_dy"); - if (bump_dx_socket->link) { - /* Avoid reconnecting the same bump twice. */ + switch (node->type) { + case SH_NODE_SHADERTORGB: + case SH_NODE_OUTPUT_WORLD: + case SH_NODE_OUTPUT_MATERIAL: { + /* Start the tree with full weight. */ + nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_VALUE); + nodes_copy[id]->tmp_flag = -2; /* Copy */ + ((bNodeSocketValueFloat *)ntree_shader_node_output_get(nodes_copy[id], 0)->default_value) + ->value = 1.0f; + break; + } + case SH_NODE_ADD_SHADER: { + /* Simple passthrough node. Each original inputs will get the same weight. */ + /* TODO(fclem) Better use some kind of reroute node? */ + nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH); + nodes_copy[id]->custom1 = NODE_MATH_ADD; + nodes_copy[id]->tmp_flag = -2; /* Copy */ + ((bNodeSocketValueFloat *)ntree_shader_node_input_get(nodes_copy[id], 0)->default_value) + ->value = 0.0f; + break; + } + case SH_NODE_MIX_SHADER: { + /* We need multiple nodes to emulate the mix node in reverse. */ + bNode *fromnode, *tonode; + bNodeSocket *fromsock, *tosock; + int id_start = id; + /* output = (factor * input_weight) */ + nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH); + nodes_copy[id]->custom1 = NODE_MATH_MULTIPLY; + nodes_copy[id]->tmp_flag = -2; /* Copy */ + id++; + /* output = ((1.0 - factor) * input_weight) <=> (input_weight - factor * input_weight) */ + nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH); + nodes_copy[id]->custom1 = NODE_MATH_SUBTRACT; + nodes_copy[id]->tmp_flag = -2; /* Copy */ + id++; + /* Node sanitizes the input mix factor by clamping it. */ + nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH); + nodes_copy[id]->custom1 = NODE_MATH_ADD; + nodes_copy[id]->custom2 = SHD_MATH_CLAMP; + nodes_copy[id]->tmp_flag = -2; /* Copy */ + ((bNodeSocketValueFloat *)ntree_shader_node_input_get(nodes_copy[id], 0)->default_value) + ->value = 0.0f; + /* Copy default value if no link present. */ + bNodeSocket *fac_sock = ntree_shader_node_find_input(node, "Fac"); + if (!fac_sock->link) { + float default_value = ((bNodeSocketValueFloat *)fac_sock->default_value)->value; + bNodeSocket *dst_sock = ntree_shader_node_input_get(nodes_copy[id], 1); + ((bNodeSocketValueFloat *)dst_sock->default_value)->value = default_value; + } + id++; + /* Reroute the weight input to the 3 processing nodes. Simplify linking later-on. */ + /* TODO(fclem) Better use some kind of reroute node? */ + nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH); + nodes_copy[id]->custom1 = NODE_MATH_ADD; + nodes_copy[id]->tmp_flag = -2; /* Copy */ + ((bNodeSocketValueFloat *)ntree_shader_node_input_get(nodes_copy[id], 0)->default_value) + ->value = 0.0f; + id++; + /* Link between nodes for the substraction. */ + fromnode = nodes_copy[id_start]; + tonode = nodes_copy[id_start + 1]; + fromsock = ntree_shader_node_output_get(fromnode, 0); + tosock = ntree_shader_node_input_get(tonode, 1); + nodeAddLink(ntree, fromnode, fromsock, tonode, tosock); + /* Link mix input to first node. */ + fromnode = nodes_copy[id_start + 2]; + tonode = nodes_copy[id_start]; + fromsock = ntree_shader_node_output_get(fromnode, 0); + tosock = ntree_shader_node_input_get(tonode, 1); + nodeAddLink(ntree, fromnode, fromsock, tonode, tosock); + /* Link weight input to both multiply nodes. */ + fromnode = nodes_copy[id_start + 3]; + fromsock = ntree_shader_node_output_get(fromnode, 0); + tonode = nodes_copy[id_start]; + tosock = ntree_shader_node_input_get(tonode, 0); + nodeAddLink(ntree, fromnode, fromsock, tonode, tosock); + tonode = nodes_copy[id_start + 1]; + tosock = ntree_shader_node_input_get(tonode, 0); + nodeAddLink(ntree, fromnode, fromsock, tonode, tosock); + break; + } + default: + BLI_assert(0); + break; + } } - else if (bump_socket && bump_socket->link) { - bNodeLink *link = bump_socket->link; - bNode *height = link->fromnode; - bNode *height_dx = ntree_shader_copy_branch(ntree, height, node_tag_branch_as_derivative, 1); - bNode *height_dy = ntree_shader_copy_branch(ntree, height, node_tag_branch_as_derivative, 0); - height_dx_sock = ntree_shader_node_find_output(height_dx, link->fromsock->identifier); - height_dy_sock = ntree_shader_node_find_output(height_dy, link->fromsock->identifier); - nodeAddLink(ntree, height_dx, height_dx_sock, bump, bump_dx_socket); - nodeAddLink(ntree, height_dy, height_dy_sock, bump, bump_dy_socket); - /* We could end iter here, but other bump node could be plugged into other input sockets. */ + } + /* Recreate links between copied nodes. */ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->tmp_flag >= 0) { + /* Naming can be confusing here. We use original nodelink name for from/to prefix. + * The final link is in reversed order. */ + int socket_index; + LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->inputs, socket_index) { + bNodeSocket *tosock; + bNode *tonode; + + switch (node->type) { + case SH_NODE_SHADERTORGB: + case SH_NODE_OUTPUT_WORLD: + case SH_NODE_OUTPUT_MATERIAL: + case SH_NODE_ADD_SHADER: { + tonode = nodes_copy[node->tmp_flag]; + tosock = ntree_shader_node_output_get(tonode, 0); + break; + } + case SH_NODE_MIX_SHADER: { + if (socket_index == 0) { + /* Mix Factor. */ + tonode = nodes_copy[node->tmp_flag + 2]; + tosock = ntree_shader_node_input_get(tonode, 1); + } + else if (socket_index == 1) { + /* Shader 1. */ + tonode = nodes_copy[node->tmp_flag + 1]; + tosock = ntree_shader_node_output_get(tonode, 0); + } + else { + /* Shader 2. */ + tonode = nodes_copy[node->tmp_flag]; + tosock = ntree_shader_node_output_get(tonode, 0); + } + break; + } + default: + BLI_assert(0); + break; + } + + if (sock->link) { + bNodeSocket *fromsock; + bNode *fromnode = sock->link->fromnode; + + switch (fromnode->type) { + case SH_NODE_ADD_SHADER: { + fromnode = nodes_copy[fromnode->tmp_flag]; + fromsock = ntree_shader_node_input_get(fromnode, 1); + if (fromsock->link) { + ntree_weight_tree_merge_weight(ntree, fromnode, fromsock, &tonode, &tosock); + } + break; + } + case SH_NODE_MIX_SHADER: { + fromnode = nodes_copy[fromnode->tmp_flag + 3]; + fromsock = ntree_shader_node_input_get(fromnode, 1); + if (fromsock->link) { + ntree_weight_tree_merge_weight(ntree, fromnode, fromsock, &tonode, &tosock); + } + break; + } + case SH_NODE_BACKGROUND: + case SH_NODE_BSDF_ANISOTROPIC: + case SH_NODE_BSDF_DIFFUSE: + case SH_NODE_BSDF_GLASS: + case SH_NODE_BSDF_GLOSSY: + case SH_NODE_BSDF_HAIR_PRINCIPLED: + case SH_NODE_BSDF_HAIR: + case SH_NODE_BSDF_PRINCIPLED: + case SH_NODE_BSDF_REFRACTION: + case SH_NODE_BSDF_TOON: + case SH_NODE_BSDF_TRANSLUCENT: + case SH_NODE_BSDF_TRANSPARENT: + case SH_NODE_BSDF_VELVET: + case SH_NODE_EEVEE_SPECULAR: + case SH_NODE_EMISSION: + case SH_NODE_HOLDOUT: + case SH_NODE_SUBSURFACE_SCATTERING: + case SH_NODE_VOLUME_ABSORPTION: + case SH_NODE_VOLUME_PRINCIPLED: + case SH_NODE_VOLUME_SCATTER: + fromsock = ntree_shader_node_find_input(fromnode, "Weight"); + if (fromsock->link) { + ntree_weight_tree_merge_weight(ntree, fromnode, fromsock, &tonode, &tosock); + } + break; + default: + fromsock = sock->link->fromsock; + break; + } + + /* Manually add the link to the socket to avoid calling + * BKE_ntree_update_main_tree(G.main, oop, nullptr. */ + fromsock->link = nodeAddLink(ntree, fromnode, fromsock, tonode, tosock); + BLI_assert(fromsock->link); + } + } } } - return true; + /* Restore displacement & thickness link. */ + if (displace_link) { + nodeAddLink( + ntree, displace_link->fromnode, displace_link->fromsock, output_node, displace_output); + } + if (thickness_link) { + nodeAddLink( + ntree, thickness_link->fromnode, thickness_link->fromsock, output_node, thickness_output); + } + BKE_ntree_update_main_tree(G.main, ntree, nullptr); + + MEM_freeN(nodes_copy); } -static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata) +static bool closure_node_filter(const bNode *node) { - switch (fromnode->type) { + switch (node->type) { + case SH_NODE_ADD_SHADER: + case SH_NODE_MIX_SHADER: + case SH_NODE_BACKGROUND: case SH_NODE_BSDF_ANISOTROPIC: - case SH_NODE_EEVEE_SPECULAR: - case SH_NODE_BSDF_GLOSSY: + case SH_NODE_BSDF_DIFFUSE: case SH_NODE_BSDF_GLASS: - fromnode->ssr_id = ((nTreeTags *)userdata)->ssr_id; - ((nTreeTags *)userdata)->ssr_id += 1; - break; - case SH_NODE_SUBSURFACE_SCATTERING: - fromnode->sss_id = ((nTreeTags *)userdata)->sss_id; - ((nTreeTags *)userdata)->sss_id += 1; - break; + case SH_NODE_BSDF_GLOSSY: + case SH_NODE_BSDF_HAIR_PRINCIPLED: + case SH_NODE_BSDF_HAIR: case SH_NODE_BSDF_PRINCIPLED: - fromnode->ssr_id = ((nTreeTags *)userdata)->ssr_id; - fromnode->sss_id = ((nTreeTags *)userdata)->sss_id; - ((nTreeTags *)userdata)->sss_id += 1; - ((nTreeTags *)userdata)->ssr_id += 1; - break; + case SH_NODE_BSDF_REFRACTION: + case SH_NODE_BSDF_TOON: + case SH_NODE_BSDF_TRANSLUCENT: + case SH_NODE_BSDF_TRANSPARENT: + case SH_NODE_BSDF_VELVET: + case SH_NODE_EEVEE_SPECULAR: + case SH_NODE_EMISSION: + case SH_NODE_HOLDOUT: + case SH_NODE_SUBSURFACE_SCATTERING: + case SH_NODE_VOLUME_ABSORPTION: + case SH_NODE_VOLUME_PRINCIPLED: + case SH_NODE_VOLUME_SCATTER: + return true; default: - /* We could return false here but since we - * allow the use of Closure as RGBA, we can have - * BSDF nodes linked to other BSDF nodes. */ - break; + return false; } +} +static bool shader_to_rgba_node_gather(bNode *UNUSED(fromnode), bNode *tonode, void *userdata) +{ + Vector &shader_to_rgba_nodes = *(Vector *)userdata; + if (tonode->tmp_flag == -1 && tonode->type == SH_NODE_SHADERTORGB) { + tonode->tmp_flag = 0; + shader_to_rgba_nodes.append(tonode); + } return true; } -/* EEVEE: Scan the ntree to set the Screen Space Reflection - * layer id of every specular node AND the Subsurface Scattering id of every SSS node. - */ -void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags) +/* Shader to rgba needs their associated closure duplicated and the weight tree generated for. */ +static void ntree_shader_shader_to_rgba_branch(bNodeTree *ntree, bNode *output_node) { - if (output_node == nullptr) { - return; + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + node->tmp_flag = -1; } - /* Make sure sockets links pointers are correct. */ - BKE_ntree_update_main_tree(G.main, ntree, nullptr); + /* First gather the shader_to_rgba nodes linked to the ouput. This is separate to avoid + * conflicting usage of the node->tmp_flag. */ + Vector shader_to_rgba_nodes; + nodeChainIterBackwards(ntree, output_node, shader_to_rgba_node_gather, &shader_to_rgba_nodes, 0); + + for (bNode *shader_to_rgba : shader_to_rgba_nodes) { + bNodeSocket *closure_input = ntree_shader_node_input_get(shader_to_rgba, 0); + if (closure_input->link == nullptr) { + continue; + } + bNode *start_node = closure_input->link->fromnode; + bNode *start_node_copy = ntree_shader_copy_branch( + ntree, start_node, closure_node_filter, nullptr, 0); + /* Replace node copy link. This assumes that every node possibly connected to the closure input + * has only one ouput. */ + bNodeSocket *closure_output = ntree_shader_node_output_get(start_node_copy, 0); + nodeRemLink(ntree, closure_input->link); + nodeAddLink(ntree, start_node_copy, closure_output, shader_to_rgba, closure_input); + BKE_ntree_update_main_tree(G.main, ntree, nullptr); + + ntree_shader_weight_tree_invert(ntree, shader_to_rgba); + } +} - nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0); +static bool ntree_branch_node_tag(bNode *fromnode, bNode *tonode, void *UNUSED(userdata)) +{ + fromnode->tmp_flag = 1; + tonode->tmp_flag = 1; + return true; } -void ntreeGPUMaterialNodes(bNodeTree *localtree, - GPUMaterial *mat, - bool *has_surface_output, - bool *has_volume_output) +/* Avoid adding more node execution when multiple outputs are present. */ +/* NOTE(@fclem): This is also a workaround for the old EEVEE SSS implementation where only the + * first executed SSS node gets a SSS profile. */ +static void ntree_shader_pruned_unused(bNodeTree *ntree, bNode *output_node) { - bNodeTreeExec *exec; + bool changed = false; - bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + node->tmp_flag = 0; + } - ntree_shader_groups_remove_muted_links(localtree); - ntree_shader_groups_expand_inputs(localtree); + /* Avoid deleting the output node if it is the only node in the tree. */ + output_node->tmp_flag = 1; - ntree_shader_groups_flatten(localtree); + nodeChainIterBackwards(ntree, output_node, ntree_branch_node_tag, nullptr, 0); - if (output == nullptr) { - /* Search again, now including flattened nodes. */ - output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == SH_NODE_OUTPUT_AOV) { + nodeChainIterBackwards(ntree, node, ntree_branch_node_tag, nullptr, 0); + } } - /* Perform all needed modifications on the tree in order to support - * displacement/bump mapping. - */ - ntree_shader_relink_displacement(localtree, output); - - /* Duplicate bump height branches for manual derivatives. - */ - nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree, 0); - LISTBASE_FOREACH (bNode *, node, &localtree->nodes) { - if (node->type == SH_NODE_OUTPUT_AOV) { - nodeChainIterBackwards(localtree, node, ntree_shader_bump_branches, localtree, 0); - nTreeTags tags = {}; - tags.ssr_id = 1.0; - tags.sss_id = 1.0; - ntree_shader_tag_nodes(localtree, node, &tags); + LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) { + if (node->tmp_flag == 0) { + ntreeFreeLocalNode(ntree, node); + changed = true; } } - /* TODO(fclem): consider moving this to the gpu shader tree evaluation. */ - nTreeTags tags = {}; - tags.ssr_id = 1.0; - tags.sss_id = 1.0; - ntree_shader_tag_nodes(localtree, output, &tags); + if (changed) { + BKE_ntree_update_main_tree(G.main, ntree, nullptr); + } +} + +void ntreeGPUMaterialNodes(bNodeTree *localtree, GPUMaterial *mat) +{ + bNodeTreeExec *exec; + + ntree_shader_groups_remove_muted_links(localtree); + ntree_shader_groups_expand_inputs(localtree); + ntree_shader_groups_flatten(localtree); + + bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); + + /* Tree is valid if it contains no undefined implicit socket type cast. */ + bool valid_tree = ntree_shader_implicit_closure_cast(localtree); + + if (valid_tree && output != NULL) { + ntree_shader_pruned_unused(localtree, output); + ntree_shader_shader_to_rgba_branch(localtree, output); + ntree_shader_weight_tree_invert(localtree, output); + } exec = ntreeShaderBeginExecTree(localtree); ntreeExecGPUNodes(exec, mat, output); @@ -918,23 +1052,6 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, } } ntreeShaderEndExecTree(exec); - - /* EEVEE: Find which material domain was used (volume, surface ...). */ - *has_surface_output = false; - *has_volume_output = false; - - if (output != nullptr) { - bNodeSocket *surface_sock = ntree_shader_node_find_input(output, "Surface"); - bNodeSocket *volume_sock = ntree_shader_node_find_input(output, "Volume"); - - if (surface_sock != nullptr) { - *has_surface_output = (nodeCountSocketLinks(localtree, surface_sock) > 0); - } - - if (volume_sock != nullptr) { - *has_volume_output = (nodeCountSocketLinks(localtree, volume_sock) > 0); - } - } } bNodeTreeExec *ntreeShaderBeginExecTree_internal(bNodeExecContext *context, diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc index 728e2760f9a..c47b69e6b69 100644 --- a/source/blender/nodes/shader/node_shader_util.cc +++ b/source/blender/nodes/shader/node_shader_util.cc @@ -284,26 +284,15 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node } } -void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link) +void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *UNUSED(node), GPUNodeLink **link) { - if (node->branch_tag == 1) { - /* Add one time the value for derivative to the input vector. */ - GPU_link(mat, "dfdx_v3", *link, link); - } - else if (node->branch_tag == 2) { - /* Add one time the value for derivative to the input vector. */ - GPU_link(mat, "dfdy_v3", *link, link); - } - else { - /* nothing to do, reference center value. */ - } + GPU_link(mat, "differentiate_texco", *link, link); } void node_shader_gpu_default_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link) { if (!*link) { *link = GPU_attribute(mat, CD_ORCO, ""); - GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), *link, link); node_shader_gpu_bump_tex_coord(mat, node, link); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc index a24b4379e69..1e8df2e985d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc +++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc @@ -36,7 +36,7 @@ static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat, GPU_link(mat, "world_normals_get", &in[2].link); } - GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE); + GPU_material_flag_set(mat, GPU_MATFLAG_AO); float inverted = (node->custom2 & SHD_AO_INSIDE) ? 1.0f : 0.0f; float f_samples = divide_ceil_u(node->custom1, 4); diff --git a/source/blender/nodes/shader/nodes/node_shader_background.cc b/source/blender/nodes/shader/nodes/node_shader_background.cc index f5d3b6811f1..ea5c1f541ea 100644 --- a/source/blender/nodes/shader/nodes/node_shader_background.cc +++ b/source/blender/nodes/shader/nodes/node_shader_background.cc @@ -9,6 +9,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.add_input(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); b.add_input(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("Background")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.cc b/source/blender/nodes/shader/nodes/node_shader_bevel.cc index 8bce38baf73..4ae60af9974 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bevel.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bevel.cc @@ -32,11 +32,7 @@ static int gpu_shader_bevel(GPUMaterial *mat, GPUNodeStack *out) { if (!in[1].link) { - GPU_link(mat, - "direction_transform_m4v3", - GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - &in[1].link); + GPU_link(mat, "world_normals_get", &in[1].link); } return GPU_stack_link(mat, node, "node_bevel", in, out); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc index 13b4a034a51..761a833f377 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc @@ -24,6 +24,7 @@ static void node_declare(NodeDeclarationBuilder &b) .subtype(PROP_FACTOR); b.add_input(N_("Normal")).hide_value(); b.add_input(N_("Tangent")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } @@ -51,13 +52,8 @@ static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; - return GPU_stack_link(mat, - node, - "node_bsdf_anisotropic", - in, - out, - GPU_constant(&use_multi_scatter), - GPU_constant(&node->ssr_id)); + return GPU_stack_link( + mat, node, "node_bsdf_anisotropic", in, out, GPU_constant(&use_multi_scatter)); } } // namespace blender::nodes::node_shader_bsdf_anisotropic_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc index 3f025b2ba39..5975e04450e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc @@ -14,6 +14,7 @@ static void node_declare(NodeDeclarationBuilder &b) .max(1.0f) .subtype(PROP_FACTOR); b.add_input(N_("Normal")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc index a1e5b705438..95869f13b7e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc @@ -15,6 +15,7 @@ static void node_declare(NodeDeclarationBuilder &b) .subtype(PROP_FACTOR); b.add_input(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f); b.add_input(N_("Normal")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } @@ -37,17 +38,11 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat, GPU_link(mat, "set_value_zero", &in[1].link); } - GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT)); + GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT); float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; - return GPU_stack_link(mat, - node, - "node_bsdf_glass", - in, - out, - GPU_constant(&use_multi_scatter), - GPU_constant(&node->ssr_id)); + return GPU_stack_link(mat, node, "node_bsdf_glass", in, out, GPU_constant(&use_multi_scatter)); } } // namespace blender::nodes::node_shader_bsdf_glass_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc index 9f0e172a5fe..07062a9730e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc @@ -14,6 +14,7 @@ static void node_declare(NodeDeclarationBuilder &b) .max(1.0f) .subtype(PROP_FACTOR); b.add_input(N_("Normal")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } @@ -40,13 +41,7 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; - return GPU_stack_link(mat, - node, - "node_bsdf_glossy", - in, - out, - GPU_constant(&use_multi_scatter), - GPU_constant(&node->ssr_id)); + return GPU_stack_link(mat, node, "node_bsdf_glossy", in, out, GPU_constant(&use_multi_scatter)); } } // namespace blender::nodes::node_shader_bsdf_glossy_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc index ef87f380bb9..1a1ba13e886 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc @@ -27,6 +27,7 @@ static void node_declare(NodeDeclarationBuilder &b) .max(1.0f) .subtype(PROP_FACTOR); b.add_input(N_("Tangent")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc index edae03bbd31..6495dcfffba 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc @@ -60,6 +60,7 @@ static void node_declare(NodeDeclarationBuilder &b) .max(1.0f) .subtype(PROP_FACTOR); b.add_input(N_("Random")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } @@ -108,6 +109,15 @@ static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node) } } +static int node_shader_gpu_hair_principled(GPUMaterial *mat, + bNode *node, + bNodeExecData *UNUSED(execdata), + GPUNodeStack *in, + GPUNodeStack *out) +{ + return GPU_stack_link(mat, node, "node_bsdf_hair_principled", in, out); +} + } // namespace blender::nodes::node_shader_bsdf_hair_principled_cc /* node type definition */ @@ -124,6 +134,7 @@ void register_node_type_sh_bsdf_hair_principled() node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, file_ns::node_shader_init_hair_principled); node_type_update(&ntype, file_ns::node_shader_update_hair_principled); + node_type_gpu(&ntype, file_ns::node_shader_gpu_hair_principled); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index ba98a797f2a..a63c7aede04 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -103,6 +103,7 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input(N_("Normal")).hide_value(); b.add_input(N_("Clearcoat Normal")).hide_value(); b.add_input(N_("Tangent")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } @@ -128,8 +129,6 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - GPUNodeLink *sss_scale; - /* Normals */ if (!in[22].link) { GPU_link(mat, "world_normals_get", &in[22].link); @@ -145,36 +144,17 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, if (!in[24].link) { GPUNodeLink *orco = GPU_attribute(CD_ORCO, ""); GPU_link(mat, "tangent_orco_z", orco, &in[24].link); - GPU_link(mat, - "node_tangent", - GPU_builtin(GPU_WORLD_NORMAL), - in[24].link, - GPU_builtin(GPU_OBJECT_MATRIX), - &in[24].link); + GPU_link(mat, "node_tangent", in[24].link, &in[24].link); } #endif bool use_diffuse = socket_not_one(6) && socket_not_one(17); - bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0; + bool use_subsurf = socket_not_zero(1) && use_diffuse; bool use_refract = socket_not_one(6) && socket_not_zero(17); + bool use_transparency = socket_not_one(21); bool use_clear = socket_not_zero(14); - /* SSS Profile */ - if (use_subsurf) { - bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2); - bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value; - /* For some reason it seems that the socket value is in ARGB format. */ - GPU_material_sss_profile_create(mat, &socket_data->value[1]); - } - - if (in[2].link) { - sss_scale = in[2].link; - } - else { - GPU_link(mat, "set_rgb_one", &sss_scale); - } - - uint flag = GPU_MATFLAG_GLOSSY; + eGPUMaterialFlag flag = GPU_MATFLAG_GLOSSY; if (use_diffuse) { flag |= GPU_MATFLAG_DIFFUSE; } @@ -182,28 +162,37 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, flag |= GPU_MATFLAG_REFRACT; } if (use_subsurf) { - flag |= GPU_MATFLAG_SSS; + flag |= GPU_MATFLAG_SUBSURFACE; + } + if (use_transparency) { + flag |= GPU_MATFLAG_TRANSPARENT; + } + + if (use_subsurf) { + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2); + bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value; + /* For some reason it seems that the socket value is in ARGB format. */ + use_subsurf = GPU_material_sss_profile_create(mat, &socket_data->value[1]); } - float f_use_diffuse = use_diffuse ? 1.0f : 0.0f; - float f_use_clearcoat = use_clear ? 1.0f : 0.0f; - float f_use_refraction = use_refract ? 1.0f : 0.0f; float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; + float use_sss = (use_subsurf) ? 1.0f : 0.0f; + float use_diffuse_f = (use_diffuse) ? 1.0f : 0.0f; + float use_clear_f = (use_clear) ? 1.0f : 0.0f; + float use_refract_f = (use_refract) ? 1.0f : 0.0f; - GPU_material_flag_set(mat, (eGPUMatFlag)flag); + GPU_material_flag_set(mat, flag); return GPU_stack_link(mat, node, "node_bsdf_principled", in, out, - GPU_constant(&f_use_diffuse), - GPU_constant(&f_use_clearcoat), - GPU_constant(&f_use_refraction), + GPU_constant(&use_diffuse_f), + GPU_constant(&use_clear_f), + GPU_constant(&use_refract_f), GPU_constant(&use_multi_scatter), - GPU_constant(&node->ssr_id), - GPU_constant(&node->sss_id), - sss_scale); + GPU_uniform(&use_sss)); } static void node_shader_update_principled(bNodeTree *ntree, bNode *node) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc index 73f58477b67..e814eb223e5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc @@ -15,6 +15,7 @@ static void node_declare(NodeDeclarationBuilder &b) .subtype(PROP_FACTOR); b.add_input(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f); b.add_input(N_("Normal")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc index 9cb7c4c3bbb..c1c092e89c7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc @@ -22,6 +22,7 @@ static void node_declare(NodeDeclarationBuilder &b) .max(1.0f) .subtype(PROP_FACTOR); b.add_input(N_("Normal")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc index 19e61d8140d..fd0dd9f93de 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc @@ -9,6 +9,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.add_input(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); b.add_input(N_("Normal")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc index 57fd7e3ef3b..291b3fdb2be 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc @@ -8,6 +8,7 @@ namespace blender::nodes::node_shader_bsdf_transparent_cc { static void node_declare(NodeDeclarationBuilder &b) { b.add_input(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } @@ -17,6 +18,9 @@ static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { + if (in[0].link || !is_zero_v3(in[0].vec)) { + GPU_material_flag_set(mat, GPU_MATFLAG_TRANSPARENT); + } return GPU_stack_link(mat, node, "node_bsdf_transparent", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc index 75bdb5b6f54..c86d70aecbf 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc @@ -14,6 +14,7 @@ static void node_declare(NodeDeclarationBuilder &b) .max(1.0f) .subtype(PROP_FACTOR); b.add_input(N_("Normal")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.cc b/source/blender/nodes/shader/nodes/node_shader_bump.cc index 5dd27e64ce3..ad2c56d96b5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bump.cc @@ -27,8 +27,6 @@ static void node_declare(NodeDeclarationBuilder &b) .min(-1000.0f) .max(1000.0f) .hide_value(); - b.add_input(N_("Height_dx")).default_value(1.0f).unavailable(); - b.add_input(N_("Height_dy")).default_value(1.0f).unavailable(); b.add_input(N_("Normal")).min(-1.0f).max(1.0f).hide_value(); b.add_output(N_("Normal")); } @@ -46,23 +44,26 @@ static int gpu_shader_bump(GPUMaterial *mat, { /* If there is no Height input, the node becomes a no-op. */ if (!in[2].link) { - if (!in[5].link) { + if (!in[3].link) { return GPU_link(mat, "world_normals_get", &out[0].link); } else { /* Actually running the bump code would normalize, but Cycles handles it as total no-op. */ - return GPU_link(mat, "vector_copy", in[5].link, &out[0].link); + return GPU_link(mat, "vector_copy", in[3].link, &out[0].link); } } - if (!in[5].link) { - GPU_link(mat, "world_normals_get", &in[5].link); + if (!in[3].link) { + GPU_link(mat, "world_normals_get", &in[3].link); } + const char *height_function = GPU_material_split_sub_function(mat, GPU_FLOAT, &in[2].link); + + GPUNodeLink *dheight = GPU_differentiate_float_function(height_function); + float invert = (node->custom1) ? -1.0 : 1.0; - return GPU_stack_link( - mat, node, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_constant(&invert)); + return GPU_stack_link(mat, node, "node_bump", in, out, dheight, GPU_constant(&invert)); } } // namespace blender::nodes::node_shader_bump_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.cc b/source/blender/nodes/shader/nodes/node_shader_camera.cc index 9d2858f56f7..99c82582456 100644 --- a/source/blender/nodes/shader/nodes/node_shader_camera.cc +++ b/source/blender/nodes/shader/nodes/node_shader_camera.cc @@ -22,11 +22,7 @@ static int gpu_shader_camera(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - GPUNodeLink *viewvec; - - viewvec = GPU_builtin(GPU_VIEW_POSITION); - GPU_link(mat, "invert_z", viewvec, &viewvec); - return GPU_stack_link(mat, node, "camera", in, out, viewvec); + return GPU_stack_link(mat, node, "camera", in, out); } } // namespace blender::nodes::node_shader_camera_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.cc b/source/blender/nodes/shader/nodes/node_shader_displacement.cc index 88d1fac13a4..6591396adda 100644 --- a/source/blender/nodes/shader/nodes/node_shader_displacement.cc +++ b/source/blender/nodes/shader/nodes/node_shader_displacement.cc @@ -33,16 +33,11 @@ static int gpu_shader_displacement(GPUMaterial *mat, GPUNodeStack *out) { if (!in[3].link) { - GPU_link(mat, - "direction_transform_m4v3", - GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - &in[3].link); + GPU_link(mat, "world_normals_get", &in[3].link); } if (node->custom1 == SHD_SPACE_OBJECT) { - return GPU_stack_link( - mat, node, "node_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX)); + return GPU_stack_link(mat, node, "node_displacement_object", in, out); } return GPU_stack_link(mat, node, "node_displacement_world", in, out); diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc index c4aed523f61..d68b0c0c37c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc +++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc @@ -33,9 +33,12 @@ static void node_declare(NodeDeclarationBuilder &b) .subtype(PROP_FACTOR); b.add_input(N_("Clear Coat Normal")).hide_value(); b.add_input(N_("Ambient Occlusion")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSDF")); } +#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f)) + static int node_shader_gpu_eevee_specular(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), @@ -59,9 +62,11 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat, GPU_link(mat, "set_value", GPU_constant(&one), &in[9].link); } - GPU_material_flag_set(mat, static_cast(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY)); + GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY); + + float use_clear = (socket_not_zero(6)) ? 1.0f : 0.0f; - return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_constant(&node->ssr_id)); + return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_constant(&use_clear)); } } // namespace blender::nodes::node_shader_eevee_specular_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.cc b/source/blender/nodes/shader/nodes/node_shader_emission.cc index d4d88857cd2..be98f096ce5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_emission.cc +++ b/source/blender/nodes/shader/nodes/node_shader_emission.cc @@ -9,6 +9,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.add_input(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); b.add_input(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("Emission")); } @@ -18,7 +19,8 @@ static int node_shader_gpu_emission(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - return GPU_stack_link(mat, node, "node_emission", in, out, GPU_builtin(GPU_VIEW_NORMAL)); + GPU_material_flag_set(mat, GPU_MATFLAG_EMISSION); + return GPU_stack_link(mat, node, "node_emission", in, out); } } // namespace blender::nodes::node_shader_emission_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.cc b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc index 47b2c6b97d4..7b771d7dafd 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.cc +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc @@ -19,14 +19,10 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, GPUNodeStack *out) { if (!in[1].link) { - in[1].link = GPU_builtin(GPU_VIEW_NORMAL); - } - else { - GPU_link( - mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link); + GPU_link(mat, "world_normals_get", &in[1].link); } - return GPU_stack_link(mat, node, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION)); + return GPU_stack_link(mat, node, "node_fresnel", in, out); } } // namespace blender::nodes::node_shader_fresnel_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.cc b/source/blender/nodes/shader/nodes/node_shader_geometry.cc index 5bd984ddfc4..47df932f9d4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.cc +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc @@ -24,29 +24,17 @@ static int node_shader_gpu_geometry(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - /* HACK: Don't request GPU_BARYCENTRIC_TEXCO if not used because it will + /* HACK: Don't request GPU_MATFLAG_BARYCENTRIC if not used because it will * trigger the use of geometry shader (and the performance penalty it implies). */ - const float val[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - GPUNodeLink *bary_link = (!out[5].hasoutput) ? GPU_constant(val) : - GPU_builtin(GPU_BARYCENTRIC_TEXCO); if (out[5].hasoutput) { GPU_material_flag_set(mat, GPU_MATFLAG_BARYCENTRIC); } /* Opti: don't request orco if not needed. */ + const float val[4] = {0.0f, 0.0f, 0.0f, 0.0f}; GPUNodeLink *orco_link = (!out[2].hasoutput) ? GPU_constant(val) : GPU_attribute(mat, CD_ORCO, ""); - const bool success = GPU_stack_link(mat, - node, - "node_geometry", - in, - out, - GPU_builtin(GPU_VIEW_POSITION), - GPU_builtin(GPU_WORLD_NORMAL), - orco_link, - GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - bary_link); + const bool success = GPU_stack_link(mat, node, "node_geometry", in, out, orco_link); int i; LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) { @@ -55,7 +43,7 @@ static int node_shader_gpu_geometry(GPUMaterial *mat, * This is the case for interpolated, non linear functions. * The resulting vector can still be a bit wrong but not as much. * (see T70644) */ - if (node->branch_tag != 0 && ELEM(i, 1, 2, 4)) { + if (ELEM(i, 1, 2, 4)) { GPU_link(mat, "vector_math_normalize", out[i].link, diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.cc b/source/blender/nodes/shader/nodes/node_shader_holdout.cc index b1a9ce75e1f..6a21fab28db 100644 --- a/source/blender/nodes/shader/nodes/node_shader_holdout.cc +++ b/source/blender/nodes/shader/nodes/node_shader_holdout.cc @@ -7,6 +7,7 @@ namespace blender::nodes::node_shader_holdout_cc { static void node_declare(NodeDeclarationBuilder &b) { + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("Holdout")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc index b5097e71657..69825e472fb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc +++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc @@ -20,14 +20,10 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat, GPUNodeStack *out) { if (!in[1].link) { - in[1].link = GPU_builtin(GPU_VIEW_NORMAL); - } - else { - GPU_link( - mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link); + GPU_link(mat, "world_normals_get", &in[1].link); } - return GPU_stack_link(mat, node, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION)); + return GPU_stack_link(mat, node, "node_layer_weight", in, out); } } // namespace blender::nodes::node_shader_layer_weight_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc index f8a5e342ae3..d51d8def945 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc @@ -83,18 +83,16 @@ static int gpu_shader_normal_map(GPUMaterial *mat, GPU_link(mat, color_to_normal_fnc_name, newnormal, &newnormal); switch (nm->space) { case SHD_SPACE_TANGENT: + GPU_material_flag_set(mat, GPU_MATFLAG_OBJECT_INFO); GPU_link(mat, "node_normal_map", - GPU_builtin(GPU_OBJECT_INFO), GPU_attribute(mat, CD_TANGENT, nm->uv_map), - GPU_builtin(GPU_WORLD_NORMAL), newnormal, &newnormal); break; case SHD_SPACE_OBJECT: case SHD_SPACE_BLENDER_OBJECT: - GPU_link( - mat, "direction_transform_m4v3", newnormal, GPU_builtin(GPU_OBJECT_MATRIX), &newnormal); + GPU_link(mat, "normal_transform_object_to_world", newnormal, &newnormal); break; case SHD_SPACE_WORLD: case SHD_SPACE_BLENDER_WORLD: @@ -102,8 +100,7 @@ static int gpu_shader_normal_map(GPUMaterial *mat, break; } - GPUNodeLink *oldnormal = GPU_builtin(GPU_WORLD_NORMAL); - GPU_link(mat, "node_normal_map_mix", strength, newnormal, oldnormal, &out[0].link); + GPU_link(mat, "node_normal_map_mix", strength, newnormal, &out[0].link); return true; } diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.cc b/source/blender/nodes/shader/nodes/node_shader_object_info.cc index 03c1a018d37..8985ab6d0e9 100644 --- a/source/blender/nodes/shader/nodes/node_shader_object_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_object_info.cc @@ -23,15 +23,8 @@ static int node_shader_gpu_object_info(GPUMaterial *mat, { Material *ma = GPU_material_get_material(mat); float index = ma ? ma->index : 0.0f; - return GPU_stack_link(mat, - node, - "node_object_info", - in, - out, - GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_OBJECT_COLOR), - GPU_builtin(GPU_OBJECT_INFO), - GPU_constant(&index)); + GPU_material_flag_set(mat, GPU_MATFLAG_OBJECT_INFO); + return GPU_stack_link(mat, node, "node_object_info", in, out, GPU_constant(&index)); } } // namespace blender::nodes::node_shader_object_info_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.cc b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc index c0a116675ab..78dabc5c1c2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_aov.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc @@ -35,12 +35,16 @@ static int node_shader_gpu_output_aov(GPUMaterial *mat, { GPUNodeLink *outlink; NodeShaderOutputAOV *aov = (NodeShaderOutputAOV *)node->storage; - /* Keep in sync with `renderpass_lib.glsl#render_pass_aov_hash` and - * `EEVEE_renderpasses_aov_hash`. */ - unsigned int hash = BLI_hash_string(aov->name) << 1; - GPU_stack_link(mat, node, "node_output_aov", in, out, &outlink); - GPU_material_add_output_link_aov(mat, outlink, hash); + uint hash = BLI_hash_string(aov->name); + /* WORKAROUND: We don't support int/uint constants for now. So make sure the aliasing works. + * We cast back to uint in GLSL. */ + BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint), + "GPUCodegen: AOV hash needs float and uint to be the same size."); + GPUNodeLink *hash_link = GPU_constant((float *)&hash); + GPU_material_flag_set(mat, GPU_MATFLAG_AOV); + GPU_stack_link(mat, node, "node_output_aov", in, out, hash_link, &outlink); + GPU_material_add_output_link_aov(mat, outlink, hash); return true; } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc index 3329ab7f8a0..54475d547da 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc @@ -12,39 +12,33 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input(N_("Surface")); b.add_input(N_("Volume")); b.add_input(N_("Displacement")).hide_value(); + b.add_input(N_("Thickness")).hide_value(); } static int node_shader_gpu_output_material(GPUMaterial *mat, - bNode *node, + bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, - GPUNodeStack *out) + GPUNodeStack *UNUSED(out)) { - GPUNodeLink *outlink, *alpha_threshold_link, *shadow_threshold_link; - Material *ma = GPU_material_get_material(mat); - - static float no_alpha_threshold = -1.0f; - if (ma) { - alpha_threshold_link = GPU_uniform((ma->blend_method == MA_BM_CLIP) ? &ma->alpha_threshold : - &no_alpha_threshold); - shadow_threshold_link = GPU_uniform((ma->blend_shadow == MA_BS_CLIP) ? &ma->alpha_threshold : - &no_alpha_threshold); + GPUNodeLink *outlink_surface, *outlink_volume, *outlink_displacement, *outlink_thickness; + /* Passthrough node in order to do the right socket conversions (important for displacement). */ + if (in[0].link) { + GPU_link(mat, "node_output_material_surface", in[0].link, &outlink_surface); + GPU_material_output_surface(mat, outlink_surface); } - else { - alpha_threshold_link = GPU_uniform(&no_alpha_threshold); - shadow_threshold_link = GPU_uniform(&no_alpha_threshold); + if (in[1].link) { + GPU_link(mat, "node_output_material_volume", in[1].link, &outlink_volume); + GPU_material_output_volume(mat, outlink_volume); + } + if (in[2].link) { + GPU_link(mat, "node_output_material_displacement", in[2].link, &outlink_displacement); + GPU_material_output_displacement(mat, outlink_displacement); + } + if (in[3].link) { + GPU_link(mat, "node_output_material_thickness", in[3].link, &outlink_thickness); + GPU_material_output_thickness(mat, outlink_thickness); } - - GPU_stack_link(mat, - node, - "node_output_material", - in, - out, - alpha_threshold_link, - shadow_threshold_link, - &outlink); - GPU_material_output_link(mat, outlink); - return true; } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.cc b/source/blender/nodes/shader/nodes/node_shader_output_world.cc index 77146876d9d..b0cf4c80bc5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_world.cc +++ b/source/blender/nodes/shader/nodes/node_shader_output_world.cc @@ -12,16 +12,20 @@ static void node_declare(NodeDeclarationBuilder &b) } static int node_shader_gpu_output_world(GPUMaterial *mat, - bNode *node, + bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, - GPUNodeStack *out) + GPUNodeStack *UNUSED(out)) { - GPUNodeLink *outlink; - - GPU_stack_link(mat, node, "node_output_world", in, out, &outlink); - GPU_material_output_link(mat, outlink); - + GPUNodeLink *outlink_surface, *outlink_volume; + if (in[0].link) { + GPU_link(mat, "node_output_world_surface", in[0].link, &outlink_surface); + GPU_material_output_surface(mat, outlink_surface); + } + if (in[1].link) { + GPU_link(mat, "node_output_world_volume", in[1].link, &outlink_volume); + GPU_material_output_volume(mat, outlink_volume); + } return true; } diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.cc b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc index 66e859a8c69..71adbd5e5c4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_particle_info.cc +++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc @@ -28,16 +28,9 @@ static int gpu_shader_particle_info(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - - return GPU_stack_link(mat, - node, - "particle_info", - in, - out, - GPU_builtin(GPU_PARTICLE_SCALAR_PROPS), - GPU_builtin(GPU_PARTICLE_LOCATION), - GPU_builtin(GPU_PARTICLE_VELOCITY), - GPU_builtin(GPU_PARTICLE_ANG_VELOCITY)); + GPU_material_flag_set(mat, GPU_MATFLAG_OBJECT_INFO); + /* TODO(fclem) Pass particle data in obinfo. */ + return GPU_stack_link(mat, node, "particle_info", in, out); } } // namespace blender::nodes::node_shader_particle_info_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc index 11dfa03ea40..0404158a803 100644 --- a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc @@ -18,9 +18,7 @@ static int node_shader_gpu_shadertorgb(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - /* Because node_shader_to_rgba is using fallback_cubemap() - * we need to tag material as glossy. */ - GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY); + GPU_material_flag_set(mat, GPU_MATFLAG_SHADER_TO_RGBA); return GPU_stack_link(mat, node, "node_shader_to_rgba", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc index 17173ef020a..e3ff4c28604 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc @@ -25,6 +25,7 @@ static void node_declare(NodeDeclarationBuilder &b) .max(1.0f) .subtype(PROP_FACTOR); b.add_input(N_("Normal")).hide_value(); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("BSSRDF")); } @@ -49,19 +50,16 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, GPU_link(mat, "world_normals_get", &in[5].link); } - if (node->sss_id > 0) { - bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2); - bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value; - /* For some reason it seems that the socket value is in ARGB format. */ - GPU_material_sss_profile_create(mat, &socket_data->value[1]); + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2); + bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value; + /* For some reason it seems that the socket value is in ARGB format. */ + bool use_subsurf = GPU_material_sss_profile_create(mat, &socket_data->value[1]); - /* sss_id is 0 only the node is not connected to any output. - * In this case flagging the material would trigger a bug (see T68736). */ - GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS)); - } + float use_sss = (use_subsurf) ? 1.0f : 0.0f; + + GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SUBSURFACE); - return GPU_stack_link( - mat, node, "node_subsurface_scattering", in, out, GPU_constant(&node->sss_id)); + return GPU_stack_link(mat, node, "node_subsurface_scattering", in, out, GPU_uniform(&use_sss)); } static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *node) diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.cc b/source/blender/nodes/shader/nodes/node_shader_tangent.cc index 25489632594..8e27ebed21b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tangent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tangent.cc @@ -73,14 +73,7 @@ static int node_shader_gpu_tangent(GPUMaterial *mat, GPU_link(mat, "tangent_orco_z", orco, &orco); } - return GPU_stack_link(mat, - node, - "node_tangent", - in, - out, - GPU_builtin(GPU_WORLD_NORMAL), - orco, - GPU_builtin(GPU_OBJECT_MATRIX)); + return GPU_stack_link(mat, node, "node_tangent", in, out, orco); } } // namespace blender::nodes::node_shader_tangent_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc index ac986787d65..ae683386bac 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc @@ -35,24 +35,18 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, { Object *ob = (Object *)node->id; - GPUNodeLink *inv_obmat = (ob != nullptr) ? GPU_uniform(&ob->imat[0][0]) : - GPU_builtin(GPU_INVERSE_OBJECT_MATRIX); + /* Use special matrix to let the shader branch to using the render object's matrix. */ + float dummy_matrix[4][4]; + dummy_matrix[3][3] = 0.0f; + GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) : + GPU_uniform(&dummy_matrix[0][0]); /* Opti: don't request orco if not needed. */ - const float default_coords[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant(default_coords) : - GPU_attribute(mat, CD_ORCO, ""); + float4 zero(0.0f); + GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant(zero) : GPU_attribute(mat, CD_ORCO, ""); GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, ""); - GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION); - GPUNodeLink *worldnor = GPU_builtin(GPU_WORLD_NORMAL); - GPUNodeLink *texcofacs = GPU_builtin(GPU_CAMERA_TEXCO_FACTORS); - if (out[0].hasoutput) { - GPU_link(mat, "generated_from_orco", orco, &orco); - } - - GPU_stack_link( - mat, node, "node_tex_coord", in, out, viewpos, worldnor, inv_obmat, texcofacs, orco, mtface); + GPU_stack_link(mat, node, "node_tex_coord", in, out, inv_obmat, orco, mtface); int i; LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) { @@ -61,7 +55,7 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, * This is the case for interpolated, non linear functions. * The resulting vector can still be a bit wrong but not as much. * (see T70644) */ - if (node->branch_tag != 0 && ELEM(i, 1, 6)) { + if (ELEM(i, 1, 6)) { GPU_link(mat, "vector_math_normalize", out[i].link, diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc index 41456091e1d..dbff092234b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc @@ -44,15 +44,13 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, GPUNodeLink *outalpha; - if (!ima) { + /* HACK(fclem): For lookdev mode: do not compile an empty environment and just create an empty + * texture entry point. We manually bind to it after DRW_shgroup_add_material_resources(). */ + if (!ima && !GPU_material_flag_get(mat, GPU_MATFLAG_LOOKDEV_HACK)) { return GPU_stack_link(mat, node, "node_tex_environment_empty", in, out); } - if (!in[0].link) { - GPU_link(mat, "node_tex_environment_texco", GPU_builtin(GPU_VIEW_POSITION), &in[0].link); - node_shader_gpu_bump_tex_coord(mat, node, &in[0].link); - } - + node_shader_gpu_default_tex_coord(mat, node, &in[0].link); node_shader_gpu_tex_mapping(mat, node, in, out); /* Compute texture coordinate. */ @@ -92,7 +90,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, /* Sample texture with correct interpolation. */ GPU_link(mat, gpu_fn, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha); - if (out[0].hasoutput) { + if (out[0].hasoutput && ima) { if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) || IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) { /* Don't let alpha affect color output in these cases. */ diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index 19b5a50cd6b..d97f7d0375d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -88,13 +88,11 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, } case SHD_PROJ_BOX: { gpu_node_name = use_cubic ? "tex_box_sample_cubic" : "tex_box_sample_linear"; - GPUNodeLink *wnor, *col1, *col2, *col3; - GPUNodeLink *vnor = GPU_builtin(GPU_WORLD_NORMAL); - GPUNodeLink *ob_mat = GPU_builtin(GPU_OBJECT_MATRIX); + GPUNodeLink *vnor, *wnor, *col1, *col2, *col3; GPUNodeLink *blend = GPU_uniform(&tex->projection_blend); GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state); - /* equivalent to normal_world_to_object */ - GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &wnor); + GPU_link(mat, "world_normals_get", &vnor); + GPU_link(mat, "normal_transform_world_to_object", vnor, &wnor); GPU_link(mat, gpu_node_name, in[0].link, wnor, gpu_image, &col1, &col2, &col3); GPU_link(mat, "tex_box_blend", wnor, col1, col2, col3, blend, &out[0].link, &out[1].link); break; diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc index 04cf0b72f32..9996e91177a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc @@ -24,23 +24,20 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - if (node->custom1 == SHD_SPACE_TANGENT) { - return GPU_stack_link(mat, - node, - "node_vector_displacement_tangent", - in, - out, - GPU_attribute(mat, CD_TANGENT, ""), - GPU_builtin(GPU_WORLD_NORMAL), - GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_VIEW_MATRIX)); + switch (node->custom1) { + case SHD_SPACE_TANGENT: + return GPU_stack_link(mat, + node, + "node_vector_displacement_tangent", + in, + out, + GPU_attribute(mat, CD_TANGENT, "")); + case SHD_SPACE_OBJECT: + return GPU_stack_link(mat, node, "node_vector_displacement_object", in, out); + case SHD_SPACE_WORLD: + default: + return GPU_stack_link(mat, node, "node_vector_displacement_world", in, out); } - if (node->custom1 == SHD_SPACE_OBJECT) { - return GPU_stack_link( - mat, node, "node_vector_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX)); - } - - return GPU_stack_link(mat, node, "node_vector_displacement_world", in, out); } } // namespace blender::nodes::node_shader_vector_displacement_cc diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc index d610e1309a7..de588f9005f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc @@ -43,7 +43,7 @@ static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *nod node->storage = vect; } -static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) +static const char *get_gpufn_name_from_to(short from, short to, bool is_direction) { switch (from) { case SHD_VECT_TRANSFORM_SPACE_OBJECT: @@ -51,9 +51,11 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) case SHD_VECT_TRANSFORM_SPACE_OBJECT: return nullptr; case SHD_VECT_TRANSFORM_SPACE_WORLD: - return GPU_builtin(GPU_OBJECT_MATRIX); + return is_direction ? "direction_transform_object_to_world" : + "point_transform_object_to_world"; case SHD_VECT_TRANSFORM_SPACE_CAMERA: - return GPU_builtin(GPU_LOC_TO_VIEW_MATRIX); + return is_direction ? "direction_transform_object_to_view" : + "point_transform_object_to_view"; } break; case SHD_VECT_TRANSFORM_SPACE_WORLD: @@ -61,9 +63,11 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) case SHD_VECT_TRANSFORM_SPACE_WORLD: return nullptr; case SHD_VECT_TRANSFORM_SPACE_CAMERA: - return GPU_builtin(GPU_VIEW_MATRIX); + return is_direction ? "direction_transform_world_to_view" : + "point_transform_world_to_view"; case SHD_VECT_TRANSFORM_SPACE_OBJECT: - return GPU_builtin(GPU_INVERSE_OBJECT_MATRIX); + return is_direction ? "direction_transform_world_to_object" : + "point_transform_world_to_object"; } break; case SHD_VECT_TRANSFORM_SPACE_CAMERA: @@ -71,14 +75,17 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) case SHD_VECT_TRANSFORM_SPACE_CAMERA: return nullptr; case SHD_VECT_TRANSFORM_SPACE_WORLD: - return GPU_builtin(GPU_INVERSE_VIEW_MATRIX); + return is_direction ? "direction_transform_view_to_world" : + "point_transform_view_to_world"; case SHD_VECT_TRANSFORM_SPACE_OBJECT: - return GPU_builtin(GPU_INVERSE_LOC_TO_VIEW_MATRIX); + return is_direction ? "direction_transform_view_to_object" : + "point_transform_view_to_object"; } break; } - return nullptr; + return NULL; } + static int gpu_shader_vect_transform(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), @@ -86,11 +93,6 @@ static int gpu_shader_vect_transform(GPUMaterial *mat, GPUNodeStack *out) { struct GPUNodeLink *inputlink; - struct GPUNodeLink *fromto; - - const char *vtransform = "direction_transform_m4v3"; - const char *ptransform = "point_transform_m4v3"; - const char *func_name = nullptr; NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage; @@ -101,17 +103,20 @@ static int gpu_shader_vect_transform(GPUMaterial *mat, inputlink = GPU_constant(in[0].vec); } - fromto = get_gpulink_matrix_from_to(nodeprop->convert_from, nodeprop->convert_to); + const bool is_direction = (nodeprop->type != SHD_VECT_TRANSFORM_TYPE_POINT); + const char *func_name = get_gpufn_name_from_to( + nodeprop->convert_from, nodeprop->convert_to, is_direction); - func_name = (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_POINT) ? ptransform : vtransform; - if (fromto) { + if (func_name) { /* For cycles we have inverted Z */ /* TODO: pass here the correct matrices */ if (nodeprop->convert_from == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_to != SHD_VECT_TRANSFORM_SPACE_CAMERA) { GPU_link(mat, "invert_z", inputlink, &inputlink); } - GPU_link(mat, func_name, inputlink, fromto, &out[0].link); + + GPU_link(mat, func_name, inputlink, &out[0].link); + if (nodeprop->convert_to == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_from != SHD_VECT_TRANSFORM_SPACE_CAMERA) { GPU_link(mat, "invert_z", out[0].link, &out[0].link); diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc index e0fef6b0d19..930fa6e5fb9 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc +++ b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc @@ -9,6 +9,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.add_input(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); b.add_input(N_("Density")).default_value(1.0f).min(0.0f).max(1000.0f); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("Volume")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc index 980782f571c..d414b4b2ef7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc @@ -27,6 +27,7 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input(N_("Blackbody Tint")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); b.add_input(N_("Temperature")).default_value(1000.0f).min(0.0f).max(6500.0f); b.add_input(N_("Temperature Attribute")); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("Volume")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc index 6408efb769d..0c6859ad1fb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc +++ b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc @@ -14,6 +14,7 @@ static void node_declare(NodeDeclarationBuilder &b) .min(-1.0f) .max(1.0f) .subtype(PROP_FACTOR); + b.add_input(N_("Weight")).unavailable(); b.add_output(N_("Volume")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.cc b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc index 1204c3a678f..6a1acda3353 100644 --- a/source/blender/nodes/shader/nodes/node_shader_wireframe.cc +++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc @@ -28,17 +28,11 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat, GPU_material_flag_set(mat, GPU_MATFLAG_BARYCENTRIC); /* node->custom1 is use_pixel_size */ if (node->custom1) { - return GPU_stack_link( - mat, node, "node_wireframe_screenspace", in, out, GPU_builtin(GPU_BARYCENTRIC_TEXCO)); + return GPU_stack_link(mat, node, "node_wireframe_screenspace", in, out); + } + else { + return GPU_stack_link(mat, node, "node_wireframe", in, out); } - - return GPU_stack_link(mat, - node, - "node_wireframe", - in, - out, - GPU_builtin(GPU_BARYCENTRIC_TEXCO), - GPU_builtin(GPU_BARYCENTRIC_DIST)); } } // namespace blender::nodes::node_shader_wireframe_cc -- cgit v1.2.3