diff options
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_materials.c')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_materials.c | 2388 |
1 files changed, 538 insertions, 1850 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 03cdb02a48a..0563d098a1c 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -23,10 +23,10 @@ #include "DRW_render.h" #include "BLI_alloca.h" -#include "BLI_dynstr.h" #include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_math_bits.h" +#include "BLI_memblock.h" #include "BLI_rand.h" #include "BLI_string_utils.h" @@ -48,29 +48,11 @@ /* *********** STATIC *********** */ static struct { - char *frag_shader_lib; - char *vert_shader_str; - char *vert_shadow_shader_str; - char *vert_background_shader_str; - char *vert_volume_shader_str; - char *geom_volume_shader_str; - char *volume_shader_lib; - - struct GPUShader *default_prepass_sh; - struct GPUShader *default_prepass_clip_sh; - struct GPUShader *default_hair_prepass_sh; - struct GPUShader *default_hair_prepass_clip_sh; - struct GPUShader *default_lit[VAR_MAT_MAX]; - struct GPUShader *default_background; - struct GPUShader *update_noise_sh; - /* 64*64 array texture containing all LUTs and other utilitarian arrays. * Packing enables us to same precious textures slots. */ struct GPUTexture *util_tex; struct GPUTexture *noise_tex; - uint sss_count; - float noise_offsets[3]; } e_data = {NULL}; /* Engine data */ @@ -82,8 +64,6 @@ extern char datatoc_prepass_vert_glsl[]; extern char datatoc_default_frag_glsl[]; extern char datatoc_default_world_frag_glsl[]; extern char datatoc_ltc_lib_glsl[]; -extern char datatoc_bsdf_lut_frag_glsl[]; -extern char datatoc_btdf_lut_frag_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; @@ -107,392 +87,91 @@ extern char datatoc_volumetric_frag_glsl[]; extern char datatoc_volumetric_lib_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; -#define DEFAULT_RENDER_PASS_FLAG 0xefffffff - -/* Iterator for render passes. This iteration will only do the material based render passes. it - * will ignore `EEVEE_RENDER_PASS_ENVIRONMENT`. - * - * parameters: - * - `render_passes_` is a bitflag for render_passes that needs to be iterated over. - * - `render_pass_index_` is a parameter name where the index of the render_pass will be available - * during iteration. This index can be used to select the right pass in the `psl`. - * - `render_pass_` is the bitflag of the render_pass of the current iteration. - * - * The `render_pass_index_` parameter needs to be the same for the `RENDER_PASS_ITER_BEGIN` and - * `RENDER_PASS_ITER_END`. - */ -#define RENDER_PASS_ITER_BEGIN(render_passes_, render_pass_index_, render_pass_) \ - const eViewLayerEEVEEPassType __filtered_##render_pass_index_ = render_passes_ & \ - EEVEE_RENDERPASSES_MATERIAL & \ - ~EEVEE_RENDER_PASS_ENVIRONMENT; \ - if (__filtered_##render_pass_index_ != 0) { \ - int render_pass_index_ = 1; \ - for (int bit_##render_pass_ = 0; bit_##render_pass_ < EEVEE_RENDER_PASS_MAX_BIT; \ - bit_##render_pass_++) { \ - eViewLayerEEVEEPassType render_pass_ = (1 << bit_##render_pass_); \ - if ((__filtered_##render_pass_index_ & render_pass_) != 0) { -#define RENDER_PASS_ITER_END(render_pass_index_) \ - render_pass_index_ += 1; \ - } \ - } \ - } \ - ((void)0) +typedef struct EeveeMaterialCache { + struct DRWShadingGroup *depth_grp; + struct DRWShadingGroup *shading_grp; + struct DRWShadingGroup *shadow_grp; + struct GPUMaterial *shading_gpumat; + /* Meh, Used by hair to ensure draw order when calling DRW_shgroup_create_sub. + * Pointers to ghash values. */ + struct DRWShadingGroup **depth_grp_p; + struct DRWShadingGroup **shading_grp_p; + struct DRWShadingGroup **shadow_grp_p; +} EeveeMaterialCache; /* *********** FUNCTIONS *********** */ -#if 0 /* Used only to generate the LUT values */ -static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h)) -{ - struct GPUTexture *tex; - struct GPUFrameBuffer *fb = NULL; - static float samples_len = 8192.0f; - static float inv_samples_len = 1.0f / 8192.0f; - - char *lib_str = BLI_string_joinN(datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl); - - struct GPUShader *sh = DRW_shader_create_with_lib(datatoc_lightprobe_vert_glsl, - datatoc_lightprobe_geom_glsl, - datatoc_bsdf_lut_frag_glsl, - lib_str, - "#define HAMMERSLEY_SIZE 8192\n" - "#define BRDF_LUT_SIZE 64\n" - "#define NOISE_SIZE 64\n"); - - DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); - DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); - DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); - - struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call(grp, geom, NULL); - - float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); - - tex = DRW_texture_create_2d(w, h, GPU_RG16F, DRW_TEX_FILTER, (float *)texels); - - DRWFboTexture tex_filter = {&tex, GPU_RG16F, DRW_TEX_FILTER}; - GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); - - GPU_framebuffer_bind(fb); - DRW_draw_pass(pass); - - float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glReadPixels(0, 0, w, h, GL_RGB, GL_FLOAT, data); - - printf("{"); - for (int i = 0; i < w * h * 3; i += 3) { - printf("%ff, %ff, ", data[i], data[i + 1]); - i += 3; - printf("%ff, %ff, ", data[i], data[i + 1]); - i += 3; - printf("%ff, %ff, ", data[i], data[i + 1]); - i += 3; - printf("%ff, %ff, \n", data[i], data[i + 1]); - } - printf("}"); - - MEM_freeN(texels); - MEM_freeN(data); - - return tex; -} - -static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h) -{ - struct GPUTexture *tex; - struct GPUTexture *hammersley = create_hammersley_sample_texture(8192); - struct GPUFrameBuffer *fb = NULL; - static float samples_len = 8192.0f; - static float a2 = 0.0f; - static float inv_samples_len = 1.0f / 8192.0f; - - char *frag_str = BLI_string_joinN( - datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_btdf_lut_frag_glsl); - - struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str, - "#define HAMMERSLEY_SIZE 8192\n" - "#define BRDF_LUT_SIZE 64\n" - "#define NOISE_SIZE 64\n" - "#define LUT_SIZE 64\n"); - - MEM_freeN(frag_str); - - DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_float(grp, "a2", &a2, 1); - DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1); - DRW_shgroup_uniform_texture(grp, "texHammersley", hammersley); - DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex); - - struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call(grp, geom, NULL); - - float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); - - tex = DRW_texture_create_2d(w, h, GPU_R16F, DRW_TEX_FILTER, (float *)texels); - - DRWFboTexture tex_filter = {&tex, GPU_R16F, DRW_TEX_FILTER}; - GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); - - GPU_framebuffer_bind(fb); - - float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); - - float inc = 1.0f / 31.0f; - float roughness = 1e-8f - inc; - FILE *f = BLI_fopen("btdf_split_sum_ggx.h", "w"); - fprintf(f, "static float btdf_split_sum_ggx[32][64 * 64] = {\n"); - do { - roughness += inc; - CLAMP(roughness, 1e-4f, 1.0f); - a2 = powf(roughness, 4.0f); - DRW_draw_pass(pass); - - GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data); - -# if 1 - fprintf(f, "\t{\n\t\t"); - for (int i = 0; i < w * h * 3; i += 3) { - fprintf(f, "%ff,", data[i]); - if (((i / 3) + 1) % 12 == 0) { - fprintf(f, "\n\t\t"); - } - else { - fprintf(f, " "); - } - } - fprintf(f, "\n\t},\n"); -# else - for (int i = 0; i < w * h * 3; i += 3) { - if (data[i] < 0.01) { - printf(" "); - } - else if (data[i] < 0.3) { - printf("."); - } - else if (data[i] < 0.6) { - printf("+"); - } - else if (data[i] < 0.9) { - printf("%%"); - } - else { - printf("#"); - } - if ((i / 3 + 1) % 64 == 0) { - printf("\n"); - } - } -# endif - - } while (roughness < 1.0f); - fprintf(f, "\n};\n"); - - fclose(f); - - MEM_freeN(texels); - MEM_freeN(data); - - return tex; -} -#endif /* XXX TODO define all shared resources in a shared place without duplication */ struct GPUTexture *EEVEE_materials_get_util_tex(void) { return e_data.util_tex; } -static char *eevee_get_defines(int options) -{ - char *str = NULL; - - DynStr *ds = BLI_dynstr_new(); - BLI_dynstr_append(ds, SHADER_DEFINES); - - if ((options & VAR_MAT_MESH) != 0) { - BLI_dynstr_append(ds, "#define MESH_SHADER\n"); - } - if ((options & VAR_MAT_HAIR) != 0) { - BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); - } - if ((options & VAR_MAT_PROBE) != 0) { - BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n"); - } - if ((options & VAR_MAT_CLIP) != 0) { - BLI_dynstr_append(ds, "#define USE_ALPHA_CLIP\n"); - } - if ((options & VAR_MAT_SHADOW) != 0) { - BLI_dynstr_append(ds, "#define SHADOW_SHADER\n"); - } - if ((options & VAR_MAT_HASH) != 0) { - BLI_dynstr_append(ds, "#define USE_ALPHA_HASH\n"); - } - if ((options & VAR_MAT_BLEND) != 0) { - BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND\n"); - } - if ((options & VAR_MAT_MULT) != 0) { - BLI_dynstr_append(ds, "#define USE_MULTIPLY\n"); - } - if ((options & VAR_MAT_REFRACT) != 0) { - BLI_dynstr_append(ds, "#define USE_REFRACTION\n"); - } - if ((options & VAR_MAT_LOOKDEV) != 0) { - BLI_dynstr_append(ds, "#define LOOKDEV\n"); - } - if ((options & VAR_MAT_HOLDOUT) != 0) { - BLI_dynstr_append(ds, "#define HOLDOUT\n"); - } - - str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return str; -} - -static char *eevee_get_volume_defines(int options) -{ - char *str = NULL; - - DynStr *ds = BLI_dynstr_new(); - BLI_dynstr_append(ds, SHADER_DEFINES); - BLI_dynstr_append(ds, "#define VOLUMETRICS\n"); - - if ((options & VAR_MAT_VOLUME) != 0) { - BLI_dynstr_append(ds, "#define MESH_SHADER\n"); - } - - str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return str; -} - -/* Get the default render pass ubo. This is a ubo that enables all bsdf render passes. */ -struct GPUUniformBuffer *EEVEE_material_default_render_pass_ubo_get(EEVEE_ViewLayerData *sldata) -{ - return sldata->renderpass_ubo[0]; -} - -/* Get the render pass ubo for rendering the given render_pass. */ -static struct GPUUniformBuffer *get_render_pass_ubo(EEVEE_ViewLayerData *sldata, - eViewLayerEEVEEPassType render_pass) -{ - int index; - switch (render_pass) { - case EEVEE_RENDER_PASS_DIFFUSE_COLOR: - index = 1; - break; - case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: - index = 2; - break; - case EEVEE_RENDER_PASS_SPECULAR_COLOR: - index = 3; - break; - case EEVEE_RENDER_PASS_SPECULAR_LIGHT: - index = 4; - break; - case EEVEE_RENDER_PASS_EMIT: - index = 5; - break; - default: - index = 0; - break; - } - return sldata->renderpass_ubo[index]; -} /** * ssr_id can be null to disable ssr contribution. */ -static void add_standard_uniforms(DRWShadingGroup *shgrp, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - int *ssr_id, - float *refract_depth, - bool use_diffuse, - bool use_glossy, - bool use_refract, - bool use_ssrefraction, - bool use_alpha_blend, - eViewLayerEEVEEPassType render_pass) +void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, + GPUMaterial *gpumat, + EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + int *ssr_id, + float *refract_depth, + bool use_ssrefraction, + bool use_alpha_blend) { + 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); + LightCache *lcache = vedata->stl->g_data->light_cache; EEVEE_EffectsInfo *effects = vedata->stl->effects; + EEVEE_PrivateData *pd = vedata->stl->g_data; - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(shgrp, "renderpass_block", get_render_pass_ubo(sldata, render_pass)); + DRW_shgroup_uniform_block_persistent(shgrp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block_persistent(shgrp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block_persistent(shgrp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block_persistent(shgrp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block_persistent(shgrp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block_persistent(shgrp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block_ref_persistent(shgrp, "renderpass_block", &pd->renderpass_ubo); DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1); + DRW_shgroup_uniform_texture_persistent(shgrp, "utilTex", e_data.util_tex); if (use_diffuse || use_glossy || use_refract) { - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool); - DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); - DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); + DRW_shgroup_uniform_texture_ref_persistent( + shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool); + DRW_shgroup_uniform_texture_ref_persistent( + shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); + DRW_shgroup_uniform_texture_ref_persistent(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); } if ((use_diffuse || use_glossy) && !use_ssrefraction) { - DRW_shgroup_uniform_texture_ref(shgrp, "horizonBuffer", &effects->gtao_horizons); + DRW_shgroup_uniform_texture_ref_persistent(shgrp, "horizonBuffer", &effects->gtao_horizons); } if (use_diffuse) { - DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex); + DRW_shgroup_uniform_texture_ref_persistent(shgrp, "irradianceGrid", &lcache->grid_tx.tex); } if (use_glossy || use_refract) { - DRW_shgroup_uniform_texture_ref(shgrp, "probeCubes", &lcache->cube_tx.tex); + DRW_shgroup_uniform_texture_ref_persistent(shgrp, "probeCubes", &lcache->cube_tx.tex); } if (use_glossy) { - DRW_shgroup_uniform_texture_ref(shgrp, "probePlanars", &vedata->txl->planar_pool); + DRW_shgroup_uniform_texture_ref_persistent(shgrp, "probePlanars", &vedata->txl->planar_pool); DRW_shgroup_uniform_int_copy(shgrp, "outputSsrId", ssr_id ? *ssr_id : 0); } if (use_refract) { DRW_shgroup_uniform_float_copy( shgrp, "refractionDepth", (refract_depth) ? *refract_depth : 0.0); if (use_ssrefraction) { - DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color); + DRW_shgroup_uniform_texture_ref_persistent( + shgrp, "colorBuffer", &vedata->txl->refract_color); } } if (use_alpha_blend) { - DRW_shgroup_uniform_texture_ref(shgrp, "inScattering", &effects->volume_scatter); - DRW_shgroup_uniform_texture_ref(shgrp, "inTransmittance", &effects->volume_transmit); + DRW_shgroup_uniform_texture_ref_persistent(shgrp, "inScattering", &effects->volume_scatter); + DRW_shgroup_uniform_texture_ref_persistent( + shgrp, "inTransmittance", &effects->volume_transmit); } } -/* Add the uniforms for the background shader to `shgrp`. */ -static void add_background_uniforms(DRWShadingGroup *shgrp, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata) -{ - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - DRW_shgroup_uniform_float(shgrp, "backgroundAlpha", &stl->g_data->background_alpha, 1); - /* TODO (fclem): remove those (need to clean the GLSL files). */ - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); -} - -static void create_default_shader(int options) -{ - char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_default_frag_glsl); - - char *defines = eevee_get_defines(options); - - e_data.default_lit[options] = DRW_shader_create(e_data.vert_shader_str, NULL, frag_str, defines); - - MEM_freeN(defines); - MEM_freeN(frag_str); -} - static void eevee_init_noise_texture(void) { e_data.noise_tex = DRW_texture_create_2d(64, 64, GPU_RGBA16F, 0, (float *)blue_noise); @@ -559,8 +238,6 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const d e_data.noise_offsets[1] = offsets[1]; e_data.noise_offsets[2] = offsets[2]; - /* Attach & detach because we don't currently support multiple FB per texture, - * and this would be the case for multiple viewport. */ GPU_framebuffer_bind(fbl->update_noise_fb); DRW_draw_pass(psl->update_noise_pass); } @@ -606,94 +283,15 @@ void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_vi } void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) { const DRWContextState *draw_ctx = DRW_context_state_get(); EEVEE_PrivateData *g_data = stl->g_data; - if (!e_data.frag_shader_lib) { - /* Shaders */ - e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_common_uniforms_lib_glsl, - datatoc_bsdf_common_lib_glsl, - datatoc_bsdf_sampling_lib_glsl, - datatoc_ambient_occlusion_lib_glsl, - datatoc_raytrace_lib_glsl, - datatoc_ssr_lib_glsl, - datatoc_octahedron_lib_glsl, - datatoc_cubemap_lib_glsl, - datatoc_irradiance_lib_glsl, - datatoc_lightprobe_lib_glsl, - datatoc_ltc_lib_glsl, - datatoc_lights_lib_glsl, - /* Add one for each Closure */ - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_lit_surface_frag_glsl, - datatoc_volumetric_lib_glsl); - - e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_common_uniforms_lib_glsl, - datatoc_bsdf_common_lib_glsl, - datatoc_ambient_occlusion_lib_glsl, - datatoc_octahedron_lib_glsl, - datatoc_cubemap_lib_glsl, - datatoc_irradiance_lib_glsl, - datatoc_lightprobe_lib_glsl, - datatoc_ltc_lib_glsl, - datatoc_lights_lib_glsl, - datatoc_volumetric_lib_glsl, - datatoc_volumetric_frag_glsl); - - e_data.vert_shader_str = BLI_string_joinN( - datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl); - - e_data.vert_shadow_shader_str = BLI_string_joinN( - datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl); - - e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_background_vert_glsl); - - e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_volumetric_vert_glsl); - - e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_volumetric_geom_glsl); - - e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl, - NULL, - datatoc_default_world_frag_glsl, - datatoc_common_view_lib_glsl, - NULL); - - char *vert_str = BLI_string_joinN( - datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_prepass_vert_glsl); - - e_data.default_prepass_sh = DRW_shader_create(vert_str, NULL, datatoc_prepass_frag_glsl, NULL); - - e_data.default_prepass_clip_sh = DRW_shader_create( - vert_str, NULL, datatoc_prepass_frag_glsl, "#define CLIP_PLANES\n"); - - e_data.default_hair_prepass_sh = DRW_shader_create( - vert_str, NULL, datatoc_prepass_frag_glsl, "#define HAIR_SHADER\n"); - - e_data.default_hair_prepass_clip_sh = DRW_shader_create(vert_str, - NULL, - datatoc_prepass_frag_glsl, - "#define HAIR_SHADER\n" - "#define CLIP_PLANES\n"); - MEM_freeN(vert_str); - - e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL); + if (!e_data.util_tex) { + EEVEE_shaders_material_shaders_init(); eevee_init_util_texture(); eevee_init_noise_texture(); @@ -728,33 +326,36 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, { /* Create RenderPass UBO */ - if (sldata->renderpass_ubo[0] == NULL) { - /* EEVEE_RENDER_PASS_COMBINED */ - sldata->renderpass_data[0] = (const EEVEE_RenderPassData){ - true, true, true, true, true, false}; - /* EEVEE_RENDER_PASS_DIFFUSE_COLOR */ - sldata->renderpass_data[1] = (const EEVEE_RenderPassData){ - true, false, false, false, false, true}; - /* EEVEE_RENDER_PASS_DIFFUSE_LIGHT */ - sldata->renderpass_data[2] = (const EEVEE_RenderPassData){ - true, true, false, false, false, false}; - /* EEVEE_RENDER_PASS_SPECULAR_COLOR */ - sldata->renderpass_data[3] = (const EEVEE_RenderPassData){ - false, false, true, false, false, false}; - /* EEVEE_RENDER_PASS_SPECULAR_LIGHT */ - sldata->renderpass_data[4] = (const EEVEE_RenderPassData){ - false, false, true, true, false, false}; - /* EEVEE_RENDER_PASS_EMIT */ - sldata->renderpass_data[5] = (const EEVEE_RenderPassData){ - false, false, false, false, true, false}; - - for (int i = 0; i < MAX_MATERIAL_RENDER_PASSES_UBO; i++) { - sldata->renderpass_ubo[i] = DRW_uniformbuffer_create(sizeof(EEVEE_RenderPassData), - &sldata->renderpass_data[i]); - } + if (sldata->renderpass_ubo.combined == NULL) { + sldata->renderpass_ubo.combined = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){true, true, true, true, true, false}); + + sldata->renderpass_ubo.diff_color = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){true, false, false, false, false, true}); + + sldata->renderpass_ubo.diff_light = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){true, true, false, false, false, false}); + + sldata->renderpass_ubo.spec_color = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){false, false, true, false, false, false}); + + sldata->renderpass_ubo.spec_light = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){false, false, true, true, false, false}); + + sldata->renderpass_ubo.emit = DRW_uniformbuffer_create( + sizeof(EEVEE_RenderPassData), + &(const EEVEE_RenderPassData){false, false, false, false, true, false}); } - /* HACK: EEVEE_material_world_background_get can create a new context. This can only be + /* Used combined pass by default. */ + g_data->renderpass_ubo = sldata->renderpass_ubo.combined; + + /* HACK: EEVEE_material_get can create a new context. This can only be * done when there is no active framebuffer. We do this here otherwise * `EEVEE_renderpasses_output_init` will fail. It cannot be done in * `EEVEE_renderpasses_init` as the `e_data.vertcode` can be uninitialized. @@ -763,414 +364,12 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, struct Scene *scene = draw_ctx->scene; struct World *wo = scene->world; if (wo && wo->use_nodes) { - EEVEE_material_world_background_get(scene, wo); + EEVEE_material_get(vedata, scene, NULL, wo, VAR_WORLD_BACKGROUND); } } } } -struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, World *wo) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - const int options = VAR_WORLD_PROBE; - - GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, false); - if (mat != NULL) { - return mat; - } - return DRW_shader_create_from_world(scene, - wo, - engine, - options, - false, - e_data.vert_background_shader_str, - NULL, - e_data.frag_shader_lib, - SHADER_DEFINES "#define PROBE_CAPTURE\n", - false); -} - -struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, World *wo) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_WORLD_BACKGROUND; - - GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true); - if (mat != NULL) { - return mat; - } - return DRW_shader_create_from_world(scene, - wo, - engine, - options, - false, - e_data.vert_background_shader_str, - NULL, - e_data.frag_shader_lib, - SHADER_DEFINES "#define WORLD_BACKGROUND\n", - true); -} - -struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *wo) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_WORLD_VOLUME; - - GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true); - if (mat != NULL) { - return mat; - } - - char *defines = eevee_get_volume_defines(options); - - mat = DRW_shader_create_from_world(scene, - wo, - engine, - options, - true, - e_data.vert_volume_shader_str, - e_data.geom_volume_shader_str, - e_data.volume_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, - Material *ma, - EEVEE_Data *UNUSED(vedata), - bool use_blend, - bool use_refract) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); - SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT); - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - e_data.vert_shader_str, - NULL, - e_data.frag_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_VOLUME; - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat != NULL) { - return mat; - } - - char *defines = eevee_get_volume_defines(options); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - true, - e_data.vert_volume_shader_str, - e_data.geom_volume_shader_str, - e_data.volume_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, - Material *ma, - bool use_hashed_alpha, - bool is_shadow) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, use_hashed_alpha, VAR_MAT_HASH); - SET_FLAG_FROM_TEST(options, !use_hashed_alpha, VAR_MAT_CLIP); - SET_FLAG_FROM_TEST(options, is_shadow, VAR_MAT_SHADOW); - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - (is_shadow) ? e_data.vert_shadow_shader_str : - e_data.vert_shader_str, - NULL, - frag_str, - defines, - true); - - MEM_freeN(frag_str); - MEM_freeN(defines); - - return mat; -} - -static struct GPUMaterial *EEVEE_material_hair_depth_get(struct Scene *scene, - Material *ma, - bool use_hashed_alpha, - bool is_shadow) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - - SET_FLAG_FROM_TEST(options, use_hashed_alpha, VAR_MAT_HASH); - SET_FLAG_FROM_TEST(options, !use_hashed_alpha, VAR_MAT_CLIP); - SET_FLAG_FROM_TEST(options, is_shadow, VAR_MAT_SHADOW); - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - (is_shadow) ? e_data.vert_shadow_shader_str : - e_data.vert_shader_str, - NULL, - frag_str, - defines, - false); - - MEM_freeN(frag_str); - MEM_freeN(defines); - - return mat; -} - -struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma) -{ - const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - - GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); - if (mat) { - return mat; - } - - char *defines = eevee_get_defines(options); - - mat = DRW_shader_create_from_material(scene, - ma, - engine, - options, - false, - e_data.vert_shader_str, - NULL, - e_data.frag_shader_lib, - defines, - true); - - MEM_freeN(defines); - - return mat; -} - -/** - * Create a default shading group inside the given pass. - */ -static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - DRWPass *pass, - bool is_hair, - bool use_blend, - bool use_ssr) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); - SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - true, - true, - false, - false, - use_blend, - DEFAULT_RENDER_PASS_FLAG); - - return shgrp; -} - -/** - * Create a default shading group inside the default pass without standard uniforms. - */ -static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - Object *ob, - ParticleSystem *psys, - ModifierData *md, - bool is_hair, - bool holdout, - bool use_ssr) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH; - - EEVEE_PassList *psl = vedata->psl; - - BLI_assert(!is_hair || (ob && ((psys && md) || ob->type == OB_HAIR))); - - SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); - SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - if (psl->default_pass[options] == NULL) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->default_pass[options], state); - - /* XXX / WATCH: This creates non persistent binds for the ubos and textures. - * But it's currently OK because the following shgroups does not add any bind. - * EDIT: THIS IS NOT THE CASE FOR HAIRS !!! DUMMY!!! */ - if (!is_hair) { - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], - psl->default_pass[options]); - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - } - } - - if (is_hair) { - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, psys, md, vedata->psl->default_pass[options], e_data.default_lit[options]); - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - return shgrp; - } - else { - return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); - } -} - -static struct DRWShadingGroup *EEVEE_default_render_pass_shading_group_get( - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - bool holdout, - bool use_ssr, - DRWPass *pass, - eViewLayerEEVEEPassType render_pass_flag) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH; - - SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms( - shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag); - return shgrp; -} - -static struct DRWShadingGroup *EEVEE_default_hair_render_pass_shading_group_get( - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - Object *ob, - ParticleSystem *psys, - ModifierData *md, - bool holdout, - bool use_ssr, - DRWPass *pass, - eViewLayerEEVEEPassType render_pass_flag) -{ - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - - BLI_assert((ob && psys && md)); - - SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT); - - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); - } - - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, psys, md, pass, e_data.default_lit[options]); - add_standard_uniforms( - shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag); - return shgrp; -} - void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -1180,10 +379,17 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* Create Material Ghash */ { stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash"); + + if (sldata->material_cache == NULL) { + sldata->material_cache = BLI_memblock_create(sizeof(EeveeMaterialCache)); + } + else { + BLI_memblock_clear(sldata->material_cache, NULL); + } } { - DRW_PASS_CREATE(psl->background_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + DRW_PASS_CREATE(psl->background_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = NULL; @@ -1191,485 +397,297 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) Scene *scene = draw_ctx->scene; World *wo = scene->world; - const float *col = G_draw.block.colorBackground; - - EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->background_pass, wo, NULL); + EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->background_ps, wo, NULL); if (!grp && wo) { - col = &wo->horr; - - if (wo->use_nodes && wo->nodetree) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo); - - switch (GPU_material_status(gpumat)) { - case GPU_MAT_SUCCESS: - grp = DRW_shgroup_material_create(gpumat, psl->background_pass); - add_background_uniforms(grp, sldata, vedata); - DRW_shgroup_call(grp, geom, NULL); - break; - case GPU_MAT_QUEUED: - /* TODO Bypass probe compilation. */ - stl->g_data->queued_shaders_count++; - col = compile_col; - break; - case GPU_MAT_FAILED: - default: - col = error_col; - break; - } - } + struct GPUMaterial *gpumat = EEVEE_material_get( + vedata, scene, NULL, wo, VAR_WORLD_BACKGROUND); + + grp = DRW_shgroup_material_create(gpumat, psl->background_ps); + DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); + /* TODO (fclem): remove those (need to clean the GLSL files). */ + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_call(grp, geom, NULL); } /* Fallback if shader fails or if not using nodetree. */ if (grp == NULL) { - grp = DRW_shgroup_create(e_data.default_background, psl->background_pass); - DRW_shgroup_uniform_vec3(grp, "color", col, 1); + GPUShader *sh = EEVEE_shaders_default_background_sh_get(); + grp = DRW_shgroup_create(sh, psl->background_ps); + DRW_shgroup_uniform_vec3(grp, "color", G_draw.block.colorBackground, 1); DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); DRW_shgroup_call(grp, geom, NULL); } } - { - DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRW_PASS_CREATE(psl->depth_pass, state); - stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->depth_pass_cull, state); - stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, - psl->depth_pass_cull); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->depth_pass_clip, state); - stl->g_data->depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, - psl->depth_pass_clip); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->depth_pass_clip_cull, state); - stl->g_data->depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh, - psl->depth_pass_clip_cull); - } +#define EEVEE_PASS_CREATE(pass, state) \ + do { \ + DRW_PASS_CREATE(psl->pass##_ps, state); \ + DRW_PASS_CREATE(psl->pass##_cull_ps, state | DRW_STATE_CULL_BACK); \ + DRW_pass_link(psl->pass##_ps, psl->pass##_cull_ps); \ + } while (0) - { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->material_pass, state); - DRW_PASS_CREATE(psl->material_pass_cull, state | DRW_STATE_CULL_BACK); - } +#define EEVEE_CLIP_PASS_CREATE(pass, state) \ + do { \ + DRWState st = state | DRW_STATE_CLIP_PLANES; \ + DRW_PASS_INSTANCE_CREATE(psl->pass##_clip_ps, psl->pass##_ps, st); \ + DRW_PASS_INSTANCE_CREATE( \ + psl->pass##_clip_cull_ps, psl->pass##_cull_ps, st | DRW_STATE_CULL_BACK); \ + DRW_pass_link(psl->pass##_clip_ps, psl->pass##_clip_cull_ps); \ + } while (0) { - DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRW_PASS_CREATE(psl->refract_depth_pass, state); - stl->g_data->refract_depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, - psl->refract_depth_pass); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->refract_depth_pass_cull, state); - stl->g_data->refract_depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, - psl->refract_depth_pass_cull); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; - DRW_PASS_CREATE(psl->refract_depth_pass_clip, state); - stl->g_data->refract_depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, - psl->refract_depth_pass_clip); - - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->refract_depth_pass_clip_cull, state); - stl->g_data->refract_depth_shgrp_clip_cull = DRW_shgroup_create( - e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip_cull); - } + DRWState state_depth = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + DRWState state_shading = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; + DRWState state_sss = DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - { - DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES); - DRW_PASS_CREATE(psl->refract_pass, state); - } + EEVEE_PASS_CREATE(depth, state_depth); + EEVEE_CLIP_PASS_CREATE(depth, state_depth); - { - DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS); - DRW_PASS_CREATE(psl->sss_pass, state); - DRW_PASS_CREATE(psl->sss_pass_cull, state | DRW_STATE_CULL_BACK); - e_data.sss_count = 0; + EEVEE_PASS_CREATE(depth_refract, state_depth); + EEVEE_CLIP_PASS_CREATE(depth_refract, state_depth); + + EEVEE_PASS_CREATE(material, state_shading); + EEVEE_PASS_CREATE(material_refract, state_shading); + EEVEE_PASS_CREATE(material_sss, state_shading | state_sss); } + { + /* Renderpass accumulation. */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ADD_FULL; + /* Create an instance of each of theses passes and link them together. */ + DRWPass *passes[] = { + psl->material_ps, + psl->material_cull_ps, + psl->material_sss_ps, + psl->material_sss_cull_ps, + }; + DRWPass *first = NULL, *last = NULL; + for (int i = 0; i < ARRAY_SIZE(passes); i++) { + DRWPass *pass = DRW_pass_create_instance("Renderpass Accumulation", passes[i], state); + if (first == NULL) { + first = last = pass; + } + else { + DRW_pass_link(last, pass); + last = pass; + } + } + psl->material_accum_ps = first; + /* Same for background */ + DRW_PASS_INSTANCE_CREATE(psl->background_accum_ps, psl->background_ps, state); + } { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; DRW_PASS_CREATE(psl->transparent_pass, state); } - { DRW_PASS_CREATE(psl->update_noise_pass, DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.update_noise_sh, psl->update_noise_pass); + GPUShader *sh = EEVEE_shaders_update_noise_sh_get(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->update_noise_pass); DRW_shgroup_uniform_texture(grp, "blueNoise", e_data.noise_tex); DRW_shgroup_uniform_vec3(grp, "offsets", e_data.noise_offsets, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } +} - if (eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) { - DRWShadingGroup *shgrp; - - struct GPUBatch *sphere = DRW_cache_sphere_get(); - static float color_chrome[3] = {1.0f, 1.0f, 1.0f}; - static float color_diffuse[3] = {0.8f, 0.8f, 0.8f}; - int options = VAR_MAT_MESH | VAR_MAT_LOOKDEV; +BLI_INLINE void material_shadow(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Material *ma, + bool is_hair, + EeveeMaterialCache *emc) +{ + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_PassList *psl = vedata->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; - if (e_data.default_lit[options] == NULL) { - create_default_shader(options); + if (ma->blend_shadow != MA_BS_NONE) { + /* Shadow Pass */ + const bool use_shadow_shader = ma->use_nodes && ma->nodetree && + ELEM(ma->blend_shadow, MA_BS_CLIP, MA_BS_HASHED); + int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH; + SET_FLAG_FROM_TEST(mat_options, use_shadow_shader, VAR_MAT_HASH); + SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR); + GPUMaterial *gpumat = (use_shadow_shader) ? + EEVEE_material_get(vedata, scene, ma, NULL, mat_options) : + EEVEE_material_default_get(scene, ma, mat_options); + + /* Avoid possible confusion with depth pre-pass options. */ + int option = KEY_SHADOW; + SET_FLAG_FROM_TEST(option, is_hair, KEY_HAIR); + + /* Search for the same shaders usage in the pass. */ + struct GPUShader *sh = GPU_material_get_shader(gpumat); + void *cache_key = (char *)sh + option; + DRWShadingGroup *grp, **grp_p; + + if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) { + /* This GPUShader has already been used by another material. + * Add new shading group just after to avoid shader switching cost. */ + grp = DRW_shgroup_create_sub(*grp_p); + } + else { + *grp_p = grp = DRW_shgroup_create(sh, psl->shadow_pass); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); } - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | - DRW_STATE_CULL_BACK; - - DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state); - shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_diffuse_pass); - add_standard_uniforms(shgrp, - sldata, - vedata, - NULL, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_diffuse, 1); - DRW_shgroup_uniform_float_copy(shgrp, "metallic", 0.0f); - DRW_shgroup_uniform_float_copy(shgrp, "specular", 0.5f); - DRW_shgroup_uniform_float_copy(shgrp, "roughness", 1.0f); - DRW_shgroup_call(shgrp, sphere, NULL); - - DRW_PASS_CREATE(psl->lookdev_glossy_pass, state); - shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_glossy_pass); - add_standard_uniforms(shgrp, - sldata, - vedata, - NULL, - NULL, - true, - true, - false, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_chrome, 1); - DRW_shgroup_uniform_float_copy(shgrp, "metallic", 1.0f); - DRW_shgroup_uniform_float_copy(shgrp, "roughness", 0.0f); - DRW_shgroup_call(shgrp, sphere, NULL); - } + DRW_shgroup_add_material_resources(grp, gpumat); - { - memset(psl->material_accum_pass, 0, sizeof(psl->material_accum_pass)); - for (int pass_index = 0; pass_index < stl->g_data->render_passes_material_count; - pass_index++) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ADD_FULL; - DRW_PASS_CREATE(psl->material_accum_pass[pass_index], state); - } + emc->shadow_grp = grp; + emc->shadow_grp_p = grp_p; + } + else { + emc->shadow_grp = NULL; + emc->shadow_grp_p = NULL; } } -#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ - do { \ - if (oedata) { \ - DRW_shgroup_call_with_callback(shgrp, geom, ob, oedata); \ - } \ - else { \ - DRW_shgroup_call(shgrp, geom, ob); \ - } \ - } while (0) - -#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom, oedata) \ - do { \ - if (shgrp) { \ - ADD_SHGROUP_CALL(shgrp, ob, geom, oedata); \ - } \ - } while (0) - -typedef struct EeveeMaterialShadingGroups { - struct DRWShadingGroup *shading_grp; - struct DRWShadingGroup *depth_grp; - struct DRWShadingGroup *depth_clip_grp; - struct DRWShadingGroup *material_accum_grp[MAX_MATERIAL_RENDER_PASSES]; -} EeveeMaterialShadingGroups; - -static void material_opaque(Material *ma, - GHash *material_hash, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - struct GPUMaterial **gpumat, - struct GPUMaterial **gpumat_depth, - struct EeveeMaterialShadingGroups *shgrps, - bool holdout) +static EeveeMaterialCache material_opaque(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Material *ma, + const bool is_hair) { EEVEE_EffectsInfo *effects = vedata->stl->effects; + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_PassList *psl = vedata->psl; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - bool use_diffuse, use_glossy, use_refract; - bool store_material = true; - float *color_p = &ma->r; - float *metal_p = &ma->metallic; - float *spec_p = &ma->spec; - float *rough_p = &ma->roughness; - const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; - const bool use_gpumat = (ma->use_nodes && ma->nodetree && !holdout); + const bool do_cull = !is_hair && (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; + const bool use_gpumat = (ma->use_nodes && ma->nodetree); const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && ((effects->enabled_effects & EFFECT_REFRACT) != 0); - const bool use_translucency = ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0); - - EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma); - - if (emsg) { - memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups)); + const bool use_depth_shader = use_gpumat && ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED); - /* This will have been created already, just perform a lookup. */ - *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract) : - NULL; - *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get( - scene, ma, (ma->blend_method == MA_BM_HASHED), false) : - NULL; - return; + /* HACK: Assume the struct will never be smaller than our variations. + * This allow us to only keep one ghash and avoid bigger keys comparissons/hashing. */ + void *key = (char *)ma + is_hair; + /* Search for other material instances (sharing the same Material datablock). */ + EeveeMaterialCache **emc_p, *emc; + if (BLI_ghash_ensure_p(pd->material_hash, key, (void ***)&emc_p)) { + return **emc_p; + } + else { + *emc_p = emc = BLI_memblock_alloc(sldata->material_cache); } - emsg = MEM_callocN(sizeof(EeveeMaterialShadingGroups), "EeveeMaterialShadingGroups"); - if (use_gpumat) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - static float half = 0.5f; - - /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract); - - eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat); - - /* Alpha CLipped : Discard pixel from depth pass, then - * fail the depth test for shading. */ - if (ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED)) { - *gpumat_depth = EEVEE_material_mesh_depth_get( - scene, ma, (ma->blend_method == MA_BM_HASHED), false); - - eGPUMaterialStatus status_mat_depth = GPU_material_status(*gpumat_depth); - if (status_mat_depth != GPU_MAT_SUCCESS) { - /* Mixing both flags. If depth shader fails, show it to the user by not using - * the surface shader. */ - status_mat_surface = status_mat_depth; - } - else if (use_ssrefract) { - emsg->depth_grp = DRW_shgroup_material_create( - *gpumat_depth, (do_cull) ? psl->refract_depth_pass_cull : psl->refract_depth_pass); - emsg->depth_clip_grp = DRW_shgroup_material_create( - *gpumat_depth, - (do_cull) ? psl->refract_depth_pass_clip_cull : psl->refract_depth_pass_clip); - } - else { - emsg->depth_grp = DRW_shgroup_material_create( - *gpumat_depth, (do_cull) ? psl->depth_pass_cull : psl->depth_pass); - emsg->depth_clip_grp = DRW_shgroup_material_create( - *gpumat_depth, (do_cull) ? psl->depth_pass_clip_cull : psl->depth_pass_clip); - } + material_shadow(vedata, sldata, ma, is_hair, emc); - if (emsg->depth_grp != NULL) { - use_diffuse = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_DIFFUSE); - use_glossy = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_GLOSSY); - use_refract = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_REFRACT); - - add_standard_uniforms(emsg->depth_grp, - sldata, - vedata, - NULL, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - add_standard_uniforms(emsg->depth_clip_grp, - sldata, - vedata, - NULL, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - - if (ma->blend_method == MA_BM_CLIP) { - DRW_shgroup_uniform_float(emsg->depth_grp, "alphaThreshold", &ma->alpha_threshold, 1); - DRW_shgroup_uniform_float( - emsg->depth_clip_grp, "alphaThreshold", &ma->alpha_threshold, 1); - } - } + { + /* Depth Pass */ + int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH; + SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT); + SET_FLAG_FROM_TEST(mat_options, use_depth_shader, VAR_MAT_HASH); + SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR); + GPUMaterial *gpumat = (use_depth_shader) ? + EEVEE_material_get(vedata, scene, ma, NULL, mat_options) : + EEVEE_material_default_get(scene, ma, mat_options); + + int option = 0; + SET_FLAG_FROM_TEST(option, do_cull, KEY_CULL); + SET_FLAG_FROM_TEST(option, use_ssrefract, KEY_REFRACT); + DRWPass *depth_ps = (DRWPass *[]){ + psl->depth_ps, + psl->depth_cull_ps, + psl->depth_refract_ps, + psl->depth_refract_cull_ps, + }[option]; + /* Hair are rendered inside the non-cull pass but needs to have a separate cache key. */ + SET_FLAG_FROM_TEST(option, is_hair, KEY_HAIR); + + /* Search for the same shaders usage in the pass. */ + struct GPUShader *sh = GPU_material_get_shader(gpumat); + void *cache_key = (char *)sh + option; + DRWShadingGroup *grp, **grp_p; + + if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) { + /* This GPUShader has already been used by another material. + * Add new shading group just after to avoid shader switching cost. */ + grp = DRW_shgroup_create_sub(*grp_p); } - - switch (status_mat_surface) { - case GPU_MAT_SUCCESS: { - static int no_ssr = 0; - static int first_ssr = 1; - int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? - &first_ssr : - &no_ssr; - const bool use_sss = GPU_material_flag_get(*gpumat, GPU_MATFLAG_SSS); - use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE); - use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY); - use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT); - - emsg->shading_grp = DRW_shgroup_material_create( - *gpumat, - (use_ssrefract) ? - psl->refract_pass : - (use_sss) ? ((do_cull) ? psl->sss_pass_cull : psl->sss_pass) : - ((do_cull) ? psl->material_pass_cull : psl->material_pass)); - - add_standard_uniforms(emsg->shading_grp, - sldata, - vedata, - ssr_id, - &ma->refract_depth, - use_diffuse, - use_glossy, - use_refract, - use_ssrefract, - false, - DEFAULT_RENDER_PASS_FLAG); - - if (use_sss) { - struct GPUTexture *sss_tex_profile = NULL; - struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get( - *gpumat, stl->effects->sss_sample_count, &sss_tex_profile); - - if (sss_profile) { - /* Limit of 8 bit stencil buffer. ID 255 is refraction. */ - if (e_data.sss_count < 254) { - int sss_id = e_data.sss_count + 1; - DRW_shgroup_stencil_mask(emsg->shading_grp, sss_id); - EEVEE_subsurface_add_pass(sldata, vedata, sss_id, sss_profile); - if (use_translucency) { - EEVEE_subsurface_translucency_add_pass( - sldata, vedata, sss_id, sss_profile, sss_tex_profile); - } - e_data.sss_count++; - } - else { - /* TODO : display message. */ - printf("Error: Too many different Subsurface shader in the scene.\n"); - } - } - } - - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - emsg->material_accum_grp[render_pass_index] = DRW_shgroup_material_create( - *gpumat, psl->material_accum_pass[render_pass_index]); - add_standard_uniforms(emsg->material_accum_grp[render_pass_index], - sldata, - vedata, - ssr_id, - &ma->refract_depth, - use_diffuse, - use_glossy, - use_refract, - use_ssrefract, - false, - render_pass_flag); - } - RENDER_PASS_ITER_END(render_pass_index); - - break; - } - case GPU_MAT_QUEUED: { - stl->g_data->queued_shaders_count++; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - store_material = false; - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; + else { + *grp_p = grp = DRW_shgroup_create(sh, depth_ps); + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false); } - } - /* Fallback to default shader */ - if (emsg->shading_grp == NULL) { - bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); - emsg->shading_grp = EEVEE_default_shading_group_get( - sldata, vedata, NULL, NULL, NULL, false, holdout, use_ssr); - DRW_shgroup_uniform_vec3(emsg->shading_grp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(emsg->shading_grp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(emsg->shading_grp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(emsg->shading_grp, "roughness", rough_p, 1); - - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - DRWShadingGroup *shgrp = EEVEE_default_render_pass_shading_group_get( - sldata, - vedata, - holdout, - use_ssr, - psl->material_accum_pass[render_pass_index], - render_pass_flag); - - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - emsg->material_accum_grp[render_pass_index] = shgrp; - } - RENDER_PASS_ITER_END(render_pass_index); - } + DRW_shgroup_add_material_resources(grp, gpumat); - /* Fallback default depth prepass */ - if (emsg->depth_grp == NULL) { - if (use_ssrefract) { - emsg->depth_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_cull : - stl->g_data->refract_depth_shgrp; - emsg->depth_clip_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_clip_cull : - stl->g_data->refract_depth_shgrp_clip; + emc->depth_grp = grp; + emc->depth_grp_p = grp_p; + } + { + /* Shading Pass */ + int mat_options = VAR_MAT_MESH; + 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); + + 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; + DRWPass *shading_pass = (DRWPass *[]){ + psl->material_refract_ps, + psl->material_refract_cull_ps, + psl->material_sss_ps, + psl->material_sss_cull_ps, + psl->material_ps, + psl->material_cull_ps, + }[option]; + /* Hair are rendered inside the non-cull pass but needs to have a separate cache key */ + option = option * 2 + is_hair; + + /* Search for the same shaders usage in the pass. */ + /* HACK: Assume the struct will never be smaller than our variations. + * This allow us to only keep one ghash and avoid bigger keys comparissons/hashing. */ + BLI_assert(option <= 16); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + void *cache_key = (char *)sh + option; + DRWShadingGroup *grp, **grp_p; + + if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) { + /* This GPUShader has already been used by another material. + * Add new shading group just after to avoid shader switching cost. */ + grp = DRW_shgroup_create_sub(*grp_p); } else { - emsg->depth_grp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp; - emsg->depth_clip_grp = (do_cull) ? stl->g_data->depth_shgrp_clip_cull : - stl->g_data->depth_shgrp_clip; + *grp_p = grp = DRW_shgroup_create(sh, shading_pass); + EEVEE_material_bind_resources( + grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, false); } - } + DRW_shgroup_add_material_resources(grp, gpumat); - memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups)); - if (store_material) { - BLI_ghash_insert(material_hash, ma, emsg); - } - else { - MEM_freeN(emsg); + if (use_sss) { + EEVEE_subsurface_add_pass(sldata, vedata, ma, grp, gpumat); + } + + emc->shading_grp = grp; + emc->shading_grp_p = grp_p; + emc->shading_gpumat = gpumat; } + return *emc; } -static void material_transparent(Material *ma, - EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - struct GPUMaterial **gpumat, - struct EeveeMaterialShadingGroups *shgrps) +static EeveeMaterialCache material_transparent(EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Material *ma) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; + EeveeMaterialCache emc = {0}; const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; const bool use_gpumat = ma->use_nodes && ma->nodetree; const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && - ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0); - const float *color_p = &ma->r; - const float *metal_p = &ma->metallic; - const float *spec_p = &ma->spec; - const float *rough_p = &ma->roughness; - + ((effects->enabled_effects & EFFECT_REFRACT) != 0); const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0); DRWState cur_state; @@ -1677,81 +695,53 @@ static void material_transparent(Material *ma, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_CUSTOM); - /* Depth prepass */ + material_shadow(vedata, sldata, ma, false, &emc); + if (use_prepass) { - shgrps->depth_grp = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass); + /* Depth prepass */ + int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH; + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); + struct GPUShader *sh = GPU_material_get_shader(gpumat); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->transparent_pass); + + EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, true); + DRW_shgroup_add_material_resources(grp, gpumat); cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; - DRW_shgroup_state_disable(shgrps->depth_grp, all_state); - DRW_shgroup_state_enable(shgrps->depth_grp, cur_state); + DRW_shgroup_state_disable(grp, all_state); + DRW_shgroup_state_enable(grp, cur_state); + + emc.depth_grp = grp; } + { + /* Shading */ + int ssr_id = -1; /* TODO transparent SSR */ + int mat_options = VAR_MAT_MESH | VAR_MAT_BLEND; + SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT); + GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); - if (use_gpumat) { - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - static float half = 0.5f; + DRWShadingGroup *grp = DRW_shgroup_create(GPU_material_get_shader(gpumat), + psl->transparent_pass); - /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, use_ssrefract); - - switch (GPU_material_status(*gpumat)) { - case GPU_MAT_SUCCESS: { - static int ssr_id = -1; /* TODO transparent SSR */ - - shgrps->shading_grp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); - - bool use_blend = true; - 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); - - add_standard_uniforms(shgrps->shading_grp, - sldata, - vedata, - &ssr_id, - &ma->refract_depth, - use_diffuse, - use_glossy, - use_refract, - use_ssrefract, - use_blend, - DEFAULT_RENDER_PASS_FLAG); - break; - } - case GPU_MAT_QUEUED: { - /* TODO Bypass probe compilation. */ - stl->g_data->queued_shaders_count++; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; - } - } + EEVEE_material_bind_resources( + grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, true); + DRW_shgroup_add_material_resources(grp, gpumat); - /* Fallback to default shader */ - if (shgrps->shading_grp == NULL) { - shgrps->shading_grp = EEVEE_default_shading_group_create( - sldata, vedata, psl->transparent_pass, false, true, false); - DRW_shgroup_uniform_vec3(shgrps->shading_grp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrps->shading_grp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrps->shading_grp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrps->shading_grp, "roughness", rough_p, 1); - } + cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; + cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL; + cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; - cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; - cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL; - cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; + /* Disable other blend modes and use the one we want. */ + DRW_shgroup_state_disable(grp, all_state); + DRW_shgroup_state_enable(grp, cur_state); - /* Disable other blend modes and use the one we want. */ - DRW_shgroup_state_disable(shgrps->shading_grp, all_state); - DRW_shgroup_state_enable(shgrps->shading_grp, cur_state); + emc.shading_grp = grp; + emc.shading_gpumat = gpumat; + } + return emc; } /* Return correct material or empty default material if slot is empty. */ @@ -1766,12 +756,35 @@ BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot, bool holdou ma = BKE_material_default_volume(); } else { - ma = BKE_material_default_empty(); + ma = BKE_material_default_surface(); } } return ma; } +BLI_INLINE EeveeMaterialCache eevee_material_cache_get( + EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, int slot, bool is_hair) +{ + const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; + EeveeMaterialCache matcache; + Material *ma = eevee_object_material_get(ob, slot, holdout); + switch (ma->blend_method) { + case MA_BM_BLEND: + if (!is_hair) { + matcache = material_transparent(vedata, sldata, ma); + break; + } + ATTR_FALLTHROUGH; + case MA_BM_SOLID: + case MA_BM_CLIP: + case MA_BM_HASHED: + default: + matcache = material_opaque(vedata, sldata, ma, is_hair); + break; + } + return matcache; +} + static void eevee_hair_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, @@ -1780,240 +793,49 @@ static void eevee_hair_cache_populate(EEVEE_Data *vedata, int matnr, bool *cast_shadow) { - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; - - DRWShadingGroup *shgrp = NULL; - Material *ma = eevee_object_material_get(ob, matnr - 1, holdout); - const bool use_gpumat = ma->use_nodes && ma->nodetree && !holdout; - const bool use_alpha_hash = (ma->blend_method == MA_BM_HASHED); - const bool use_alpha_clip = (ma->blend_method == MA_BM_CLIP); - const bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0); - - GPUMaterial *gpumat = use_gpumat ? EEVEE_material_hair_get(scene, ma) : NULL; - eGPUMaterialStatus status_mat_surface = gpumat ? GPU_material_status(gpumat) : GPU_MAT_SUCCESS; - - float *color_p = &ma->r; - float *metal_p = &ma->metallic; - float *spec_p = &ma->spec; - float *rough_p = &ma->roughness; + EeveeMaterialCache matcache = eevee_material_cache_get(vedata, sldata, ob, matnr - 1, true); - /* Depth prepass. */ - if (use_gpumat && (use_alpha_clip || use_alpha_hash)) { - GPUMaterial *gpumat_depth = EEVEE_material_hair_depth_get(scene, ma, use_alpha_hash, false); - - eGPUMaterialStatus status_mat_depth = GPU_material_status(gpumat_depth); - - if (status_mat_depth != GPU_MAT_SUCCESS) { - /* Mixing both flags. If depth shader fails, show it to the user by not using - * the surface shader. */ - status_mat_surface = status_mat_depth; - } - else { - const bool use_diffuse = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_DIFFUSE); - const bool use_glossy = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_GLOSSY); - const bool use_refract = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_REFRACT); - - for (int i = 0; i < 2; i++) { - DRWPass *pass = (i == 0) ? psl->depth_pass : psl->depth_pass_clip; - - shgrp = DRW_shgroup_material_hair_create(ob, psys, md, pass, gpumat_depth); - - add_standard_uniforms(shgrp, - sldata, - vedata, - NULL, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - - /* Unfortunately needed for correctness but not 99% of the time not needed. - * TODO detect when needed? */ - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - - if (use_alpha_clip) { - DRW_shgroup_uniform_float(shgrp, "alphaThreshold", &ma->alpha_threshold, 1); - } - } - } + if (matcache.depth_grp) { + *matcache.depth_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.depth_grp); } - - /* Fallback to default shader */ - if (shgrp == NULL) { - for (int i = 0; i < 2; i++) { - DRWPass *depth_pass = (i == 0) ? psl->depth_pass : psl->depth_pass_clip; - struct GPUShader *depth_sh = (i == 0) ? e_data.default_hair_prepass_sh : - e_data.default_hair_prepass_clip_sh; - DRW_shgroup_hair_create(ob, psys, md, depth_pass, depth_sh); - } + if (matcache.shading_grp) { + *matcache.shading_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shading_grp); } - - shgrp = NULL; - - if (gpumat) { - static int ssr_id; - ssr_id = (use_ssr) ? 1 : -1; - static float half = 0.5f; - static float error_col[3] = {1.0f, 0.0f, 1.0f}; - static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - - switch (status_mat_surface) { - case GPU_MAT_SUCCESS: { - 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); - - shgrp = DRW_shgroup_material_hair_create(ob, psys, md, psl->material_pass, gpumat); - - if (!use_diffuse && !use_glossy && !use_refract) { - /* HACK: Small hack to avoid issue when utilTex is needed for - * world_normals_get and none of the bsdfs are present. - * This binds utilTex even if not needed. */ - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - } - - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - DEFAULT_RENDER_PASS_FLAG); - - /* Add the hair to all the render_passes that are enabled */ - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - shgrp = DRW_shgroup_material_hair_create( - ob, psys, md, psl->material_accum_pass[render_pass_index], gpumat); - if (!use_diffuse && !use_glossy && !use_refract) { - /* Small hack to avoid issue when utilTex is needed for - * world_normals_get and none of the bsdfs that need it are present. - * This binds `utilTex` even if not needed. */ - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - } - - add_standard_uniforms(shgrp, - sldata, - vedata, - &ssr_id, - NULL, - use_diffuse, - use_glossy, - use_refract, - false, - false, - render_pass_flag); - } - RENDER_PASS_ITER_END(render_pass_index); - - break; - } - case GPU_MAT_QUEUED: { - stl->g_data->queued_shaders_count++; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; - } + if (matcache.shadow_grp) { + *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shadow_grp); + *cast_shadow = true; } +} - /* Fallback to default shader */ - if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get(sldata, vedata, ob, psys, md, true, holdout, use_ssr); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - - RENDER_PASS_ITER_BEGIN (stl->g_data->render_passes, render_pass_index, render_pass_flag) { - shgrp = EEVEE_default_hair_render_pass_shading_group_get( - sldata, - vedata, - ob, - psys, - md, - holdout, - use_ssr, - psl->material_accum_pass[render_pass_index], - render_pass_flag); - - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - } - RENDER_PASS_ITER_END(render_pass_index); - } +#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ + do { \ + if (oedata) { \ + DRW_shgroup_call_with_callback(shgrp, geom, ob, oedata); \ + } \ + else { \ + DRW_shgroup_call(shgrp, geom, ob); \ + } \ + } while (0) - /* Shadows */ - char blend_shadow = use_gpumat ? ma->blend_shadow : MA_BS_SOLID; - const bool shadow_alpha_hash = (blend_shadow == MA_BS_HASHED); - switch (blend_shadow) { - case MA_BS_SOLID: - DRW_shgroup_hair_create(ob, psys, md, psl->shadow_pass, e_data.default_hair_prepass_sh); - *cast_shadow = true; - break; - case MA_BS_CLIP: - case MA_BS_HASHED: - gpumat = EEVEE_material_hair_depth_get(scene, ma, shadow_alpha_hash, true); - shgrp = DRW_shgroup_material_hair_create(ob, psys, md, psl->shadow_pass, gpumat); - /* Unfortunately needed for correctness but not 99% of the time not needed. - * TODO detect when needed? */ - DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block( - shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); - DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - - if (!shadow_alpha_hash) { - DRW_shgroup_uniform_float(shgrp, "alphaThreshold", &ma->alpha_threshold, 1); - } - *cast_shadow = true; - break; - case MA_BS_NONE: - default: - break; +#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom, oedata) \ + do { \ + if (shgrp) { \ + ADD_SHGROUP_CALL(shgrp, ob, geom, oedata); \ + } \ + } while (0) + +#define MATCACHE_AS_ARRAY(matcache, member, materials_len, output_array) \ + for (int i = 0; i < materials_len; i++) { \ + output_array[i] = matcache[i].member; \ } -} void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, bool *cast_shadow) { - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - GHash *material_hash = stl->g_data->material_hash; - const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0; bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && !DRW_state_is_image_render(); @@ -2022,139 +844,64 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { const int materials_len = DRW_cache_object_material_count_get(ob); - struct EeveeMaterialShadingGroups *shgrps_array = BLI_array_alloca(shgrps_array, - materials_len); - - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len); - struct Material **ma_array = BLI_array_alloca(ma_array, materials_len); - + EeveeMaterialCache *matcache = BLI_array_alloca(matcache, materials_len); for (int i = 0; i < materials_len; i++) { - ma_array[i] = eevee_object_material_get(ob, i, holdout); - memset(&shgrps_array[i], 0, sizeof(EeveeMaterialShadingGroups)); - gpumat_array[i] = NULL; - gpumat_depth_array[i] = NULL; - - switch (ma_array[i]->blend_method) { - case MA_BM_SOLID: - case MA_BM_CLIP: - case MA_BM_HASHED: - material_opaque(ma_array[i], - material_hash, - sldata, - vedata, - &gpumat_array[i], - &gpumat_depth_array[i], - &shgrps_array[i], - holdout); - break; - case MA_BM_BLEND: - material_transparent(ma_array[i], sldata, vedata, &gpumat_array[i], &shgrps_array[i]); - break; - default: - BLI_assert(0); - break; - } + matcache[i] = eevee_material_cache_get(vedata, sldata, ob, i, false); } /* Only support single volume material for now. */ /* XXX We rely on the previously compiled surface shader * to know if the material has a "volume nodetree". */ - bool use_volume_material = (gpumat_array[0] && - GPU_material_has_volume_output(gpumat_array[0])); + bool use_volume_material = (matcache[0].shading_gpumat && + GPU_material_has_volume_output(matcache[0].shading_gpumat)); if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) { - /* Get per-material split surface */ - struct GPUBatch **mat_geom = NULL; - - if (!use_sculpt_pbvh) { - mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); - } - if (use_sculpt_pbvh) { - struct DRWShadingGroup **sculpt_shgrps_array = BLI_array_alloca(sculpt_shgrps_array, - materials_len); - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].shading_grp; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); + struct DRWShadingGroup **shgrps_array = BLI_array_alloca(shgrps_array, materials_len); - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].depth_grp; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].depth_clip_grp; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); + MATCACHE_AS_ARRAY(matcache, shading_grp, materials_len, shgrps_array); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); - for (int renderpass_index = 0; - renderpass_index < stl->g_data->render_passes_material_count; - renderpass_index++) { - for (int i = 0; i < materials_len; i++) { - sculpt_shgrps_array[i] = shgrps_array[i].material_accum_grp[renderpass_index]; - } - DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, materials_len, ob); - } + MATCACHE_AS_ARRAY(matcache, depth_grp, materials_len, shgrps_array); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); - /* TODO(fclem): Support shadows in sculpt mode. */ + MATCACHE_AS_ARRAY(matcache, shadow_grp, materials_len, shgrps_array); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); } - else if (mat_geom) { - for (int i = 0; i < materials_len; i++) { - if (mat_geom[i] == NULL) { - continue; - } + else { + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + MATCACHE_AS_ARRAY(matcache, shading_gpumat, materials_len, gpumat_array); + /* Get per-material split surface */ + struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get( + ob, gpumat_array, materials_len); - /* Do not render surface if we are rendering a volume object - * and do not have a surface closure. */ - if (use_volume_material && - (gpumat_array[i] && !GPU_material_has_surface_output(gpumat_array[i]))) { - continue; - } + if (mat_geom) { + for (int i = 0; i < materials_len; i++) { + if (mat_geom[i] == NULL) { + continue; + } - /* XXX TODO rewrite this to include the dupli objects. - * This means we cannot exclude dupli objects from reflections!!! */ - EEVEE_ObjectEngineData *oedata = NULL; - if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { - oedata = EEVEE_object_data_ensure(ob); - oedata->ob = ob; - oedata->test_data = &sldata->probes->vis_data; - } - EeveeMaterialShadingGroups *shgrps = &shgrps_array[i]; - ADD_SHGROUP_CALL(shgrps->shading_grp, ob, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrps->depth_grp, ob, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrps->depth_clip_grp, ob, mat_geom[i], oedata); - for (int renderpass_index = 0; - renderpass_index < stl->g_data->render_passes_material_count; - renderpass_index++) { - ADD_SHGROUP_CALL_SAFE( - shgrps->material_accum_grp[renderpass_index], ob, mat_geom[i], oedata); - } + /* Do not render surface if we are rendering a volume object + * and do not have a surface closure. */ + if (use_volume_material && + (gpumat_array[i] && !GPU_material_has_surface_output(gpumat_array[i]))) { + continue; + } - /* Shadow Pass */ - struct GPUMaterial *gpumat; - const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree); - char blend_shadow = use_gpumat ? ma_array[i]->blend_shadow : MA_BS_SOLID; - switch (blend_shadow) { - case MA_BS_SOLID: - EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob); - *cast_shadow = true; - break; - case MA_BS_CLIP: - gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true); - EEVEE_shadows_caster_material_add( - sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold); - *cast_shadow = true; - break; - case MA_BS_HASHED: - gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true); - EEVEE_shadows_caster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL); - *cast_shadow = true; - break; - case MA_BS_NONE: - default: - break; + /* XXX TODO rewrite this to include the dupli objects. + * This means we cannot exclude dupli objects from reflections!!! */ + EEVEE_ObjectEngineData *oedata = NULL; + if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { + oedata = EEVEE_object_data_ensure(ob); + oedata->ob = ob; + oedata->test_data = &sldata->probes->vis_data; + } + + ADD_SHGROUP_CALL(matcache[i].shading_grp, ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(matcache[i].depth_grp, ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(matcache[i].shadow_grp, ob, mat_geom[i], oedata); + *cast_shadow = (matcache[i].shadow_grp != NULL); } } } @@ -2205,11 +952,12 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata, void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_EffectsInfo *effects = vedata->stl->effects; - BLI_ghash_free(stl->g_data->material_hash, NULL, MEM_freeN); + BLI_ghash_free(pd->material_hash, NULL, NULL); - SET_FLAG_FROM_TEST(stl->effects->enabled_effects, e_data.sss_count > 0, EFFECT_SSS); + SET_FLAG_FROM_TEST(effects->enabled_effects, effects->sss_surface_count > 0, EFFECT_SSS); /* TODO(fclem) this is not really clean. Init should not be done in cache finish. */ EEVEE_subsurface_draw_init(sldata, vedata); @@ -2217,38 +965,10 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat void EEVEE_materials_free(void) { - for (int i = 0; i < VAR_MAT_MAX; i++) { - DRW_SHADER_FREE_SAFE(e_data.default_lit[i]); - } - MEM_SAFE_FREE(e_data.frag_shader_lib); - MEM_SAFE_FREE(e_data.vert_shader_str); - MEM_SAFE_FREE(e_data.vert_shadow_shader_str); - MEM_SAFE_FREE(e_data.vert_background_shader_str); - MEM_SAFE_FREE(e_data.vert_volume_shader_str); - MEM_SAFE_FREE(e_data.geom_volume_shader_str); - MEM_SAFE_FREE(e_data.volume_shader_lib); - DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh); - DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh); - DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh); - DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh); - DRW_SHADER_FREE_SAFE(e_data.default_background); - DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_TEXTURE_FREE_SAFE(e_data.util_tex); DRW_TEXTURE_FREE_SAFE(e_data.noise_tex); } -void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_PassList *psl) -{ - for (int i = 0; i < VAR_MAT_MAX; i++) { - if (psl->default_pass[i]) { - DRW_draw_pass(psl->default_pass[i]); - } - } - - DRW_draw_pass(psl->material_pass); - DRW_draw_pass(psl->material_pass_cull); -} - /* -------------------------------------------------------------------- */ /** \name Render Passes @@ -2256,172 +976,140 @@ void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Pass void EEVEE_material_renderpasses_init(EEVEE_Data *vedata) { - EEVEE_StorageList *stl = vedata->stl; - EEVEE_PrivateData *g_data = stl->g_data; + EEVEE_PrivateData *pd = vedata->stl->g_data; /* For diffuse and glossy we calculate the final light + color buffer where we extract the * light from by dividing by the color buffer. When one the light is requested we also tag * the color buffer to do the extraction. */ - if (g_data->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { - g_data->render_passes |= EEVEE_RENDER_PASS_DIFFUSE_COLOR; + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + pd->render_passes |= EEVEE_RENDER_PASS_DIFFUSE_COLOR; } - if (g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { - g_data->render_passes |= EEVEE_RENDER_PASS_SPECULAR_COLOR; + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + pd->render_passes |= EEVEE_RENDER_PASS_SPECULAR_COLOR; } +} - /* Calculate the number of material based render passes */ - uint num_render_passes = count_bits_i(stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL); - if ((num_render_passes != 0 && stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) == - 0) { - num_render_passes += 1; +static void material_renderpass_init(EEVEE_FramebufferList *fbl, + GPUTexture **output_tx, + const eGPUTextureFormat format, + const bool do_clear) +{ + DRW_texture_ensure_fullscreen_2d(output_tx, format, 0); + /* Clear texture. */ + if (do_clear) { + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + /* TODO(fclem) replace by GPU_texture_clear once it is fast. */ + GPU_framebuffer_texture_attach(fbl->material_accum_fb, *output_tx, 0, 0); + GPU_framebuffer_bind(fbl->material_accum_fb); + GPU_framebuffer_clear_color(fbl->material_accum_fb, clear); + GPU_framebuffer_bind(fbl->main_fb); + GPU_framebuffer_texture_detach(fbl->material_accum_fb, *output_tx); } - stl->g_data->render_passes_material_count = num_render_passes; } void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples) { - const DRWContextState *draw_ctx = DRW_context_state_get(); EEVEE_FramebufferList *fbl = vedata->fbl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; - EEVEE_PassList *psl = vedata->psl; EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_PrivateData *pd = stl->g_data; - float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + /* Should be enough precision for many samples. */ + const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F; + const bool do_clear = DRW_state_is_image_render() || (effects->taa_current_sample == 1); /* Create FrameBuffer. */ + GPU_framebuffer_ensure_config(&fbl->material_accum_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); - /* Should be enough precision for many samples. */ - const eGPUTextureFormat texture_format_material_accum = (tot_samples > 128) ? GPU_RGBA32F : - GPU_RGBA16F; - const eViewLayerEEVEEPassType render_passes = stl->g_data->render_passes & - EEVEE_RENDERPASSES_MATERIAL; - if (render_passes != 0) { - GPU_framebuffer_ensure_config(&fbl->material_accum_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); - int render_pass_index = ((render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) != 0) ? 0 : 1; - for (int bit = 0; bit < 32; bit++) { - eViewLayerEEVEEPassType bitflag = (1 << bit); - if ((render_passes & bitflag) != 0) { - - DRW_texture_ensure_fullscreen_2d( - &txl->material_accum[render_pass_index], texture_format_material_accum, 0); - - /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { - GPU_framebuffer_texture_attach( - fbl->material_accum_fb, txl->material_accum[render_pass_index], 0, 0); - GPU_framebuffer_bind(fbl->material_accum_fb); - GPU_framebuffer_clear_color(fbl->material_accum_fb, clear); - GPU_framebuffer_bind(fbl->main_fb); - GPU_framebuffer_texture_detach(fbl->material_accum_fb, - txl->material_accum[render_pass_index]); - } - render_pass_index++; - } - } + if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { + material_renderpass_init(fbl, &txl->env_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) { + material_renderpass_init(fbl, &txl->emit_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) { + material_renderpass_init(fbl, &txl->diff_color_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + material_renderpass_init(fbl, &txl->diff_light_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) { + material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear); + } + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear); - if ((render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) && - (effects->enabled_effects & EFFECT_SSR)) { + if (effects->enabled_effects & EFFECT_SSR) { EEVEE_reflection_output_init(sldata, vedata, tot_samples); } + } +} - if (render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { - Scene *scene = draw_ctx->scene; - World *wo = scene->world; +static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl, + DRWPass *renderpass, + EEVEE_PrivateData *pd, + GPUTexture *output_tx, + struct GPUUniformBuffer *renderpass_option_ubo) +{ + GPU_framebuffer_texture_attach(fbl->material_accum_fb, output_tx, 0, 0); + GPU_framebuffer_bind(fbl->material_accum_fb); - if (wo && wo->use_nodes && wo->nodetree) { - struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo); - if (GPU_material_status(gpumat) == GPU_MAT_SUCCESS) { - DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->material_accum_pass[0]); - add_background_uniforms(grp, sldata, vedata); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - } - } - } + pd->renderpass_ubo = renderpass_option_ubo; + DRW_draw_pass(renderpass); + + GPU_framebuffer_texture_detach(fbl->material_accum_fb, output_tx); } void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *pd = vedata->stl->g_data; + EEVEE_EffectsInfo *effects = vedata->stl->effects; EEVEE_TextureList *txl = vedata->txl; if (fbl->material_accum_fb != NULL) { - for (int renderpass_index = 0; renderpass_index < stl->g_data->render_passes_material_count; - renderpass_index++) { - if (txl->material_accum[renderpass_index] != NULL) { - GPU_framebuffer_texture_attach( - fbl->material_accum_fb, txl->material_accum[renderpass_index], 0, 0); - GPU_framebuffer_bind(fbl->material_accum_fb); - DRW_draw_pass(psl->material_accum_pass[renderpass_index]); - GPU_framebuffer_bind(fbl->main_fb); - GPU_framebuffer_texture_detach(fbl->material_accum_fb, - txl->material_accum[renderpass_index]); - } + DRWPass *material_accum_ps = psl->material_accum_ps; + if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { + material_renderpass_accumulate( + fbl, psl->background_accum_ps, pd, txl->env_accum, sldata->renderpass_ubo.combined); } - if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) && - (stl->effects->enabled_effects & EFFECT_SSR)) { - EEVEE_reflection_output_accumulate(sldata, vedata); + if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->emit_accum, sldata->renderpass_ubo.emit); } - } -} - -int EEVEE_material_output_pass_index_get(EEVEE_ViewLayerData *UNUSED(sldata), - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type) -{ - EEVEE_StorageList *stl = vedata->stl; - - BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL) != 0); - BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL & renderpass_type) != 0); - - /* pass_index 0 is reserved for the environment pass. */ - if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT & renderpass_type) != 0) { - return 0; - } - - /* pass_index 0 is reserved for the environment pass. Other passes start from index 1 */ - int index = 1; - eViewLayerEEVEEPassType active_material_passes = stl->g_data->render_passes & - EEVEE_RENDERPASSES_MATERIAL & - ~EEVEE_RENDER_PASS_ENVIRONMENT; + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->diff_color_accum, sldata->renderpass_ubo.diff_color); + } + if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->diff_light_accum, sldata->renderpass_ubo.diff_light); - for (int bitshift = 0; bitshift < 32; bitshift++) { - eViewLayerEEVEEPassType pass_flag = (1 << bitshift); - if (pass_flag == renderpass_type) { - break; + if (effects->enabled_effects & EFFECT_SSS) { + EEVEE_subsurface_output_accumulate(sldata, vedata); + } } - if (active_material_passes & pass_flag) { - index++; + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->spec_color_accum, sldata->renderpass_ubo.spec_color); } - } + if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { + material_renderpass_accumulate( + fbl, material_accum_ps, pd, txl->spec_light_accum, sldata->renderpass_ubo.spec_light); - return index; -} + if (effects->enabled_effects & EFFECT_SSR) { + EEVEE_reflection_output_accumulate(sldata, vedata); + } + } -/* Get the pass index that contains the color pass for the given renderpass_type. */ -int EEVEE_material_output_color_pass_index_get(EEVEE_ViewLayerData *sldata, - EEVEE_Data *vedata, - eViewLayerEEVEEPassType renderpass_type) -{ - BLI_assert( - ELEM(renderpass_type, EEVEE_RENDER_PASS_DIFFUSE_LIGHT, EEVEE_RENDER_PASS_SPECULAR_LIGHT)); - eViewLayerEEVEEPassType color_pass_type; - switch (renderpass_type) { - case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: - color_pass_type = EEVEE_RENDER_PASS_DIFFUSE_COLOR; - break; - case EEVEE_RENDER_PASS_SPECULAR_LIGHT: - color_pass_type = EEVEE_RENDER_PASS_SPECULAR_COLOR; - break; - default: - color_pass_type = 0; - BLI_assert(false); + /* Restore default. */ + pd->renderpass_ubo = sldata->renderpass_ubo.combined; + GPU_framebuffer_bind(fbl->main_fb); } - return EEVEE_material_output_pass_index_get(sldata, vedata, color_pass_type); } + /* \} */ |