Eevee: Update to support shader deferred compilation.

World probe is tagged to refresh when it it's shader is updated.
Probes are recomputed only after all meshes shaders have been compiled.
This commit is contained in:
Clément Foucault 2018-03-06 02:19:28 +01:00
parent 2faa809ea6
commit f8b63b564d
5 changed files with 147 additions and 88 deletions

View File

@ -100,7 +100,7 @@ static void eevee_cache_init(void *vedata)
EEVEE_effects_cache_init(sldata, vedata);
EEVEE_lightprobes_cache_init(sldata, vedata);
EEVEE_lights_cache_init(sldata, vedata);
EEVEE_materials_cache_init(vedata);
EEVEE_materials_cache_init(sldata, vedata);
EEVEE_motion_blur_cache_init(sldata, vedata);
EEVEE_occlusion_cache_init(sldata, vedata);
EEVEE_screen_raytrace_cache_init(sldata, vedata);

View File

@ -85,8 +85,6 @@ static struct {
struct Gwn_VertFormat *format_probe_display_cube;
struct Gwn_VertFormat *format_probe_display_planar;
int update_world;
} e_data = {NULL}; /* Engine data */
extern char datatoc_background_vert_glsl[];
@ -304,6 +302,9 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL);
}
/* Only start doing probes if all materials have finished compiling. */
sldata->probes->all_materials_updated = true;
common_data->spec_toggle = true;
common_data->ssr_toggle = true;
common_data->sss_toggle = true;
@ -334,7 +335,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
}
if (update_all) {
e_data.update_world |= PROBE_UPDATE_ALL;
sldata->probes->update_world |= PROBE_UPDATE_ALL;
sldata->probes->updated_bounce = 0;
sldata->probes->grid_initialized = false;
}
@ -395,34 +396,50 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
float *col = ts.colorBackground;
if (wo) {
col = &wo->horr;
if (wo->update_flag != 0 || pinfo->prev_world != wo) {
e_data.update_world |= PROBE_UPDATE_ALL;
pinfo->updated_bounce = 0;
pinfo->grid_initialized = false;
}
wo->update_flag = 0;
bool wo_sh_compiled = true;
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_lightprobe_get(scene, wo);
grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
GPUMaterialStatus status = GPU_material_status(gpumat);
if (grp) {
DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
DRW_shgroup_call_add(grp, geom, NULL);
}
else {
/* Shader failed : pink background */
static float pink[3] = {1.0f, 0.0f, 1.0f};
col = pink;
switch (status) {
case GPU_MAT_SUCCESS:
grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
DRW_shgroup_call_add(grp, geom, NULL);
wo_sh_compiled = true;
break;
case GPU_MAT_QUEUED:
pinfo->all_materials_updated = false;
wo_sh_compiled = false;
/* TODO Bypass probe compilation. */
col = compile_col;
break;
case GPU_MAT_FAILED:
default:
wo_sh_compiled = true;
col = error_col;
break;
}
}
pinfo->prev_world = wo;
if (wo->update_flag != 0 || pinfo->prev_world != wo || pinfo->prev_wo_sh_compiled != wo_sh_compiled) {
pinfo->update_world |= PROBE_UPDATE_ALL;
pinfo->updated_bounce = 0;
pinfo->grid_initialized = false;
pinfo->prev_wo_sh_compiled = wo_sh_compiled;
pinfo->prev_world = wo;
}
wo->update_flag = 0;
}
else if (pinfo->prev_world) {
pinfo->prev_wo_sh_compiled = false;
pinfo->prev_world = NULL;
e_data.update_world |= PROBE_UPDATE_ALL;
pinfo->update_world |= PROBE_UPDATE_ALL;
pinfo->updated_bounce = 0;
pinfo->grid_initialized = false;
}
@ -584,7 +601,7 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
}
}
if (e_data.update_world) {
if (pinfo->update_world) {
ped->need_update = true;
ped->updated_cells = 0;
ped->updated_lvl = 0;
@ -899,7 +916,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
}
/* Tag probes to refresh */
e_data.update_world |= PROBE_UPDATE_CUBE;
pinfo->update_world |= PROBE_UPDATE_CUBE;
common_data->prb_num_render_cube = 0;
pinfo->cache_num_cube = pinfo->num_cube;
@ -935,7 +952,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
common_data->prb_num_render_grid = 0;
pinfo->updated_bounce = 0;
pinfo->grid_initialized = false;
e_data.update_world |= PROBE_UPDATE_GRID;
pinfo->update_world |= PROBE_UPDATE_GRID;
for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_PROBE); i++) {
EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
@ -1372,14 +1389,15 @@ static void lightprobe_cell_world_location_get(EEVEE_LightGrid *egrid, float loc
static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
EEVEE_PassList *psl = vedata->psl;
render_world_to_probe(sldata, psl);
if (e_data.update_world & PROBE_UPDATE_CUBE) {
if (pinfo->update_world & PROBE_UPDATE_CUBE) {
glossy_filter_probe(sldata, vedata, psl, 0, 1.0);
common_data->prb_num_render_cube = 1;
}
if (e_data.update_world & PROBE_UPDATE_GRID) {
if (pinfo->update_world & PROBE_UPDATE_GRID) {
diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0, 1.0);
SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
DRW_framebuffer_texture_detach(sldata->probe_pool);
@ -1389,7 +1407,7 @@ static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
common_data->prb_num_render_grid = 1;
}
e_data.update_world = 0;
pinfo->update_world = 0;
DRW_viewport_request_redraw();
}
@ -1664,6 +1682,7 @@ bool EEVEE_lightprobes_all_probes_ready(EEVEE_ViewLayerData *sldata, EEVEE_Data
void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
/* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
common_data->spec_toggle = false;
@ -1677,10 +1696,10 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
common_data->ao_dist = 0.0f;
/* Render world in priority */
if (e_data.update_world) {
if (pinfo->update_world) {
lightprobes_refresh_world(sldata, vedata);
}
else if (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false) {
else if (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false && pinfo->all_materials_updated) {
lightprobes_refresh_all_no_world(sldata, vedata);
}

View File

@ -856,7 +856,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(
return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
}
void EEVEE_materials_cache_init(EEVEE_Data *vedata)
void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
@ -894,6 +894,7 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
DRW_shgroup_call_add(grp, geom, NULL);
break;
case GPU_MAT_QUEUED:
sldata->probes->all_materials_updated = false;
/* TODO Bypass probe compilation. */
col = compile_col;
break;
@ -1042,60 +1043,29 @@ static void material_opaque(
}
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, false, use_refract,
use_sss, use_translucency, linfo->shadow_method);
*shgrp = DRW_shgroup_material_create(*gpumat,
(use_refract) ? psl->refract_pass :
(use_sss) ? psl->sss_pass : psl->material_pass);
if (*shgrp) {
static int no_ssr = -1;
static int first_ssr = 1;
int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_refract) ? &first_ssr : &no_ssr;
add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false);
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) {
if (use_translucency) {
DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile);
DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile);
}
/* Limit of 8 bit stencil buffer. ID 255 is refraction. */
if (e_data.sss_count < 254) {
DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1);
EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile);
e_data.sss_count++;
}
else {
/* TODO : display message. */
printf("Error: Too many different Subsurface shader in the scene.\n");
}
}
}
}
else {
/* Shader failed : pink color */
static float col[3] = {1.0f, 0.0f, 1.0f};
static float half = 0.5f;
color_p = col;
metal_p = spec_p = rough_p = &half;
}
GPUMaterialStatus 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);
(ma->blend_method == MA_BM_HASHED), false);
if (use_refract) {
GPUMaterialStatus 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_refract) {
*shgrp_depth = DRW_shgroup_material_create(*gpumat_depth, (do_cull) ? psl->refract_depth_pass_cull : psl->refract_depth_pass);
*shgrp_depth_clip = DRW_shgroup_material_create(*gpumat_depth, (do_cull) ? psl->refract_depth_pass_clip_cull : psl->refract_depth_pass_clip);
}
@ -1117,6 +1087,59 @@ static void material_opaque(
}
}
}
switch (status_mat_surface) {
case GPU_MAT_SUCCESS:
{
static int no_ssr = -1;
static int first_ssr = 1;
int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_refract) ? &first_ssr : &no_ssr;
*shgrp = DRW_shgroup_material_create(*gpumat,
(use_refract) ? psl->refract_pass :
(use_sss) ? psl->sss_pass : psl->material_pass);
add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false);
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) {
if (use_translucency) {
DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile);
DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile);
}
/* Limit of 8 bit stencil buffer. ID 255 is refraction. */
if (e_data.sss_count < 254) {
DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1);
EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile);
e_data.sss_count++;
}
else {
/* TODO : display message. */
printf("Error: Too many different Subsurface shader in the scene.\n");
}
}
}
break;
}
case GPU_MAT_QUEUED:
{
sldata->probes->all_materials_updated = false;
/* TODO Bypass probe compilation. */
color_p = compile_col;
metal_p = spec_p = rough_p = &half;
break;
}
case GPU_MAT_FAILED:
default:
color_p = error_col;
metal_p = spec_p = rough_p = &half;
break;
}
}
/* Fallback to default shader */
@ -1166,23 +1189,37 @@ static void material_transparent(
float *rough_p = &ma->gloss_mir;
if (ma->use_nodes && ma->nodetree) {
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, true, (ma->blend_method == MA_BM_MULTIPLY), use_refract,
false, false, linfo->shadow_method);
*shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
if (*shgrp) {
static int ssr_id = -1; /* TODO transparent SSR */
bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0;
add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend);
}
else {
/* Shader failed : pink color */
static float col[3] = {1.0f, 0.0f, 1.0f};
static float half = 0.5f;
switch (GPU_material_status(*gpumat)) {
case GPU_MAT_SUCCESS:
{
static int ssr_id = -1; /* TODO transparent SSR */
bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0;
color_p = col;
metal_p = spec_p = rough_p = &half;
*shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend);
break;
}
case GPU_MAT_QUEUED:
{
sldata->probes->all_materials_updated = false;
/* TODO Bypass probe compilation. */
color_p = compile_col;
metal_p = spec_p = rough_p = &half;
break;
}
case GPU_MAT_FAILED:
default:
color_p = error_col;
metal_p = spec_p = rough_p = &half;
break;
}
}

View File

@ -441,7 +441,10 @@ typedef struct EEVEE_LightProbesInfo {
int target_size;
int grid_initialized;
struct World *prev_world;
int update_world;
bool prev_wo_sh_compiled;
bool do_cube_update;
bool all_materials_updated;
/* For rendering probes */
float probemat[6][4][4];
int layer;
@ -766,7 +769,7 @@ EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob);
/* eevee_materials.c */
struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl);
void EEVEE_materials_cache_init(EEVEE_Data *vedata);
void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob);
void EEVEE_materials_cache_finish(EEVEE_Data *vedata);
struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo);

View File

@ -115,7 +115,7 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
EEVEE_effects_cache_init(sldata, vedata);
EEVEE_lightprobes_cache_init(sldata, vedata);
EEVEE_lights_cache_init(sldata, vedata);
EEVEE_materials_cache_init(vedata);
EEVEE_materials_cache_init(sldata, vedata);
EEVEE_motion_blur_cache_init(sldata, vedata);
EEVEE_occlusion_cache_init(sldata, vedata);
EEVEE_screen_raytrace_cache_init(sldata, vedata);