diff options
Diffstat (limited to 'source/blender/draw/engines/workbench/workbench_shader.cc')
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_shader.cc | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/source/blender/draw/engines/workbench/workbench_shader.cc b/source/blender/draw/engines/workbench/workbench_shader.cc new file mode 100644 index 00000000000..bbc0bc02b03 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_shader.cc @@ -0,0 +1,398 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include <string> + +#include "workbench_engine.h" +#include "workbench_private.h" + +/* Maximum number of variations. */ +#define MAX_LIGHTING 3 + +enum eWORKBENCH_TextureType { + TEXTURE_SH_NONE = 0, + TEXTURE_SH_SINGLE, + TEXTURE_SH_TILED, + TEXTURE_SH_MAX, +}; + +static struct { + struct GPUShader + *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX][TEXTURE_SH_MAX]; + struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX] + [MAX_LIGHTING][TEXTURE_SH_MAX]; + + struct GPUShader *opaque_composite_sh[MAX_LIGHTING]; + struct GPUShader *oit_resolve_sh; + struct GPUShader *outline_sh; + struct GPUShader *merge_infront_sh; + + struct GPUShader *shadow_depth_pass_sh[2]; + struct GPUShader *shadow_depth_fail_sh[2][2]; + + struct GPUShader *cavity_sh[2][2]; + + struct GPUShader *dof_prepare_sh; + struct GPUShader *dof_downsample_sh; + struct GPUShader *dof_blur1_sh; + struct GPUShader *dof_blur2_sh; + struct GPUShader *dof_resolve_sh; + + struct GPUShader *aa_accum_sh; + struct GPUShader *smaa_sh[3]; + + struct GPUShader *volume_sh[2][2][3][2]; + +} e_data = {{{{nullptr}}}}; + +/* -------------------------------------------------------------------- */ +/** \name Conversions + * \{ */ + +static const char *workbench_lighting_mode_to_str(int light) +{ + switch (light) { + default: + BLI_assert_msg(0, "Error: Unknown lighting mode."); + ATTR_FALLTHROUGH; + case V3D_LIGHTING_STUDIO: + return "_studio"; + case V3D_LIGHTING_MATCAP: + return "_matcap"; + case V3D_LIGHTING_FLAT: + return "_flat"; + return ""; + } +} + +static const char *workbench_datatype_mode_to_str(eWORKBENCH_DataType datatype) +{ + switch (datatype) { + default: + BLI_assert_msg(0, "Error: Unknown data mode."); + ATTR_FALLTHROUGH; + case WORKBENCH_DATATYPE_MESH: + return "_mesh"; + case WORKBENCH_DATATYPE_HAIR: + return "_hair"; + case WORKBENCH_DATATYPE_POINTCLOUD: + return "_ptcloud"; + } +} + +static const char *workbench_volume_interp_to_str(eWORKBENCH_VolumeInterpType interp_type) +{ + switch (interp_type) { + default: + BLI_assert_msg(0, "Error: Unknown lighting mode."); + ATTR_FALLTHROUGH; + case WORKBENCH_VOLUME_INTERP_LINEAR: + return "_linear"; + case WORKBENCH_VOLUME_INTERP_CUBIC: + return "_cubic"; + case WORKBENCH_VOLUME_INTERP_CLOSEST: + return "_closest"; + } +} + +static const char *workbench_texture_type_to_str(eWORKBENCH_TextureType tex_type) +{ + switch (tex_type) { + default: + BLI_assert_msg(0, "Error: Unknown texture mode."); + ATTR_FALLTHROUGH; + case TEXTURE_SH_NONE: + return "_tex_none"; + case TEXTURE_SH_TILED: + return "_tex_tile"; + case TEXTURE_SH_SINGLE: + return "_tex_single"; + } +} + +static eWORKBENCH_TextureType workbench_texture_type_get(bool textured, bool tiled) +{ + return textured ? (tiled ? TEXTURE_SH_TILED : TEXTURE_SH_SINGLE) : TEXTURE_SH_NONE; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Shader request + * \{ */ + +static GPUShader *workbench_shader_get_ex(WORKBENCH_PrivateData *wpd, + bool transp, + eWORKBENCH_DataType datatype, + bool textured, + bool tiled) +{ + eWORKBENCH_TextureType tex_type = workbench_texture_type_get(textured, tiled); + int light = wpd->shading.light; + BLI_assert(light < MAX_LIGHTING); + struct GPUShader **shader = + (transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][datatype][light][tex_type] : + &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][datatype][tex_type]; + + if (*shader == nullptr) { + std::string create_info_name = "workbench"; + create_info_name += (transp) ? "_transp" : "_opaque"; + if (transp) { + create_info_name += workbench_lighting_mode_to_str(light); + } + create_info_name += workbench_datatype_mode_to_str(datatype); + create_info_name += workbench_texture_type_to_str(tex_type); + create_info_name += (wpd->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? "_clip" : "_no_clip"; + + *shader = GPU_shader_create_from_info_name(create_info_name.c_str()); + } + return *shader; +} + +GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType datatype) +{ + return workbench_shader_get_ex(wpd, false, datatype, false, false); +} + +GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, + eWORKBENCH_DataType datatype, + bool tiled) +{ + return workbench_shader_get_ex(wpd, false, datatype, true, tiled); +} + +GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, + eWORKBENCH_DataType datatype) +{ + return workbench_shader_get_ex(wpd, true, datatype, false, false); +} + +GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd, + eWORKBENCH_DataType datatype, + bool tiled) +{ + return workbench_shader_get_ex(wpd, true, datatype, true, tiled); +} + +GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd) +{ + int light = wpd->shading.light; + struct GPUShader **shader = &e_data.opaque_composite_sh[light]; + BLI_assert(light < MAX_LIGHTING); + + if (*shader == nullptr) { + std::string create_info_name = "workbench_composite"; + create_info_name += workbench_lighting_mode_to_str(light); + *shader = GPU_shader_create_from_info_name(create_info_name.c_str()); + } + return *shader; +} + +GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd)) +{ + if (e_data.merge_infront_sh == nullptr) { + e_data.merge_infront_sh = GPU_shader_create_from_info_name("workbench_merge_infront"); + } + return e_data.merge_infront_sh; +} + +GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *UNUSED(wpd)) +{ + if (e_data.oit_resolve_sh == nullptr) { + e_data.oit_resolve_sh = GPU_shader_create_from_info_name("workbench_transparent_resolve"); + } + return e_data.oit_resolve_sh; +} + +static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap) +{ + struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] : + &e_data.shadow_depth_fail_sh[manifold][cap]; + + if (*shader == nullptr) { + std::string create_info_name = "workbench_shadow"; + create_info_name += (depth_pass) ? "_pass" : "_fail"; + create_info_name += (manifold) ? "_manifold" : "_no_manifold"; + create_info_name += (cap) ? "_caps" : "_no_caps"; +#if DEBUG_SHADOW_VOLUME + create_info_name += "_debug"; +#endif + *shader = GPU_shader_create_from_info_name(create_info_name.c_str()); + } + return *shader; +} + +GPUShader *workbench_shader_shadow_pass_get(bool manifold) +{ + return workbench_shader_shadow_pass_get_ex(true, manifold, false); +} + +GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap) +{ + return workbench_shader_shadow_pass_get_ex(false, manifold, cap); +} + +GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature) +{ + BLI_assert(cavity || curvature); + struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature]; + + if (*shader == nullptr) { + std::string create_info_name = "workbench_effect"; + create_info_name += (cavity) ? "_cavity" : ""; + create_info_name += (curvature) ? "_curvature" : ""; + *shader = GPU_shader_create_from_info_name(create_info_name.c_str()); + } + return *shader; +} + +GPUShader *workbench_shader_outline_get(void) +{ + if (e_data.outline_sh == nullptr) { + e_data.outline_sh = GPU_shader_create_from_info_name("workbench_effect_outline"); + } + return e_data.outline_sh; +} + +void workbench_shader_depth_of_field_get(GPUShader **prepare_sh, + GPUShader **downsample_sh, + GPUShader **blur1_sh, + GPUShader **blur2_sh, + GPUShader **resolve_sh) +{ + if (e_data.dof_prepare_sh == nullptr) { + e_data.dof_prepare_sh = GPU_shader_create_from_info_name("workbench_effect_dof_prepare"); + e_data.dof_downsample_sh = GPU_shader_create_from_info_name("workbench_effect_dof_downsample"); +#if 0 /* TODO(fclem): finish COC min_max optimization */ + e_data.dof_flatten_v_sh = GPU_shader_create_from_info_name("workbench_effect_dof_flatten_v"); + e_data.dof_flatten_h_sh = GPU_shader_create_from_info_name("workbench_effect_dof_flatten_h"); + e_data.dof_dilate_v_sh = GPU_shader_create_from_info_name("workbench_effect_dof_dilate_v"); + e_data.dof_dilate_h_sh = GPU_shader_create_from_info_name("workbench_effect_dof_dilate_h"); +#endif + e_data.dof_blur1_sh = GPU_shader_create_from_info_name("workbench_effect_dof_blur1"); + e_data.dof_blur2_sh = GPU_shader_create_from_info_name("workbench_effect_dof_blur2"); + e_data.dof_resolve_sh = GPU_shader_create_from_info_name("workbench_effect_dof_resolve"); + } + + *prepare_sh = e_data.dof_prepare_sh; + *downsample_sh = e_data.dof_downsample_sh; + *blur1_sh = e_data.dof_blur1_sh; + *blur2_sh = e_data.dof_blur2_sh; + *resolve_sh = e_data.dof_resolve_sh; +} + +GPUShader *workbench_shader_antialiasing_accumulation_get(void) +{ + if (e_data.aa_accum_sh == nullptr) { + e_data.aa_accum_sh = GPU_shader_create_from_info_name("workbench_taa"); + } + return e_data.aa_accum_sh; +} + +GPUShader *workbench_shader_antialiasing_get(int stage) +{ + BLI_assert(stage < 3); + GPUShader **shader = &e_data.smaa_sh[stage]; + + if (*shader == nullptr) { + std::string create_info_name = "workbench_smaa_stage_"; + create_info_name += std::to_string(stage); + *shader = GPU_shader_create_from_info_name(create_info_name.c_str()); + } + return e_data.smaa_sh[stage]; +} + +GPUShader *workbench_shader_volume_get(bool slice, + bool coba, + eWORKBENCH_VolumeInterpType interp_type, + bool smoke) +{ + GPUShader **shader = &e_data.volume_sh[slice][coba][interp_type][smoke]; + + if (*shader == nullptr) { + std::string create_info_name = "workbench_volume"; + create_info_name += (smoke) ? "_smoke" : "_object"; + create_info_name += workbench_volume_interp_to_str(interp_type); + create_info_name += (coba) ? "_coba" : "_no_coba"; + create_info_name += (slice) ? "_slice" : "_no_slice"; + *shader = GPU_shader_create_from_info_name(create_info_name.c_str()); + } + return *shader; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Cleanup + * \{ */ + +void workbench_shader_free(void) +{ + for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < ARRAY_SIZE(e_data.opaque_composite_sh); j++) { + struct GPUShader **sh_array = &e_data.opaque_composite_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < ARRAY_SIZE(e_data.shadow_depth_pass_sh); j++) { + struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.cavity_sh[0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < ARRAY_SIZE(e_data.smaa_sh); j++) { + struct GPUShader **sh_array = &e_data.smaa_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.volume_sh[0][0][0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + + DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh); + DRW_SHADER_FREE_SAFE(e_data.outline_sh); + DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh); + + DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh); + + DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh); +} + +/** \} */ |