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:
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h18
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c253
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c190
-rw-r--r--source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl63
6 files changed, 335 insertions, 192 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 950adf3ddc5..dc5508340de 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -102,6 +102,7 @@ set(SRC
engines/eevee/eevee_motion_blur.c
engines/eevee/eevee_occlusion.c
engines/eevee/eevee_render.c
+ engines/eevee/eevee_renderpasses.c
engines/eevee/eevee_sampling.c
engines/eevee/eevee_screen_raytrace.c
engines/eevee/eevee_shaders.c
@@ -221,6 +222,7 @@ data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/update_noise_frag.glsl SRC)
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index a1096390bce..173b7ff57a1 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -483,6 +483,7 @@ static void eevee_engine_free(void)
EEVEE_screen_raytrace_free();
EEVEE_subsurface_free();
EEVEE_volumes_free();
+ EEVEE_renderpasses_free();
}
static const DrawEngineDataSize eevee_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 41e38fd8437..b49328d90ab 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -271,6 +271,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *update_noise_pass;
struct DRWPass *lookdev_glossy_pass;
struct DRWPass *lookdev_diffuse_pass;
+ struct DRWPass *renderpass_pass;
} EEVEE_PassList;
typedef struct EEVEE_FramebufferList {
@@ -295,6 +296,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *screen_tracing_fb;
struct GPUFrameBuffer *refract_fb;
struct GPUFrameBuffer *mist_accum_fb;
+ struct GPUFrameBuffer *renderpass_fb;
struct GPUFrameBuffer *ao_accum_fb;
struct GPUFrameBuffer *velocity_resolve_fb;
@@ -341,6 +343,8 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *maxzbuffer;
+ struct GPUTexture *renderpass;
+
struct GPUTexture *color; /* R16_G16_B16 */
struct GPUTexture *color_double_buffer;
struct GPUTexture *depth_double_buffer;
@@ -799,6 +803,10 @@ typedef struct EEVEE_PrivateData {
float studiolight_glossy_clamp;
float studiolight_filter_quality;
+ /* Renderpasses */
+ /* Bitmask containing the active render_passes */
+ eScenePassType render_passes;
+
/** For rendering shadows. */
struct DRWView *cube_views[6];
/** For rendering probes. */
@@ -1039,6 +1047,16 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_mist_free(void);
+/* eevee_renderpasses.c */
+void EEVEE_renderpasses_init(EEVEE_Data *vedata);
+void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint tot_samples);
+void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ eScenePassType renderpass_type);
+void EEVEE_renderpasses_free(void);
+
/* eevee_temporal_sampling.c */
void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata);
int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index ee1dc8a0208..9a7d170c9ea 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -130,7 +130,9 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
DRW_view_default_set(view);
DRW_view_set_active(view);
- /* EEVEE_effects_init needs to go first for TAA */
+ /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`.
+ * `EEVEE_effects_init` needs to go second for TAA. */
+ EEVEE_renderpasses_init(vedata);
EEVEE_effects_init(sldata, vedata, ob_camera_eval, false);
EEVEE_materials_init(sldata, stl, fbl);
EEVEE_shadows_init(sldata);
@@ -202,79 +204,60 @@ void EEVEE_render_cache(void *vedata,
}
}
-static void eevee_render_result_combined(RenderLayer *rl,
- const char *viewname,
- const rcti *rect,
- EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata))
+static void eevee_render_color_result(RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect,
+ const char *render_pass_name,
+ int num_channels,
+ GPUFrameBuffer *framebuffer,
+ EEVEE_Data *vedata)
{
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
-
- GPU_framebuffer_bind(vedata->stl->effects->final_fb);
- GPU_framebuffer_read_color(vedata->stl->effects->final_fb,
+ RenderPass *rp = RE_pass_find_by_name(rl, render_pass_name, viewname);
+ GPU_framebuffer_bind(framebuffer);
+ GPU_framebuffer_read_color(framebuffer,
vedata->stl->g_data->overscan_pixels + rect->xmin,
vedata->stl->g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
- 4,
+ num_channels,
0,
rp->rect);
}
+static void eevee_render_result_combined(RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect,
+ EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *UNUSED(sldata))
+{
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_COMBINED, 4, vedata->stl->effects->final_fb, vedata);
+}
+
static void eevee_render_result_subsurface(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata),
- int render_samples)
+ EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
-
if (vedata->fbl->sss_accum_fb == NULL) {
/* SSS is not enabled. */
return;
}
- if ((view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_COLOR, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
- GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
- vedata->stl->g_data->overscan_pixels + rect->xmin,
- vedata->stl->g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 3,
- 1,
- rp->rect);
-
- /* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
- rp->rect[i] /= (float)render_samples;
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_COLOR) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_SUBSURFACE_COLOR);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_SUBSURFACE_COLOR, 3, vedata->fbl->renderpass_fb, vedata);
}
- if ((view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_DIRECT, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
- GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
- vedata->stl->g_data->overscan_pixels + rect->xmin,
- vedata->stl->g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 3,
- 0,
- rp->rect);
-
- /* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
- rp->rect[i] /= (float)render_samples;
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_DIRECT) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_SUBSURFACE_DIRECT);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_SUBSURFACE_DIRECT, 3, vedata->fbl->renderpass_fb, vedata);
}
- if ((view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) != 0) {
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_INDIRECT) != 0) {
/* Do nothing as all the lighting is in the direct pass.
* TODO : Separate Direct from indirect lighting. */
}
@@ -284,54 +267,19 @@ static void eevee_render_result_normal(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata))
+ EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_PrivateData *g_data = stl->g_data;
+ const int current_sample = vedata->stl->effects->taa_current_sample;
/* Only read the center texel. */
- if (stl->effects->taa_current_sample > 1) {
+ if (current_sample > 1) {
return;
}
- if ((view_layer->passflag & SCE_PASS_NORMAL) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_NORMAL, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->main_fb);
- GPU_framebuffer_read_color(vedata->fbl->main_fb,
- g_data->overscan_pixels + rect->xmin,
- g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 3,
- 1,
- rp->rect);
-
- float viewinv[4][4];
- DRW_view_viewmat_get(NULL, viewinv, true);
-
- /* Convert Eevee encoded normals to Blender normals. */
- for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
- if (rp->rect[i] == 0.0f && rp->rect[i + 1] == 0.0f) {
- /* If normal is not correct then do not produce NANs. */
- continue;
- }
-
- float fenc[2];
- fenc[0] = rp->rect[i + 0] * 4.0f - 2.0f;
- fenc[1] = rp->rect[i + 1] * 4.0f - 2.0f;
-
- float f = dot_v2v2(fenc, fenc);
- float g = sqrtf(1.0f - f / 4.0f);
-
- rp->rect[i + 0] = fenc[0] * g;
- rp->rect[i + 1] = fenc[1] * g;
- rp->rect[i + 2] = 1.0f - f / 2.0f;
-
- mul_mat3_m4_v3(viewinv, &rp->rect[i]);
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_NORMAL) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_NORMAL);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_NORMAL, 3, vedata->fbl->renderpass_fb, vedata);
}
}
@@ -341,49 +289,17 @@ static void eevee_render_result_z(RenderLayer *rl,
EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
- EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_PrivateData *g_data = stl->g_data;
+ const int current_sample = vedata->stl->effects->taa_current_sample;
/* Only read the center texel. */
- if (stl->effects->taa_current_sample > 1) {
+ if (current_sample > 1) {
return;
}
- if ((view_layer->passflag & SCE_PASS_Z) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->main_fb);
- GPU_framebuffer_read_depth(vedata->fbl->main_fb,
- g_data->overscan_pixels + rect->xmin,
- g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- rp->rect);
-
- bool is_persp = DRW_view_is_persp_get(NULL);
-
- float winmat[4][4];
- DRW_view_winmat_get(NULL, winmat, false);
-
- /* Convert ogl depth [0..1] to view Z [near..far] */
- for (int i = 0; i < rp->rectx * rp->recty; i++) {
- if (rp->rect[i] == 1.0f) {
- rp->rect[i] = 1e10f; /* Background */
- }
- else {
- if (is_persp) {
- rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
- rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
- }
- else {
- rp->rect[i] = -common_data->view_vecs[0][2] +
- rp->rect[i] * -common_data->view_vecs[1][2];
- }
- }
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_Z) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_Z);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_Z, 1, vedata->fbl->renderpass_fb, vedata);
}
}
@@ -391,29 +307,12 @@ static void eevee_render_result_mist(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata),
- int render_samples)
+ EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
-
- if ((view_layer->passflag & SCE_PASS_MIST) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_MIST, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->mist_accum_fb);
- GPU_framebuffer_read_color(vedata->fbl->mist_accum_fb,
- vedata->stl->g_data->overscan_pixels + rect->xmin,
- vedata->stl->g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 1,
- 0,
- rp->rect);
-
- /* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rp->rectx * rp->recty; i++) {
- rp->rect[i] /= (float)render_samples;
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_MIST) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_MIST);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_MIST, 1, vedata->fbl->renderpass_fb, vedata);
}
}
@@ -421,35 +320,17 @@ static void eevee_render_result_occlusion(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
- EEVEE_ViewLayerData *UNUSED(sldata),
- int render_samples)
+ EEVEE_ViewLayerData *sldata)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
-
if (vedata->fbl->ao_accum_fb == NULL) {
/* AO is not enabled. */
return;
}
- if ((view_layer->passflag & SCE_PASS_AO) != 0) {
- RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_AO, viewname);
-
- GPU_framebuffer_bind(vedata->fbl->ao_accum_fb);
- GPU_framebuffer_read_color(vedata->fbl->ao_accum_fb,
- vedata->stl->g_data->overscan_pixels + rect->xmin,
- vedata->stl->g_data->overscan_pixels + rect->ymin,
- BLI_rcti_size_x(rect),
- BLI_rcti_size_y(rect),
- 3,
- 0,
- rp->rect);
-
- /* This is the accumulated color. Divide by the number of samples. */
- for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
- rp->rect[i] = rp->rect[i + 1] = rp->rect[i + 2] = min_ff(
- 1.0f, rp->rect[i] / (float)render_samples);
- }
+ if ((vedata->stl->g_data->render_passes & SCE_PASS_AO) != 0) {
+ EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_AO);
+ eevee_render_color_result(
+ rl, viewname, rect, RE_PASSNAME_AO, 3, vedata->fbl->renderpass_fb, vedata);
}
}
@@ -488,7 +369,6 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
- ViewLayer *view_layer = draw_ctx->view_layer;
const char *viewname = RE_GetActiveRenderView(engine->re);
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
@@ -525,18 +405,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
tot_sample += 1;
}
- if ((view_layer->passflag & (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT |
- SCE_PASS_SUBSURFACE_INDIRECT)) != 0) {
- EEVEE_subsurface_output_init(sldata, vedata, tot_sample);
- }
-
- if ((view_layer->passflag & SCE_PASS_MIST) != 0) {
- EEVEE_mist_output_init(sldata, vedata);
- }
-
- if ((view_layer->passflag & SCE_PASS_AO) != 0) {
- EEVEE_occlusion_output_init(sldata, vedata, tot_sample);
- }
+ EEVEE_renderpasses_output_init(sldata, vedata, tot_sample);
if (RE_engine_test_break(engine)) {
return;
@@ -644,9 +513,9 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
}
eevee_render_result_combined(rl, viewname, rect, vedata, sldata);
- eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata, render_samples);
- eevee_render_result_mist(rl, viewname, rect, vedata, sldata, render_samples);
- eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata, render_samples);
+ eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata);
+ eevee_render_result_mist(rl, viewname, rect, vedata, sldata);
+ eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata);
/* Restore original viewport size. */
DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]});
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
new file mode 100644
index 00000000000..17f1f8c96d6
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -0,0 +1,190 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BLI_string_utils.h"
+
+#include "eevee_private.h"
+
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_renderpass_postprocess_frag_glsl[];
+
+static struct {
+ struct GPUShader *postprocess_sh;
+} e_data = {NULL}; /* Engine data */
+
+/* bitmask containing all renderpasses that need post-processing */
+#define EEVEE_RENDERPASSES_WITH_POST_PROCESSING \
+ (SCE_PASS_Z | SCE_PASS_MIST | SCE_PASS_NORMAL | SCE_PASS_AO | SCE_PASS_SUBSURFACE_COLOR | \
+ SCE_PASS_SUBSURFACE_DIRECT)
+
+#define EEVEE_RENDERPASSES_SUBSURFACE \
+ (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT | SCE_PASS_SUBSURFACE_INDIRECT)
+
+#define EEVEE_RENDERPASSES_ALL (EEVEE_RENDERPASSES_WITH_POST_PROCESSING | SCE_PASS_COMBINED)
+
+void EEVEE_renderpasses_init(EEVEE_Data *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ g_data->render_passes = (view_layer->passflag & EEVEE_RENDERPASSES_ALL) | SCE_PASS_COMBINED;
+}
+
+void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ uint tot_samples)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+
+ const bool needs_post_processing = (g_data->render_passes &
+ EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0;
+ if (needs_post_processing) {
+ if (e_data.postprocess_sh == NULL) {
+ char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_renderpass_postprocess_frag_glsl);
+ e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL);
+ MEM_freeN(frag_str);
+ }
+
+ /* Create FrameBuffer. */
+
+ /* Should be enough to store the data needs for a single pass.
+ * Some passes will use less, but it is only relevant for final renderings and
+ * when renderpasses other than `SCE_PASS_COMBINED` are requested */
+ DRW_texture_ensure_fullscreen_2d(&txl->renderpass, GPU_RGBA16F, 0);
+ GPU_framebuffer_ensure_config(&fbl->renderpass_fb,
+ {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->renderpass)});
+
+ if ((g_data->render_passes & EEVEE_RENDERPASSES_SUBSURFACE) != 0) {
+ EEVEE_subsurface_output_init(sldata, vedata, tot_samples);
+ }
+
+ if ((g_data->render_passes & SCE_PASS_MIST) != 0) {
+ EEVEE_mist_output_init(sldata, vedata);
+ }
+
+ if ((g_data->render_passes & SCE_PASS_AO) != 0) {
+ EEVEE_occlusion_output_init(sldata, vedata, tot_samples);
+ }
+
+ /* Create Pass. */
+ DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR);
+ }
+ else {
+ /* Free unneeded memory */
+ DRW_TEXTURE_FREE_SAFE(txl->renderpass);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb);
+ psl->renderpass_pass = NULL;
+ }
+}
+
+/* Postprocess data to construct a specific renderpass
+ *
+ * This method will create a shading group to perform the post-processing for the given
+ * `renderpass_type`. The post-processing will be done and the result will be stored in the
+ * `vedata->txl->renderpass` texture.
+ *
+ * Only invoke this function for passes that need post-processing.
+ *
+ * After invoking this function the active framebuffer is set to `vedata->fbl->renderpass_fb`. */
+void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ eScenePassType renderpass_type)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ const int current_sample = effects->taa_current_sample;
+
+ DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass);
+ DRW_shgroup_uniform_int_copy(shgrp, "renderpassType", renderpass_type);
+
+ switch (renderpass_type) {
+ case SCE_PASS_Z: {
+ DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_texture_ref(shgrp, "depthBuffer", &dtxl->depth);
+ break;
+ }
+
+ case SCE_PASS_AO: {
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->ao_accum);
+ DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
+ break;
+ }
+
+ case SCE_PASS_NORMAL: {
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &effects->ssr_normal_input);
+ break;
+ }
+
+ case SCE_PASS_MIST: {
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->mist_accum);
+ DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
+ break;
+ }
+
+ case SCE_PASS_SUBSURFACE_DIRECT: {
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->sss_dir_accum);
+ DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
+ break;
+ }
+
+ case SCE_PASS_SUBSURFACE_COLOR: {
+ DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->sss_col_accum);
+ DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
+ break;
+ }
+
+ default: {
+ break;
+ }
+ }
+
+ DRW_shgroup_call(shgrp, DRW_cache_fullscreen_quad_get(), NULL);
+
+ /* only draw the shading group that has been added. This function can be called multiple times
+ * and the pass still hold the previous shading groups.*/
+ GPU_framebuffer_bind(fbl->renderpass_fb);
+ DRW_draw_pass_subset(psl->renderpass_pass, shgrp, shgrp);
+}
+
+void EEVEE_renderpasses_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.postprocess_sh);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
new file mode 100644
index 00000000000..8a543f13fbc
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
@@ -0,0 +1,63 @@
+#define SCE_PASS_Z (1 << 1)
+#define SCE_PASS_AO (1 << 6)
+#define SCE_PASS_NORMAL (1 << 8)
+#define SCE_PASS_MIST (1 << 14)
+#define SCE_PASS_SUBSURFACE_DIRECT (1 << 28)
+#define SCE_PASS_SUBSURFACE_COLOR (1 << 30)
+
+#define ACCUMULATED_COLOR_PASSES (SCE_PASS_SUBSURFACE_DIRECT | SCE_PASS_SUBSURFACE_COLOR)
+#define ACCUMULATED_VALUE_PASSES (SCE_PASS_MIST)
+uniform int renderpassType;
+uniform int currentSample;
+uniform sampler2D inputBuffer;
+
+out vec4 fragColor;
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+
+ if (renderpassType == SCE_PASS_Z) {
+ float depth = texelFetch(depthBuffer, texel, 0).r;
+ if (depth == 1.0f) {
+ depth = 1e10;
+ }
+ else {
+ depth = -get_view_z_from_depth(depth);
+ }
+ fragColor.r = depth;
+ }
+
+ else if (renderpassType == SCE_PASS_AO) {
+ float ao_accum = texelFetch(inputBuffer, texel, 0).r;
+ fragColor = vec4(vec3(min(1.0, ao_accum / currentSample)), 1.0);
+ }
+
+ else if (renderpassType == SCE_PASS_NORMAL) {
+ vec2 encoded_normal = texelFetch(inputBuffer, texel, 0).rg;
+ /* decode the normals only when they are valid. otherwise the result buffer will be filled with
+ * NaN's */
+ if (any(notEqual(encoded_normal, vec2(0.0)))) {
+ vec3 decoded_normal = normal_decode(texelFetch(inputBuffer, texel, 0).rg, vec3(0.0));
+ vec3 world_normal = mat3(ViewMatrixInverse) * decoded_normal;
+ fragColor = vec4(world_normal, 0.0);
+ }
+ else {
+ fragColor = vec4(0.0);
+ }
+ }
+
+ else if ((renderpassType & ACCUMULATED_VALUE_PASSES) != 0) {
+ float accumulated_value = texelFetch(inputBuffer, texel, 0).r;
+ fragColor.r = accumulated_value / currentSample;
+ }
+
+ else if ((renderpassType & ACCUMULATED_COLOR_PASSES) != 0) {
+ vec3 accumulated_color = texelFetch(inputBuffer, texel, 0).rgb;
+ fragColor.rgb = accumulated_color / currentSample;
+ }
+
+ else {
+ fragColor = vec4(1.0, 0.0, 1.0, 1.0);
+ }
+} \ No newline at end of file