2019-11-07 13:14:15 +01:00
|
|
|
/*
|
|
|
|
|
* 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"
|
|
|
|
|
|
2019-11-08 16:47:33 +01:00
|
|
|
#include "DEG_depsgraph_query.h"
|
|
|
|
|
|
2019-11-07 13:14:15 +01:00
|
|
|
#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)
|
|
|
|
|
|
2019-11-08 16:47:33 +01:00
|
|
|
#define EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE (SCE_PASS_Z | SCE_PASS_NORMAL)
|
|
|
|
|
|
|
|
|
|
#define EEVEE_RENDERPASSES_COLOR_PASS (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT)
|
|
|
|
|
|
|
|
|
|
bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata)
|
|
|
|
|
{
|
|
|
|
|
EEVEE_StorageList *stl = vedata->stl;
|
|
|
|
|
EEVEE_PrivateData *g_data = stl->g_data;
|
|
|
|
|
return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-07 13:14:15 +01:00
|
|
|
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;
|
2019-11-08 16:47:33 +01:00
|
|
|
View3D *v3d = draw_ctx->v3d;
|
2019-11-07 13:14:15 +01:00
|
|
|
|
2019-11-08 16:47:33 +01:00
|
|
|
if (v3d) {
|
|
|
|
|
g_data->render_passes = v3d->shading.render_pass;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
g_data->render_passes = (view_layer->passflag & EEVEE_RENDERPASSES_ALL) | SCE_PASS_COMBINED;
|
|
|
|
|
}
|
2019-11-07 13:14:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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: {
|
2019-11-08 16:47:33 +01:00
|
|
|
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
|
2019-11-07 13:14:15 +01:00
|
|
|
DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->ao_accum);
|
|
|
|
|
DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SCE_PASS_NORMAL: {
|
2019-11-08 16:47:33 +01:00
|
|
|
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
|
2019-11-07 13:14:15 +01:00
|
|
|
DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &effects->ssr_normal_input);
|
2019-11-08 16:47:33 +01:00
|
|
|
DRW_shgroup_uniform_texture_ref(shgrp, "depthBuffer", &dtxl->depth);
|
2019-11-07 13:14:15 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SCE_PASS_MIST: {
|
2019-11-08 16:47:33 +01:00
|
|
|
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
|
2019-11-07 13:14:15 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-08 16:47:33 +01:00
|
|
|
void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
|
|
|
|
{
|
|
|
|
|
EEVEE_StorageList *stl = vedata->stl;
|
|
|
|
|
EEVEE_EffectsInfo *effects = stl->effects;
|
|
|
|
|
eScenePassType render_pass = stl->g_data->render_passes;
|
|
|
|
|
|
|
|
|
|
if ((render_pass & SCE_PASS_MIST) != 0) {
|
|
|
|
|
EEVEE_mist_output_accumulate(sldata, vedata);
|
|
|
|
|
}
|
|
|
|
|
if ((effects->enabled_effects & EFFECT_SSS) &&
|
|
|
|
|
(render_pass & EEVEE_RENDERPASSES_SUBSURFACE) != 0) {
|
|
|
|
|
EEVEE_subsurface_output_accumulate(sldata, vedata);
|
|
|
|
|
}
|
|
|
|
|
if ((render_pass & SCE_PASS_AO) != 0) {
|
|
|
|
|
EEVEE_occlusion_output_accumulate(sldata, vedata);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
|
|
|
|
{
|
|
|
|
|
EEVEE_FramebufferList *fbl = vedata->fbl;
|
|
|
|
|
EEVEE_TextureList *txl = vedata->txl;
|
|
|
|
|
EEVEE_StorageList *stl = vedata->stl;
|
|
|
|
|
EEVEE_EffectsInfo *effects = stl->effects;
|
|
|
|
|
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
|
|
|
|
eScenePassType render_pass = stl->g_data->render_passes;
|
|
|
|
|
const DRWContextState *draw_ctx = DRW_context_state_get();
|
|
|
|
|
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
|
|
|
|
|
|
2019-11-29 09:39:28 +01:00
|
|
|
bool is_valid = (render_pass & EEVEE_RENDERPASSES_ALL) > 0;
|
2019-11-08 16:47:33 +01:00
|
|
|
bool needs_color_transfer = (render_pass & EEVEE_RENDERPASSES_COLOR_PASS) > 0 &&
|
|
|
|
|
DRW_state_is_opengl_render();
|
|
|
|
|
|
|
|
|
|
/* When SSS isn't available, but the pass is requested, we mark it as invalid */
|
|
|
|
|
if ((render_pass & EEVEE_RENDERPASSES_SUBSURFACE) != 0 &&
|
|
|
|
|
(effects->enabled_effects & EFFECT_SSS) == 0) {
|
|
|
|
|
is_valid = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* When SSS isn't available, but the pass is requested, we mark it as invalid */
|
|
|
|
|
if ((render_pass & SCE_PASS_AO) != 0 && (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) == 0) {
|
|
|
|
|
is_valid = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int current_sample = stl->effects->taa_current_sample;
|
|
|
|
|
const int total_samples = stl->effects->taa_total_sample;
|
|
|
|
|
if ((render_pass & EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) &&
|
|
|
|
|
(current_sample > 1 && total_samples != 1)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_valid) {
|
|
|
|
|
EEVEE_renderpasses_postprocess(sldata, vedata, render_pass);
|
|
|
|
|
GPU_framebuffer_bind(dfbl->default_fb);
|
|
|
|
|
DRW_transform_to_display(txl->renderpass, needs_color_transfer, false);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Draw state is not valid for this pass, clear the buffer */
|
|
|
|
|
static float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
|
|
|
GPU_framebuffer_bind(dfbl->default_fb);
|
|
|
|
|
GPU_framebuffer_clear_color(dfbl->default_fb, clear_color);
|
|
|
|
|
}
|
|
|
|
|
GPU_framebuffer_bind(fbl->main_fb);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-07 13:14:15 +01:00
|
|
|
void EEVEE_renderpasses_free(void)
|
|
|
|
|
{
|
|
|
|
|
DRW_SHADER_FREE_SAFE(e_data.postprocess_sh);
|
|
|
|
|
}
|