Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_effects.c')
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c524
1 files changed, 478 insertions, 46 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 861d862657e..7592e5c08d9 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -34,25 +34,47 @@
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
+#include "BKE_global.h" /* for G.debug_value */
#include "BKE_camera.h"
#include "BKE_object.h"
#include "BKE_animsys.h"
#include "BKE_screen.h"
+#include "DEG_depsgraph.h"
+
#include "BLI_dynstr.h"
#include "eevee_private.h"
#include "GPU_texture.h"
+#include "GPU_framebuffer.h"
+
+#define SHADER_DEFINES \
+ "#define EEVEE_ENGINE\n" \
+ "#define MAX_PROBE " STRINGIFY(MAX_PROBE) "\n" \
+ "#define MAX_GRID " STRINGIFY(MAX_GRID) "\n" \
+ "#define MAX_PLANAR " STRINGIFY(MAX_PLANAR) "\n"
typedef struct EEVEE_LightProbeData {
short probe_id, shadow_id;
} EEVEE_LightProbeData;
+/* SSR shader variations */
+enum {
+ SSR_RESOLVE = (1 << 0),
+ SSR_FULL_TRACE = (1 << 1),
+ SSR_MAX_SHADER = (1 << 2),
+};
+
static struct {
/* Downsample Depth */
- struct GPUShader *minmaxz_downlevel_sh;
- struct GPUShader *minmaxz_downdepth_sh;
- struct GPUShader *minmaxz_copydepth_sh;
+ struct GPUShader *minz_downlevel_sh;
+ struct GPUShader *maxz_downlevel_sh;
+ struct GPUShader *minz_downdepth_sh;
+ struct GPUShader *maxz_downdepth_sh;
+ struct GPUShader *minz_downdepth_layer_sh;
+ struct GPUShader *maxz_downdepth_layer_sh;
+ struct GPUShader *minz_copydepth_sh;
+ struct GPUShader *maxz_copydepth_sh;
/* Motion Blur */
struct GPUShader *motion_blur_sh;
@@ -71,21 +93,37 @@ static struct {
/* Volumetric */
struct GPUShader *volumetric_upsample_sh;
+ /* Screen Space Reflection */
+ struct GPUShader *ssr_sh[SSR_MAX_SHADER];
+
+ /* Simple Downsample */
+ struct GPUShader *downsample_sh;
+
struct GPUTexture *depth_src;
+ struct GPUTexture *color_src;
+ int depth_src_layer;
} e_data = {NULL}; /* Engine data */
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_effect_ssr_frag_glsl[];
extern char datatoc_effect_minmaxz_frag_glsl[];
extern char datatoc_effect_motion_blur_frag_glsl[];
extern char datatoc_effect_bloom_frag_glsl[];
extern char datatoc_effect_dof_vert_glsl[];
extern char datatoc_effect_dof_geom_glsl[];
extern char datatoc_effect_dof_frag_glsl[];
+extern char datatoc_effect_downsample_frag_glsl[];
+extern char datatoc_lightprobe_lib_glsl[];
+extern char datatoc_raytrace_lib_glsl[];
extern char datatoc_tonemap_frag_glsl[];
extern char datatoc_volumetric_frag_glsl[];
static void eevee_motion_blur_camera_get_matrix_at_time(
- Scene *scene, ARegion *ar, RegionView3D *rv3d, View3D *v3d, Object *camera, float time, float r_mat[4][4])
+ const bContext *C, Scene *scene, ARegion *ar, RegionView3D *rv3d, View3D *v3d, Object *camera, float time, float r_mat[4][4])
{
+ EvaluationContext eval_ctx;
float obmat[4][4];
/* HACK */
@@ -94,12 +132,14 @@ static void eevee_motion_blur_camera_get_matrix_at_time(
memcpy(&camdata_cpy, camera->data, sizeof(camdata_cpy));
cam_cpy.data = &camdata_cpy;
+ CTX_data_eval_ctx(C, &eval_ctx);
+
/* Past matrix */
/* FIXME : This is a temporal solution that does not take care of parent animations */
/* Recalc Anim manualy */
BKE_animsys_evaluate_animdata(scene, &cam_cpy.id, cam_cpy.adt, time, ADT_RECALC_ALL);
BKE_animsys_evaluate_animdata(scene, &camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL);
- BKE_object_where_is_calc_time(scene, &cam_cpy, time);
+ BKE_object_where_is_calc_time(&eval_ctx, scene, &cam_cpy, time);
/* Compute winmat */
CameraParams params;
@@ -134,6 +174,42 @@ static void eevee_motion_blur_camera_get_matrix_at_time(
mul_m4_m4m4(r_mat, params.winmat, obmat);
}
+static struct GPUShader *eevee_effects_ssr_shader_get(int options)
+{
+ if (e_data.ssr_sh[options] == NULL) {
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl);
+ char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ DynStr *ds_defines = BLI_dynstr_new();
+ BLI_dynstr_appendf(ds_defines, SHADER_DEFINES);
+ if (options & SSR_RESOLVE) {
+ BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n");
+ }
+ else {
+ BLI_dynstr_appendf(ds_defines, "#define STEP_RAYTRACE\n");
+ }
+ if (options & SSR_FULL_TRACE) {
+ BLI_dynstr_appendf(ds_defines, "#define FULLRES\n");
+ }
+ char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines);
+ BLI_dynstr_free(ds_defines);
+
+ e_data.ssr_sh[options] = DRW_shader_create_fullscreen(ssr_shader_str, ssr_define_str);
+
+ MEM_freeN(ssr_shader_str);
+ MEM_freeN(ssr_define_str);
+ }
+
+ return e_data.ssr_sh[options];
+}
+
void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_StorageList *stl = vedata->stl;
@@ -153,12 +229,28 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
/* Shaders */
if (!e_data.motion_blur_sh) {
+ e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
+
e_data.volumetric_upsample_sh = DRW_shader_create_fullscreen(datatoc_volumetric_frag_glsl, "#define STEP_UPSAMPLE\n");
- e_data.minmaxz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, NULL);
- e_data.minmaxz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define INPUT_DEPTH\n");
- e_data.minmaxz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define INPUT_DEPTH\n"
- "#define COPY_DEPTH\n");
+ e_data.minz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n");
+ e_data.maxz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n");
+ e_data.minz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n"
+ "#define INPUT_DEPTH\n");
+ e_data.maxz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n"
+ "#define INPUT_DEPTH\n");
+ e_data.minz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n"
+ "#define LAYERED\n"
+ "#define INPUT_DEPTH\n");
+ e_data.maxz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n"
+ "#define LAYERED\n"
+ "#define INPUT_DEPTH\n");
+ e_data.minz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n"
+ "#define INPUT_DEPTH\n"
+ "#define COPY_DEPTH\n");
+ e_data.maxz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n"
+ "#define INPUT_DEPTH\n"
+ "#define COPY_DEPTH\n");
e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL);
@@ -194,7 +286,7 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
int enabled_effects = 0;
- if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable")) {
+ if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable") && (draw_ctx->evil_C != NULL)) {
/* Update Motion Blur Matrices */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
float persmat[4][4];
@@ -202,7 +294,7 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
float delta = BKE_collection_engine_property_value_get_float(props, "motion_blur_shutter");
/* Current matrix */
- eevee_motion_blur_camera_get_matrix_at_time(scene, ar, rv3d, v3d, v3d->camera, ctime, effects->current_ndc_to_world);
+ eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime, effects->current_ndc_to_world);
/* Viewport Matrix */
DRW_viewport_matrix_get(persmat, DRW_MAT_PERS);
@@ -211,7 +303,7 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
if (compare_m4m4(persmat, effects->current_ndc_to_world, 0.0001f)) {
/* Past matrix */
- eevee_motion_blur_camera_get_matrix_at_time(scene, ar, rv3d, v3d, v3d->camera, ctime - delta, effects->past_world_to_ndc);
+ eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime - delta, effects->past_world_to_ndc);
#if 0 /* for future high quality blur */
/* Future matrix */
@@ -395,12 +487,16 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
}
/* MinMax Pyramid */
- /* TODO reduce precision */
- DRWFboTexture tex = {&stl->g_data->minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
+ DRWFboTexture texmin = {&stl->g_data->minzbuffer, DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
- DRW_framebuffer_init(&fbl->minmaxz_fb, &draw_engine_eevee_type,
+ DRW_framebuffer_init(&fbl->downsample_fb, &draw_engine_eevee_type,
(int)viewport_size[0] / 2, (int)viewport_size[1] / 2,
- &tex, 1);
+ &texmin, 1);
+
+ /* Cannot define 2 depth texture for one framebuffer. So allocate ourself. */
+ if (txl->maxzbuffer == NULL) {
+ txl->maxzbuffer = DRW_texture_create_2D((int)viewport_size[0] / 2, (int)viewport_size[1] / 2, DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP, NULL);
+ }
if (BKE_collection_engine_property_value_get_bool(props, "volumetric_enable")) {
World *wo = scene->world;
@@ -473,6 +569,88 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
}
}
}
+
+ if (BKE_collection_engine_property_value_get_bool(props, "ssr_enable")) {
+ effects->enabled_effects |= EFFECT_SSR;
+
+ /* Enable double buffering to be able to read previous frame color */
+ effects->enabled_effects |= EFFECT_DOUBLE_BUFFER;
+
+ effects->ssr_ray_count = BKE_collection_engine_property_value_get_int(props, "ssr_ray_count");
+ effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres");
+ effects->ssr_use_normalization = BKE_collection_engine_property_value_get_bool(props, "ssr_normalize_weight");
+ effects->ssr_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "ssr_quality");
+ effects->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness");
+ effects->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade");
+ effects->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac");
+ effects->ssr_max_roughness = BKE_collection_engine_property_value_get_float(props, "ssr_max_roughness");
+
+ if (effects->ssr_firefly_fac < 1e-8f) {
+ effects->ssr_firefly_fac = FLT_MAX;
+ }
+
+ /* Important, can lead to breakage otherwise. */
+ CLAMP(effects->ssr_ray_count, 1, 4);
+
+ const int divisor = (effects->reflection_trace_full) ? 1 : 2;
+ int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor};
+ const bool high_qual_input = true; /* TODO dither low quality input */
+
+ /* MRT for the shading pass in order to output needed data for the SSR pass. */
+ /* TODO create one texture layer per lobe */
+ if (txl->ssr_normal_input == NULL) {
+ DRWTextureFormat nor_format = DRW_TEX_RG_16;
+ txl->ssr_normal_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], nor_format, 0, NULL);
+ }
+
+ if (txl->ssr_specrough_input == NULL) {
+ DRWTextureFormat specrough_format = (high_qual_input) ? DRW_TEX_RGBA_16 : DRW_TEX_RGBA_8;
+ txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], specrough_format, 0, NULL);
+ }
+
+ /* Reattach textures to the right buffer (because we are alternating between buffers) */
+ /* TODO multiple FBO per texture!!!! */
+ DRW_framebuffer_texture_detach(txl->ssr_normal_input);
+ DRW_framebuffer_texture_detach(txl->ssr_specrough_input);
+ DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0);
+ DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0);
+
+ /* Raytracing output */
+ /* TODO try integer format for hit coord to increase precision */
+ DRWFboTexture tex_output[4] = {{&stl->g_data->ssr_hit_output[0], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
+ {&stl->g_data->ssr_hit_output[1], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
+ {&stl->g_data->ssr_hit_output[2], DRW_TEX_RGBA_16, DRW_TEX_TEMP},
+ {&stl->g_data->ssr_hit_output[3], DRW_TEX_RGBA_16, DRW_TEX_TEMP}};
+
+ DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, effects->ssr_ray_count);
+
+ /* Compute pixel size */
+ copy_v2_v2(effects->ssr_pixelsize, viewport_size);
+ invert_v2(effects->ssr_pixelsize);
+ }
+ else {
+ /* Cleanup to release memory */
+ DRW_TEXTURE_FREE_SAFE(txl->ssr_normal_input);
+ DRW_TEXTURE_FREE_SAFE(txl->ssr_specrough_input);
+ DRW_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb);
+ for (int i = 0; i < 4; ++i) {
+ stl->g_data->ssr_hit_output[i] = NULL;
+ }
+ }
+
+ /* Setup double buffer so we can access last frame as it was before post processes */
+ if ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) {
+ DRWFboTexture tex_double_buffer = {&txl->color_double_buffer, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
+
+ DRW_framebuffer_init(&fbl->double_buffer, &draw_engine_eevee_type,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &tex_double_buffer, 1);
+ }
+ else {
+ /* Cleanup to release memory */
+ DRW_TEXTURE_FREE_SAFE(txl->color_double_buffer);
+ DRW_FRAMEBUFFER_FREE_SAFE(fbl->double_buffer);
+ }
}
static DRWShadingGroup *eevee_create_bloom_pass(const char *name, EEVEE_EffectsInfo *effects, struct GPUShader *sh, DRWPass **pass, bool upsample)
@@ -561,19 +739,107 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
}
}
+ if ((effects->enabled_effects & EFFECT_SSR) != 0) {
+ int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0;
+
+ struct GPUShader *trace_shader = eevee_effects_ssr_shader_get(options);
+ struct GPUShader *resolve_shader = eevee_effects_ssr_shader_get(SSR_RESOLVE | options);
+
+ psl->ssr_raytrace = DRW_pass_create("SSR Raytrace", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input);
+ DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer);
+ DRW_shgroup_uniform_buffer(grp, "minzBuffer", &stl->g_data->minzbuffer);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
+ DRW_shgroup_uniform_vec4(grp, "ssrParameters", &effects->ssr_quality, 1);
+ DRW_shgroup_uniform_int(grp, "rayCount", &effects->ssr_ray_count, 1);
+ DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1);
+ DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1);
+ DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
+ grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input);
+ DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_buffer(grp, "colorBuffer", &txl->color_double_buffer);
+ DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
+ DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1);
+ DRW_shgroup_uniform_int(grp, "probe_count", &sldata->probes->num_render_cube, 1);
+ DRW_shgroup_uniform_float(grp, "borderFadeFactor", &effects->ssr_border_fac, 1);
+ DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1);
+ DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1);
+ DRW_shgroup_uniform_float(grp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1);
+ DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool);
+ DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool);
+ DRW_shgroup_uniform_buffer(grp, "hitBuffer0", &stl->g_data->ssr_hit_output[0]);
+ DRW_shgroup_uniform_buffer(grp, "hitBuffer1", (effects->ssr_ray_count < 2) ? &stl->g_data->ssr_hit_output[0] : &stl->g_data->ssr_hit_output[1]);
+ DRW_shgroup_uniform_buffer(grp, "hitBuffer2", (effects->ssr_ray_count < 3) ? &stl->g_data->ssr_hit_output[0] : &stl->g_data->ssr_hit_output[2]);
+ DRW_shgroup_uniform_buffer(grp, "hitBuffer3", (effects->ssr_ray_count < 4) ? &stl->g_data->ssr_hit_output[0] : &stl->g_data->ssr_hit_output[3]);
+ DRW_shgroup_uniform_int(grp, "rayCount", &effects->ssr_ray_count, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
{
- psl->minmaxz_downlevel = DRW_pass_create("HiZ Down Level", DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.minmaxz_downlevel_sh, psl->minmaxz_downlevel);
- DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minmaxz);
+ psl->color_downsample_ps = DRW_pass_create("Downsample", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps);
+ DRW_shgroup_uniform_buffer(grp, "source", &e_data.color_src);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ {
+ /* Perform min/max downsample */
+ psl->minz_downlevel_ps = DRW_pass_create("HiZ Min Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.minz_downlevel_sh, psl->minz_downlevel_ps);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minzbuffer);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->maxz_downlevel_ps = DRW_pass_create("HiZ Max Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.maxz_downlevel_sh, psl->maxz_downlevel_ps);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &txl->maxzbuffer);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ /* Copy depth buffer to halfres top level of HiZ */
+ psl->minz_downdepth_ps = DRW_pass_create("HiZ Min Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.minz_downdepth_sh, psl->minz_downdepth_ps);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_call_add(grp, quad, NULL);
- psl->minmaxz_downdepth = DRW_pass_create("HiZ Down Depth", DRW_STATE_WRITE_COLOR);
- grp = DRW_shgroup_create(e_data.minmaxz_downdepth_sh, psl->minmaxz_downdepth);
+ psl->maxz_downdepth_ps = DRW_pass_create("HiZ Max Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.maxz_downdepth_sh, psl->maxz_downdepth_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_call_add(grp, quad, NULL);
- psl->minmaxz_copydepth = DRW_pass_create("HiZ Copy Depth", DRW_STATE_WRITE_COLOR);
- grp = DRW_shgroup_create(e_data.minmaxz_copydepth_sh, psl->minmaxz_copydepth);
+ psl->minz_downdepth_layer_ps = DRW_pass_create("HiZ Min Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.minz_downdepth_layer_sh, psl->minz_downdepth_layer_ps);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->maxz_downdepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.maxz_downdepth_layer_sh, psl->maxz_downdepth_layer_ps);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ /* Copy depth buffer to halfres top level of HiZ */
+ psl->minz_copydepth_ps = DRW_pass_create("HiZ Min Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.minz_copydepth_sh, psl->minz_copydepth_ps);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->maxz_copydepth_ps = DRW_pass_create("HiZ Max Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.maxz_copydepth_sh, psl->maxz_copydepth_ps);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_call_add(grp, quad, NULL);
}
@@ -678,39 +944,79 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
}
}
-#define SWAP_BUFFERS() { \
- if (effects->source_buffer == txl->color) { \
- effects->source_buffer = txl->color_post; \
- effects->target_buffer = fbl->main; \
- } \
- else { \
- effects->source_buffer = txl->color; \
- effects->target_buffer = fbl->effect_fb; \
- } \
-} ((void)0)
+static void min_downsample_cb(void *vedata, int UNUSED(level))
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ DRW_draw_pass(psl->minz_downlevel_ps);
+}
+
+static void max_downsample_cb(void *vedata, int UNUSED(level))
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ DRW_draw_pass(psl->maxz_downlevel_ps);
+}
-static void minmax_downsample_cb(void *vedata, int UNUSED(level))
+static void simple_downsample_cb(void *vedata, int UNUSED(level))
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- DRW_draw_pass(psl->minmaxz_downlevel);
+ DRW_draw_pass(psl->color_downsample_ps);
}
-void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src)
+void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int layer)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
e_data.depth_src = depth_src;
- /* Copy depth buffer to minmax texture top level */
- DRW_framebuffer_texture_attach(fbl->minmaxz_fb, stl->g_data->minmaxz, 0, 0);
- DRW_framebuffer_bind(fbl->minmaxz_fb);
- DRW_draw_pass(psl->minmaxz_downdepth);
- DRW_framebuffer_texture_detach(stl->g_data->minmaxz);
+ DRW_stats_group_start("Min buffer");
+ /* Copy depth buffer to min texture top level */
+ DRW_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0);
+ DRW_framebuffer_bind(fbl->downsample_fb);
+ if (layer >= 0) {
+ e_data.depth_src_layer = layer;
+ DRW_draw_pass(psl->minz_downdepth_layer_ps);
+ }
+ else {
+ DRW_draw_pass(psl->minz_downdepth_ps);
+ }
+ DRW_framebuffer_texture_detach(stl->g_data->minzbuffer);
+
+ /* Create lower levels */
+ DRW_framebuffer_recursive_downsample(fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata);
+ DRW_stats_group_end();
+
+ DRW_stats_group_start("Max buffer");
+ /* Copy depth buffer to max texture top level */
+ DRW_framebuffer_texture_attach(fbl->downsample_fb, txl->maxzbuffer, 0, 0);
+ DRW_framebuffer_bind(fbl->downsample_fb);
+ if (layer >= 0) {
+ e_data.depth_src_layer = layer;
+ DRW_draw_pass(psl->maxz_downdepth_layer_ps);
+ }
+ else {
+ DRW_draw_pass(psl->maxz_downdepth_ps);
+ }
+ DRW_framebuffer_texture_detach(txl->maxzbuffer);
+
+ /* Create lower levels */
+ DRW_framebuffer_recursive_downsample(fbl->downsample_fb, txl->maxzbuffer, 8, &max_downsample_cb, vedata);
+ DRW_stats_group_end();
+}
+
+/**
+ * Simple downsampling algorithm. Reconstruct mip chain up to mip level.
+ **/
+void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, GPUTexture *texture_src, int level)
+{
+ e_data.color_src = texture_src;
+ DRW_stats_group_start("Downsample buffer");
/* Create lower levels */
- DRW_framebuffer_recursive_downsample(fbl->minmaxz_fb, stl->g_data->minmaxz, 6, &minmax_downsample_cb, vedata);
+ DRW_framebuffer_recursive_downsample(fb_src, texture_src, level, &simple_downsample_cb, vedata);
+ DRW_stats_group_end();
}
void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
@@ -747,9 +1053,79 @@ void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *veda
if (sldata->volumetrics->use_colored_transmit) {
DRW_framebuffer_texture_detach(stl->g_data->volumetric_transmit);
}
+
+ /* Rebind main buffer after attach/detach operations */
+ DRW_framebuffer_bind(fbl->main);
+ }
+}
+
+void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & EFFECT_SSR) != 0) {
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ e_data.depth_src = dtxl->depth;
+
+ for (int i = 0; i < effects->ssr_ray_count; ++i) {
+ DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_hit_output[i], i, 0);
+ }
+ DRW_framebuffer_bind(fbl->screen_tracing_fb);
+
+ if (stl->g_data->valid_double_buffer) {
+ /* Raytrace. */
+ DRW_draw_pass(psl->ssr_raytrace);
+ }
+ else {
+ float clear_col[4] = {0.0f, 0.0f, -1.0f, 0.001f};
+ DRW_framebuffer_clear(true, false, false, clear_col, 0.0f);
+ }
+
+ for (int i = 0; i < effects->ssr_ray_count; ++i) {
+ DRW_framebuffer_texture_detach(stl->g_data->ssr_hit_output[i]);
+ }
+
+ EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->color_double_buffer, 9);
+
+ /* Resolve at fullres */
+ DRW_framebuffer_texture_detach(dtxl->depth);
+ DRW_framebuffer_texture_detach(txl->ssr_normal_input);
+ DRW_framebuffer_texture_detach(txl->ssr_specrough_input);
+ DRW_framebuffer_bind(fbl->main);
+ DRW_draw_pass(psl->ssr_resolve);
+
+ /* Restore */
+ DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0);
+ DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0);
+ DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0);
}
}
+#define SWAP_DOUBLE_BUFFERS() { \
+ if (swap_double_buffer) { \
+ SWAP(struct GPUFrameBuffer *, fbl->main, fbl->double_buffer); \
+ SWAP(GPUTexture *, txl->color, txl->color_double_buffer); \
+ swap_double_buffer = false; \
+ } \
+} ((void)0)
+
+#define SWAP_BUFFERS() { \
+ if (effects->source_buffer == txl->color) { \
+ SWAP_DOUBLE_BUFFERS(); \
+ effects->source_buffer = txl->color_post; \
+ effects->target_buffer = fbl->main; \
+ } \
+ else { \
+ SWAP_DOUBLE_BUFFERS(); \
+ effects->source_buffer = txl->color; \
+ effects->target_buffer = fbl->effect_fb; \
+ } \
+} ((void)0)
+
void EEVEE_draw_effects(EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
@@ -758,6 +1134,9 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
+ /* only once per frame after the first post process */
+ bool swap_double_buffer = ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0);
+
/* Default framebuffer and texture */
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
@@ -869,15 +1248,68 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
/* Tonemapping */
DRW_transform_to_display(effects->source_buffer);
+
+ /* Debug : Ouput buffer to view. */
+ if ((G.debug_value > 0) && (G.debug_value <= 5)) {
+ switch (G.debug_value) {
+ case 1:
+ if (stl->g_data->minzbuffer) DRW_transform_to_display(stl->g_data->minzbuffer);
+ break;
+ case 2:
+ if (stl->g_data->ssr_hit_output[0]) DRW_transform_to_display(stl->g_data->ssr_hit_output[0]);
+ break;
+ case 3:
+ if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input);
+ break;
+ case 4:
+ if (txl->ssr_specrough_input) DRW_transform_to_display(txl->ssr_specrough_input);
+ break;
+ case 5:
+ if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* If no post processes is enabled, buffers are still not swapped, do it now. */
+ SWAP_DOUBLE_BUFFERS();
+
+ if (!stl->g_data->valid_double_buffer &&
+ ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) &&
+ (DRW_state_is_image_render() == false))
+ {
+ /* If history buffer is not valid request another frame.
+ * This fix black reflections on area resize. */
+ DRW_viewport_request_redraw();
+ }
+
+ /* Record pers matrix for the next frame. */
+ DRW_viewport_matrix_get(stl->g_data->prev_persmat, DRW_MAT_PERS);
+
+ /* Update double buffer status if render mode. */
+ if (DRW_state_is_image_render()) {
+ stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
+ }
}
void EEVEE_effects_free(void)
{
+ for (int i = 0; i < SSR_MAX_SHADER; ++i) {
+ DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]);
+ }
+ DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
+
DRW_SHADER_FREE_SAFE(e_data.volumetric_upsample_sh);
- DRW_SHADER_FREE_SAFE(e_data.minmaxz_downlevel_sh);
- DRW_SHADER_FREE_SAFE(e_data.minmaxz_downdepth_sh);
- DRW_SHADER_FREE_SAFE(e_data.minmaxz_copydepth_sh);
+ DRW_SHADER_FREE_SAFE(e_data.minz_downlevel_sh);
+ DRW_SHADER_FREE_SAFE(e_data.maxz_downlevel_sh);
+ DRW_SHADER_FREE_SAFE(e_data.minz_downdepth_sh);
+ DRW_SHADER_FREE_SAFE(e_data.maxz_downdepth_sh);
+ DRW_SHADER_FREE_SAFE(e_data.minz_downdepth_layer_sh);
+ DRW_SHADER_FREE_SAFE(e_data.maxz_downdepth_layer_sh);
+ DRW_SHADER_FREE_SAFE(e_data.minz_copydepth_sh);
+ DRW_SHADER_FREE_SAFE(e_data.maxz_copydepth_sh);
DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh);
DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
@@ -892,4 +1324,4 @@ void EEVEE_effects_free(void)
DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[1]);
DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[1]);
DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[1]);
-} \ No newline at end of file
+}