Eevee: Implement Temporal Anti Aliasing / Super Sampling

This adds TAA to eevee. The only thing important to note is that we need to keep the unjittered depth buffer so that the other engines are composited correctly.
This commit is contained in:
Clément Foucault 2017-09-25 20:14:07 +02:00
parent 198c7d3687
commit 3ae0be45f1
9 changed files with 269 additions and 4 deletions

View File

@ -735,6 +735,25 @@ class RENDER_PT_eevee_shadows(RenderButtonsPanel, Panel):
col.prop(props, "shadow_high_bitdepth")
class RENDER_PT_eevee_antialiasing(RenderButtonsPanel, Panel):
bl_label = "Viewport Anti Aliasing"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
scene = context.scene
return scene and (scene.render.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
scene = context.scene
props = scene.layer_properties['BLENDER_EEVEE']
col = layout.column()
col.prop(props, "taa_enable")
col.prop(props, "taa_samples")
classes = (
RENDER_MT_presets,
RENDER_MT_ffmpeg_presets,
@ -757,6 +776,7 @@ classes = (
RENDER_PT_eevee_poststack_settings,
RENDER_PT_eevee_postprocess_settings,
RENDER_PT_eevee_shadows,
RENDER_PT_eevee_antialiasing,
)
if __name__ == "__main__": # only for live edit.

View File

@ -312,6 +312,27 @@ class RENDERLAYER_PT_eevee_shadows(RenderLayerButtonsPanel, Panel):
col.template_override_property(layer_props, scene_props, "shadow_high_bitdepth")
class RENDERLAYER_PT_eevee_antialiasing(RenderLayerButtonsPanel, Panel):
bl_label = "Viewport Anti Aliasing"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
@classmethod
def poll(cls, context):
scene = context.scene
return scene and (scene.render.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
scene = context.scene
scene_props = scene.layer_properties['BLENDER_EEVEE']
layer = bpy.context.render_layer
layer_props = layer.engine_overrides['BLENDER_EEVEE']
col = layout.column()
col.template_override_property(layer_props, scene_props, "taa_enable")
col.template_override_property(layer_props, scene_props, "taa_samples")
classes = (
RENDERLAYER_UL_renderlayers,
RENDERLAYER_PT_layers,
@ -323,6 +344,7 @@ classes = (
RENDERLAYER_PT_eevee_screen_space_reflections,
RENDERLAYER_PT_eevee_volumetric,
RENDERLAYER_PT_eevee_shadows,
RENDERLAYER_PT_eevee_antialiasing,
)
if __name__ == "__main__": # only for live edit.

View File

@ -146,6 +146,7 @@ data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_ssr_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl SRC)

View File

@ -43,6 +43,7 @@
#include "DEG_depsgraph.h"
#include "BLI_dynstr.h"
#include "BLI_jitter.h"
#include "eevee_private.h"
#include "GPU_texture.h"
@ -105,8 +106,13 @@ static struct {
struct GPUShader *gtao_sh;
struct GPUShader *gtao_debug_sh;
/* Temporal Anti Aliasing */
struct GPUShader *taa_resolve_sh;
/* Theses are just references, not actually allocated */
struct GPUTexture *depth_src;
struct GPUTexture *color_src;
int depth_src_layer;
float cube_texel_size;
} e_data = {NULL}; /* Engine data */
@ -115,6 +121,7 @@ extern char datatoc_ambient_occlusion_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_effect_temporal_aa_glsl[];
extern char datatoc_effect_ssr_frag_glsl[];
extern char datatoc_effect_minmaxz_frag_glsl[];
extern char datatoc_effect_motion_blur_frag_glsl[];
@ -256,6 +263,8 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
MEM_freeN(frag_str);
e_data.taa_resolve_sh = DRW_shader_create_fullscreen(datatoc_effect_temporal_aa_glsl, NULL);
e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
e_data.downsample_cube_sh = DRW_shader_create(datatoc_lightprobe_vert_glsl,
datatoc_lightprobe_geom_glsl,
@ -738,6 +747,68 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
}
}
if (BKE_collection_engine_property_value_get_bool(props, "taa_enable")) {
float persmat[4][4], viewmat[4][4];
effects->enabled_effects |= EFFECT_TAA | EFFECT_DOUBLE_BUFFER;
/* Until we support reprojection, we need to make sure
* that the history buffer contains correct information. */
bool view_is_valid = stl->g_data->valid_double_buffer;
view_is_valid = view_is_valid && (stl->g_data->view_updated == false);
int taa_pref_samples = BKE_collection_engine_property_value_get_int(props, "taa_samples");
CLAMP(taa_pref_samples, 1, 32);
view_is_valid = view_is_valid && (effects->taa_total_sample == taa_pref_samples);
if (effects->taa_total_sample != taa_pref_samples) {
effects->taa_total_sample = taa_pref_samples;
BLI_jitter_init(effects->taa_jit_ofs, effects->taa_total_sample);
}
DRW_viewport_matrix_get(persmat, DRW_MAT_PERS);
DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
DRW_viewport_matrix_get(effects->overide_winmat, DRW_MAT_WIN);
view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, 0.0001f);
copy_m4_m4(effects->prev_drw_persmat, persmat);
if (view_is_valid && (effects->taa_current_sample < effects->taa_total_sample)) {
effects->taa_current_sample += 1;
effects->taa_alpha = 1.0f - (1.0f / (float)(effects->taa_current_sample));
window_translate_m4(
effects->overide_winmat, persmat,
(effects->taa_jit_ofs[effects->taa_current_sample][0] * 2.0f) / viewport_size[0],
(effects->taa_jit_ofs[effects->taa_current_sample][1] * 2.0f) / viewport_size[1]);
mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat);
invert_m4_m4(effects->overide_persinv, effects->overide_persmat);
invert_m4_m4(effects->overide_wininv, effects->overide_winmat);
DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS);
DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV);
DRW_viewport_matrix_override_set(effects->overide_winmat, DRW_MAT_WIN);
DRW_viewport_matrix_override_set(effects->overide_wininv, DRW_MAT_WININV);
}
else {
effects->taa_current_sample = 1;
}
DRWFboTexture tex_double_buffer = {&txl->depth_double_buffer, DRW_TEX_DEPTH_24};
DRW_framebuffer_init(&fbl->depth_double_buffer_fb, &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->depth_double_buffer);
DRW_FRAMEBUFFER_FREE_SAFE(fbl->depth_double_buffer_fb);
}
/* Normal buffer for deferred passes. */
if ((((effects->enabled_effects & EFFECT_GTAO) != 0) && G.debug_value == 6) ||
((effects->enabled_effects & EFFECT_SSR) != 0))
@ -800,6 +871,15 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
if ((effects->enabled_effects & EFFECT_TAA) != 0) {
psl->taa_resolve = DRW_pass_create("Temporal AA Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.taa_resolve_sh, psl->taa_resolve);
DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer);
DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1);
DRW_shgroup_call_add(grp, quad, NULL);
}
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
@ -1381,6 +1461,29 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
effects->source_buffer = txl->color; /* latest updated texture */
effects->target_buffer = fbl->effect_fb; /* next target to render to */
/* Motion Blur */
if ((effects->enabled_effects & EFFECT_TAA) != 0) {
if (effects->taa_current_sample != 1) {
effects->source_buffer = txl->color_double_buffer;
DRW_framebuffer_bind(fbl->main);
DRW_draw_pass(psl->taa_resolve);
effects->source_buffer = txl->color;
/* Restore the depth from sample 1. */
DRW_framebuffer_blit(fbl->depth_double_buffer_fb, fbl->main, true);
}
else {
/* Save the depth buffer for the next frame.
* This saves us from doing anything special
* in the other mode engines. */
DRW_framebuffer_blit(fbl->main, fbl->depth_double_buffer_fb, true);
}
if (effects->taa_current_sample < effects->taa_total_sample) {
DRW_viewport_request_redraw();
}
}
/* Detach depth for effects to use it */
DRW_framebuffer_texture_detach(dtxl->depth);
@ -1540,6 +1643,8 @@ void EEVEE_effects_free(void)
DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
DRW_SHADER_FREE_SAFE(e_data.downsample_cube_sh);
DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.gtao_sh);
DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh);

View File

@ -43,6 +43,22 @@ extern GlobalsUboStorage ts;
/* *********** FUNCTIONS *********** */
/* TODO : put this somewhere in BLI */
static float halton_1D(int prime, int n)
{
float inv_prime = 1.0f / (float)prime;
float f = 1.0f;
float r = 0.0f;
while (n > 0) {
f = f * inv_prime;
r += f * (n % prime);
n = (int)(n * inv_prime);
}
return r;
}
static void EEVEE_engine_init(void *ved)
{
EEVEE_Data *vedata = (EEVEE_Data *)ved;
@ -65,10 +81,20 @@ static void EEVEE_engine_init(void *ved)
(int)viewport_size[0], (int)viewport_size[1],
&tex, 1);
/* EEVEE_effects_init needs to go first for TAA */
EEVEE_effects_init(sldata, vedata);
EEVEE_materials_init(stl);
EEVEE_lights_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
EEVEE_effects_init(sldata, vedata);
if (stl->effects->taa_current_sample > 1) {
/* XXX otherwise it would break the other engines. */
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
DRW_viewport_matrix_override_unset(DRW_MAT_WININV);
}
}
static void EEVEE_cache_init(void *vedata)
@ -144,6 +170,7 @@ static void EEVEE_cache_finish(void *vedata)
static void EEVEE_draw_scene(void *vedata)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl;
EEVEE_SceneLayerData *sldata = EEVEE_scene_layer_data_get();
@ -164,6 +191,13 @@ static void EEVEE_draw_scene(void *vedata)
/* Set jitter offset */
EEVEE_update_util_texture(rand);
}
else if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && (stl->effects->taa_current_sample > 1)) {
rand = halton_1D(2, stl->effects->taa_current_sample - 1);
/* Set jitter offset */
/* PERF This is killing perf ! */
EEVEE_update_util_texture(rand);
}
while (loop_ct--) {
@ -183,6 +217,13 @@ static void EEVEE_draw_scene(void *vedata)
DRW_framebuffer_bind(fbl->main);
DRW_framebuffer_clear(false, true, false, NULL, 1.0f);
if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && stl->effects->taa_current_sample > 1) {
DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS);
DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV);
DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN);
DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV);
}
/* Depth prepass */
DRW_stats_group_start("Prepass");
DRW_draw_pass(psl->depth_pass);
@ -242,6 +283,23 @@ static void EEVEE_draw_scene(void *vedata)
DRW_stats_group_start("Post FX");
EEVEE_draw_effects(vedata);
DRW_stats_group_end();
if (stl->effects->taa_current_sample > 1) {
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
DRW_viewport_matrix_override_unset(DRW_MAT_WININV);
}
}
stl->g_data->view_updated = false;
}
static void EEVEE_view_update(void *vedata)
{
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
if (stl->g_data) {
stl->g_data->view_updated = true;
}
}
@ -268,6 +326,8 @@ static void EEVEE_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDPr
props->type == IDP_GROUP &&
props->subtype == IDP_GROUP_SUB_ENGINE_RENDER);
BKE_collection_engine_property_add_bool(props, "taa_enable", true);
BKE_collection_engine_property_add_int(props, "taa_samples", 8);
BKE_collection_engine_property_add_bool(props, "ssr_enable", false);
BKE_collection_engine_property_add_bool(props, "ssr_refraction", false);
@ -333,7 +393,8 @@ DrawEngineType draw_engine_eevee_type = {
&EEVEE_cache_populate,
&EEVEE_cache_finish,
&EEVEE_draw_scene,
NULL//&EEVEE_draw_scene
NULL, //&EEVEE_draw_scene
&EEVEE_view_update,
};
RenderEngineType DRW_engine_viewport_eevee_type = {

View File

@ -967,7 +967,7 @@ static void render_scene_to_probe(
EEVEE_StorageList *stl = vedata->stl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
float winmat[4][4], posmat[4][4], tmp_ao_dist, tmp_ao_samples, tmp_ao_settings;
float winmat[4][4], wininv[4][4], posmat[4][4], tmp_ao_dist, tmp_ao_samples, tmp_ao_settings;
unit_m4(posmat);
@ -1012,12 +1012,14 @@ static void render_scene_to_probe(
mul_m4_m4m4(persmat, winmat, viewmat);
invert_m4_m4(persinv, persmat);
invert_m4_m4(viewinv, viewmat);
invert_m4_m4(wininv, winmat);
DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV);
/* Be sure that cascaded shadow maps are updated. */
EEVEE_draw_shadows(sldata, psl);
@ -1052,6 +1054,7 @@ static void render_scene_to_probe(
DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
DRW_viewport_matrix_override_unset(DRW_MAT_WININV);
/* Restore */
sldata->probes->specular_toggle = true;
@ -1149,7 +1152,7 @@ static void render_scene_to_planar(
static void render_world_to_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
float winmat[4][4];
float winmat[4][4], wininv[4][4];
/* 1 - Render to cubemap target using geometry shader. */
/* For world probe, we don't need to clear since we render the background directly. */
@ -1178,6 +1181,7 @@ static void render_world_to_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *
DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV);
DRW_draw_pass(psl->probe_background);
@ -1190,6 +1194,7 @@ static void render_world_to_probe(EEVEE_SceneLayerData *sldata, EEVEE_PassList *
DRW_viewport_matrix_override_unset(DRW_MAT_VIEW);
DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV);
DRW_viewport_matrix_override_unset(DRW_MAT_WIN);
DRW_viewport_matrix_override_unset(DRW_MAT_WININV);
}
static void lightprobe_cell_location_get(EEVEE_LightGrid *egrid, int cell_idx, float r_pos[3])
@ -1213,6 +1218,7 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
Object *ob;
const DRWContextState *draw_ctx = DRW_context_state_get();
@ -1300,6 +1306,9 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
#endif
/* Only do one probe per frame */
DRW_viewport_request_redraw();
/* Do not let this frame accumulate. */
stl->effects->taa_current_sample = 1;
goto update_planar;
}
}
@ -1338,6 +1347,8 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
printf("Update Cubemap %d\n", i);
#endif
DRW_viewport_request_redraw();
/* Do not let this frame accumulate. */
stl->effects->taa_current_sample = 1;
/* Only do one probe per frame */
goto update_planar;

View File

@ -123,6 +123,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *ssr_resolve;
struct DRWPass *color_downsample_ps;
struct DRWPass *color_downsample_cube_ps;
struct DRWPass *taa_resolve;
/* HiZ */
struct DRWPass *minz_downlevel_ps;
@ -169,6 +170,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *main;
struct GPUFrameBuffer *double_buffer;
struct GPUFrameBuffer *depth_double_buffer_fb;
} EEVEE_FramebufferList;
typedef struct EEVEE_TextureList {
@ -195,6 +197,7 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *color; /* R16_G16_B16 */
struct GPUTexture *color_double_buffer;
struct GPUTexture *depth_double_buffer;
} EEVEE_TextureList;
typedef struct EEVEE_StorageList {
@ -364,6 +367,17 @@ typedef struct EEVEE_EffectsInfo {
float ssr_thickness;
float ssr_pixelsize[2];
/* Temporal Anti Aliasing */
int taa_current_sample;
int taa_total_sample;
float taa_jit_ofs[32][2];
float taa_alpha;
float prev_drw_persmat[4][4];
float overide_persmat[4][4];
float overide_persinv[4][4];
float overide_winmat[4][4];
float overide_wininv[4][4];
/* Ambient Occlusion */
bool use_ao, use_bent_normals;
float ao_dist, ao_samples, ao_factor, ao_samples_inv;
@ -411,6 +425,7 @@ enum {
EFFECT_DOUBLE_BUFFER = (1 << 5), /* Not really an effect but a feature */
EFFECT_REFRACT = (1 << 6),
EFFECT_GTAO = (1 << 7),
EFFECT_TAA = (1 << 8),
};
/* ************** SCENE LAYER DATA ************** */
@ -515,6 +530,7 @@ typedef struct EEVEE_PrivateData {
/* To correct mip level texel mis-alignement */
float mip_ratio[10][2]; /* TODO put in a UBO */
/* For double buffering */
bool view_updated;
bool valid_double_buffer;
float prev_persmat[4][4];
} EEVEE_PrivateData; /* Transient data */

View File

@ -0,0 +1,11 @@
uniform sampler2D colorBuffer;
uniform float alpha;
out vec4 FragColor;
void main()
{
/* TODO History buffer Reprojection */
FragColor = vec4(texelFetch(colorBuffer, ivec2(gl_FragCoord.xy), 0).rgb, alpha);
}

View File

@ -2572,6 +2572,8 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_firefly_fac)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(shadow_method)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(shadow_size)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(shadow_high_bitdepth)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(taa_enable)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(taa_samples)
/* object engine */
RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_wire)
@ -6178,6 +6180,22 @@ static void rna_def_scene_layer_engine_settings_eevee(BlenderRNA *brna)
/* see RNA_LAYER_ENGINE_GET_SET macro */
/* Temporal Anti-Aliasing */
prop = RNA_def_property(srna, "taa_enable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_taa_enable_get",
"rna_LayerEngineSettings_Eevee_taa_enable_set");
RNA_def_property_ui_text(prop, "Temporal Anti-Aliasing", "Enable temporal anti-aliasing (only used by viewport)");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_taa_samples_get",
"rna_LayerEngineSettings_Eevee_taa_samples_set", NULL);
RNA_def_property_ui_text(prop, "Samples", "Minimum number of temporal samples");
RNA_def_property_range(prop, 1, 32);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update");
/* Screen Space Reflection */
prop = RNA_def_property(srna, "ssr_enable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_enable_get",