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')
-rw-r--r--source/blender/blenkernel/BKE_appdir.h1
-rw-r--r--source/blender/blenkernel/BKE_layer.h10
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/appdir.c8
-rw-r--r--source/blender/blenkernel/intern/layer.c162
-rw-r--r--source/blender/blenkernel/intern/layer_test.cc177
-rw-r--r--source/blender/blenloader/tests/blendfile_loading_base_test.cc2
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c119
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h19
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c60
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c53
-rw-r--r--source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl13
-rw-r--r--source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl37
-rw-r--r--source/blender/editors/render/render_intern.h2
-rw-r--r--source/blender/editors/render/render_ops.c2
-rw-r--r--source/blender/editors/render/render_shading.c88
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_material.h1
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c37
-rw-r--r--source/blender/gpu/intern/gpu_material.c8
-rw-r--r--source/blender/gpu/intern/gpu_material_library.c7
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c4
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl13
-rw-r--r--source/blender/makesdna/DNA_layer_types.h29
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h1
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_internal.h4
-rw-r--r--source/blender/makesrna/intern/rna_layer.c13
-rw-r--r--source/blender/makesrna/intern/rna_scene.c95
-rw-r--r--source/blender/makesrna/intern/rna_space.c96
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c15
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_aov.c19
-rw-r--r--source/blender/windowmanager/WM_api.h3
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c1
-rw-r--r--source/blender/windowmanager/intern/wm_window.c11
37 files changed, 1061 insertions, 65 deletions
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index 3e52d7f3301..6da6079ea2a 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -26,6 +26,7 @@ extern "C" {
struct ListBase;
void BKE_appdir_init(void);
+void BKE_appdir_exit(void);
/* note on naming: typical _get() suffix is omitted here,
* since its the main purpose of the API. */
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index 7091a060243..e5fab35891c 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -42,6 +42,7 @@ struct Depsgraph;
struct LayerCollection;
struct Main;
struct Object;
+struct RenderEngine;
struct Scene;
struct View3D;
struct ViewLayer;
@@ -444,6 +445,15 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(struct Object *ob, void *user_dat
BKE_view_layer_array_from_objects_in_mode( \
view_layer, v3d, r_len, {.object_mode = mode, .no_dup_data = true})
+struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer);
+void BKE_view_layer_remove_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
+void BKE_view_layer_set_active_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
+void BKE_view_layer_verify_aov(struct RenderEngine *engine,
+ struct Scene *scene,
+ struct ViewLayer *view_layer);
+bool BKE_view_layer_has_valid_aov(struct ViewLayer *view_layer);
+ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene, struct ViewLayerAOV *view_layer_aov);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 1a90d6fadd3..a328c600eac 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -726,6 +726,7 @@ if(WITH_GTESTS)
intern/fcurve_test.cc
intern/lattice_deform_test.cc
intern/tracking_test.cc
+ intern/layer_test.cc
)
set(TEST_INC
../editors/include
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 2038079744d..b1462167edd 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -114,6 +114,14 @@ void BKE_appdir_init(void)
#endif
}
+void BKE_appdir_exit(void)
+{
+#ifndef NDEBUG
+ BLI_assert(is_appdir_init == true);
+ is_appdir_init = false;
+#endif
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 73b330bc0de..6b346d7a337 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -57,6 +57,8 @@
#include "DRW_engine.h"
+#include "RE_engine.h"
+
#include "MEM_guardedalloc.h"
#include "BLO_read_write.h"
@@ -279,6 +281,8 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
}
}
BLI_freelistN(&view_layer->drawdata);
+ BLI_freelistN(&view_layer->aovs);
+ view_layer->active_aov = NULL;
MEM_SAFE_FREE(view_layer->stats);
@@ -412,6 +416,28 @@ void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Bas
}
/**************************** Copy View Layer and Layer Collections ***********************/
+static void layer_aov_copy_data(ViewLayer *view_layer_dst,
+ const ViewLayer *view_layer_src,
+ ListBase *aovs_dst,
+ const ListBase *aovs_src)
+{
+ if (aovs_src != NULL) {
+ BLI_duplicatelist(aovs_dst, aovs_src);
+ }
+
+ ViewLayerAOV *aov_dst = aovs_dst->first;
+ const ViewLayerAOV *aov_src = aovs_src->first;
+
+ while (aov_dst != NULL) {
+ BLI_assert(aov_src);
+ if (aov_src == view_layer_src->active_aov) {
+ view_layer_dst->active_aov = aov_dst;
+ }
+
+ aov_dst = aov_dst->next;
+ aov_src = aov_src->next;
+ }
+}
static void layer_collections_copy_data(ViewLayer *view_layer_dst,
const ViewLayer *view_layer_src,
@@ -482,6 +508,10 @@ void BKE_view_layer_copy_data(Scene *scene_dst,
LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first;
lc_scene_dst->collection = scene_dst->master_collection;
+ BLI_listbase_clear(&view_layer_dst->aovs);
+ layer_aov_copy_data(
+ view_layer_dst, view_layer_src, &view_layer_dst->aovs, &view_layer_src->aovs);
+
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus((ID *)view_layer_dst->mat_override);
}
@@ -1864,6 +1894,9 @@ void BKE_view_layer_blend_write(BlendWriter *writer, ViewLayer *view_layer)
LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
BLO_write_struct(writer, FreestyleLineSet, fls);
}
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ BLO_write_struct(writer, ViewLayerAOV, aov);
+ }
write_layer_collections(writer, &view_layer->layer_collections);
}
@@ -1899,6 +1932,9 @@ void BKE_view_layer_blend_read_data(BlendDataReader *reader, ViewLayer *view_lay
BLO_read_list(reader, &(view_layer->freestyle_config.modules));
BLO_read_list(reader, &(view_layer->freestyle_config.linesets));
+ BLO_read_list(reader, &view_layer->aovs);
+ BLO_read_data_address(reader, &view_layer->active_aov);
+
BLI_listbase_clear(&view_layer->drawdata);
view_layer->object_bases_array = NULL;
view_layer->object_bases_hash = NULL;
@@ -1952,3 +1988,129 @@ void BKE_view_layer_blend_read_lib(BlendLibReader *reader, Library *lib, ViewLay
IDP_BlendReadLib(reader, view_layer->id_properties);
}
+
+/* -------------------------------------------------------------------- */
+/** \name Shader AOV
+ * \{ */
+
+static void viewlayer_aov_make_name_unique(ViewLayer *view_layer)
+{
+ ViewLayerAOV *aov = view_layer->active_aov;
+ if (aov == NULL) {
+ return;
+ }
+ BLI_uniquename(
+ &view_layer->aovs, aov, DATA_("AOV"), '.', offsetof(ViewLayerAOV, name), sizeof(aov->name));
+}
+
+static void viewlayer_aov_active_set(ViewLayer *view_layer, ViewLayerAOV *aov)
+{
+ if (aov != NULL) {
+ BLI_assert(BLI_findindex(&view_layer->aovs, aov) != -1);
+ view_layer->active_aov = aov;
+ }
+ else {
+ view_layer->active_aov = NULL;
+ }
+}
+
+struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer)
+{
+ ViewLayerAOV *aov;
+ aov = MEM_callocN(sizeof(ViewLayerAOV), __func__);
+ aov->type = AOV_TYPE_COLOR;
+ BLI_strncpy(aov->name, DATA_("AOV"), sizeof(aov->name));
+ BLI_addtail(&view_layer->aovs, aov);
+ viewlayer_aov_active_set(view_layer, aov);
+ viewlayer_aov_make_name_unique(view_layer);
+ return aov;
+}
+
+void BKE_view_layer_remove_aov(ViewLayer *view_layer, ViewLayerAOV *aov)
+{
+ BLI_assert(BLI_findindex(&view_layer->aovs, aov) != -1);
+ BLI_assert(aov != NULL);
+ if (view_layer->active_aov == aov) {
+ if (aov->next) {
+ viewlayer_aov_active_set(view_layer, aov->next);
+ }
+ else {
+ viewlayer_aov_active_set(view_layer, aov->prev);
+ }
+ }
+ BLI_freelinkN(&view_layer->aovs, aov);
+}
+
+void BKE_view_layer_set_active_aov(ViewLayer *view_layer, ViewLayerAOV *aov)
+{
+ viewlayer_aov_active_set(view_layer, aov);
+}
+
+static void bke_view_layer_verify_aov_cb(void *userdata,
+ Scene *UNUSED(scene),
+ ViewLayer *UNUSED(view_layer),
+ const char *name,
+ int UNUSED(channels),
+ const char *UNUSED(chanid),
+ int UNUSED(type))
+{
+ GHash *name_count = userdata;
+ void **value_p;
+ void *key = BLI_strdup(name);
+
+ if (!BLI_ghash_ensure_p(name_count, key, &value_p)) {
+ *value_p = POINTER_FROM_INT(1);
+ }
+ else {
+ int value = POINTER_AS_INT(*value_p);
+ value++;
+ *value_p = POINTER_FROM_INT(value);
+ MEM_freeN(key);
+ }
+}
+
+/* Update the naming and conflicts of the AOVs.
+ *
+ * Name must be unique between all AOVs.
+ * Conflicts with render passes will show a conflict icon. Reason is that switching a render
+ * engine or activating a render pass could lead to other conflicts that wouldn't be that clear
+ * for the user. */
+void BKE_view_layer_verify_aov(struct RenderEngine *engine,
+ struct Scene *scene,
+ struct ViewLayer *view_layer)
+{
+ viewlayer_aov_make_name_unique(view_layer);
+
+ GHash *name_count = BLI_ghash_str_new(__func__);
+ RE_engine_update_render_passes(
+ engine, scene, view_layer, bke_view_layer_verify_aov_cb, name_count);
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ void **value_p = BLI_ghash_lookup(name_count, aov->name);
+ int count = POINTER_AS_INT(value_p);
+ SET_FLAG_FROM_TEST(aov->flag, count > 1, AOV_CONFLICT);
+ }
+ BLI_ghash_free(name_count, MEM_freeN, NULL);
+}
+
+/* Check if the given view layer has at least one valid AOV. */
+bool BKE_view_layer_has_valid_aov(ViewLayer *view_layer)
+{
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ if ((aov->flag & AOV_CONFLICT) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene, struct ViewLayerAOV *aov)
+{
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ if (BLI_findindex(&view_layer->aovs, aov) != -1) {
+ return view_layer;
+ }
+ }
+ return NULL;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/layer_test.cc b/source/blender/blenkernel/intern/layer_test.cc
new file mode 100644
index 00000000000..84a96ed0895
--- /dev/null
+++ b/source/blender/blenkernel/intern/layer_test.cc
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2020 by Blender Foundation.
+ */
+#include "testing/testing.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_appdir.h"
+#include "BKE_idtype.h"
+#include "BKE_layer.h"
+
+#include "BLI_string.h"
+
+#include "RE_engine.h"
+
+#include "IMB_imbuf.h"
+
+#include "CLG_log.h"
+
+#include "RNA_access.h"
+
+namespace blender::bke::tests {
+
+TEST(view_layer, aov_unique_names)
+{
+ /* Set Up */
+ CLG_init();
+ BKE_appdir_init();
+ IMB_init();
+ RE_engines_init();
+
+ Scene scene = {{NULL}};
+ IDType_ID_SCE.init_data(&scene.id);
+ ViewLayer *view_layer = static_cast<ViewLayer *>(scene.view_layers.first);
+
+ RenderEngineType *engine_type = RE_engines_find(scene.r.engine);
+ RenderEngine *engine = RE_engine_create(engine_type);
+
+ EXPECT_FALSE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_EQ(view_layer->active_aov, nullptr);
+
+ /* Add an AOV */
+ ViewLayerAOV *aov1 = BKE_view_layer_add_aov(view_layer);
+ BKE_view_layer_verify_aov(engine, &scene, view_layer);
+ EXPECT_EQ(view_layer->active_aov, aov1);
+ EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
+
+ /* Add a second AOV */
+ ViewLayerAOV *aov2 = BKE_view_layer_add_aov(view_layer);
+ BKE_view_layer_verify_aov(engine, &scene, view_layer);
+ EXPECT_EQ(view_layer->active_aov, aov2);
+ EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
+ EXPECT_FALSE((aov2->flag & AOV_CONFLICT) != 0);
+ EXPECT_TRUE(STREQ(aov1->name, "AOV"));
+ EXPECT_TRUE(STREQ(aov2->name, "AOV.001"));
+
+ /* Revert previous resolution */
+ BLI_strncpy(aov2->name, "AOV", MAX_NAME);
+ BKE_view_layer_verify_aov(engine, &scene, view_layer);
+ EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
+ EXPECT_FALSE((aov2->flag & AOV_CONFLICT) != 0);
+ EXPECT_TRUE(STREQ(aov1->name, "AOV"));
+ EXPECT_TRUE(STREQ(aov2->name, "AOV.001"));
+
+ /* Resolve by removing AOV resolution */
+ BKE_view_layer_remove_aov(view_layer, aov2);
+ aov2 = NULL;
+ BKE_view_layer_verify_aov(engine, &scene, view_layer);
+ EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_FALSE((aov1->flag & AOV_CONFLICT) != 0);
+
+ /* Tear down */
+ RE_engine_free(engine);
+ RE_engines_exit();
+ IDType_ID_SCE.free_data(&scene.id);
+ IMB_exit();
+ BKE_appdir_exit();
+ CLG_exit();
+}
+
+static void test_render_pass_conflict(Scene *scene,
+ RenderEngine *engine,
+ ViewLayer *view_layer,
+ ViewLayerAOV *aov,
+ const char *render_pass_name,
+ const char *rna_prop_name)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(&scene->id, &RNA_ViewLayer, view_layer, &ptr);
+ RNA_boolean_set(&ptr, rna_prop_name, false);
+
+ /* Rename to Conflicting name */
+ BLI_strncpy(aov->name, render_pass_name, MAX_NAME);
+ BKE_view_layer_verify_aov(engine, scene, view_layer);
+ EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_FALSE((aov->flag & AOV_CONFLICT) != 0);
+ EXPECT_TRUE(STREQ(aov->name, render_pass_name));
+
+ /* Activate render pass */
+ RNA_boolean_set(&ptr, rna_prop_name, true);
+ BKE_view_layer_verify_aov(engine, scene, view_layer);
+ EXPECT_FALSE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_TRUE((aov->flag & AOV_CONFLICT) != 0);
+ EXPECT_TRUE(STREQ(aov->name, render_pass_name));
+
+ /* Deactivate render pass */
+ RNA_boolean_set(&ptr, rna_prop_name, false);
+ BKE_view_layer_verify_aov(engine, scene, view_layer);
+ EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_FALSE((aov->flag & AOV_CONFLICT) != 0);
+ EXPECT_TRUE(STREQ(aov->name, render_pass_name));
+}
+
+TEST(view_layer, aov_conflict)
+{
+ /* Set Up */
+ CLG_init();
+ BKE_appdir_init();
+ IMB_init();
+ RE_engines_init();
+
+ Scene scene = {{NULL}};
+ IDType_ID_SCE.init_data(&scene.id);
+ ViewLayer *view_layer = static_cast<ViewLayer *>(scene.view_layers.first);
+
+ RenderEngineType *engine_type = RE_engines_find(scene.r.engine);
+ RenderEngine *engine = RE_engine_create(engine_type);
+
+ EXPECT_FALSE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_EQ(view_layer->active_aov, nullptr);
+
+ /* Add an AOV */
+ ViewLayerAOV *aov = BKE_view_layer_add_aov(view_layer);
+ BKE_view_layer_verify_aov(engine, &scene, view_layer);
+ EXPECT_EQ(view_layer->active_aov, aov);
+ EXPECT_TRUE(BKE_view_layer_has_valid_aov(view_layer));
+ EXPECT_FALSE((aov->flag & AOV_CONFLICT) != 0);
+
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "Depth", "use_pass_z");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "Normal", "use_pass_normal");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "Mist", "use_pass_mist");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "Shadow", "use_pass_shadow");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "AO", "use_pass_ambient_occlusion");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "Emit", "use_pass_emit");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "Env", "use_pass_environment");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "DiffDir", "use_pass_diffuse_direct");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "DiffCol", "use_pass_diffuse_color");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "GlossDir", "use_pass_glossy_direct");
+ test_render_pass_conflict(&scene, engine, view_layer, aov, "GlossCol", "use_pass_glossy_color");
+
+ /* Tear down */
+ RE_engine_free(engine);
+ RE_engines_exit();
+ IDType_ID_SCE.free_data(&scene.id);
+ IMB_exit();
+ BKE_appdir_exit();
+ CLG_exit();
+}
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
index a3aabf6ac10..8d8dc3aebf7 100644
--- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc
+++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
@@ -103,7 +103,7 @@ void BlendfileLoadingBaseTest::TearDownTestCase()
BKE_blender_atexit();
BKE_tempdir_session_purge();
-
+ BKE_appdir_exit();
CLG_exit();
testing::Test::TearDownTestCase();
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 5c4ee015c86..47068d0b843 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -240,6 +240,9 @@ void EEVEE_view_layer_data_free(void *storage)
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_light);
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.emit);
DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.environment);
+ for (int aov_index = 0; aov_index < MAX_AOVS; aov_index++) {
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.aovs[aov_index]);
+ }
if (sldata->material_cache) {
BLI_memblock_destroy(sldata->material_cache, NULL);
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 58f182ecf8d..c7a8f7729eb 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -244,31 +244,31 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
/* Create RenderPass UBO */
if (sldata->renderpass_ubo.combined == NULL) {
EEVEE_RenderPassData data;
- data = (EEVEE_RenderPassData){true, true, true, true, true, false, false};
+ data = (EEVEE_RenderPassData){true, true, true, true, true, false, false, false, 0};
sldata->renderpass_ubo.combined = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.combined");
- data = (EEVEE_RenderPassData){true, false, false, false, false, true, false};
+ data = (EEVEE_RenderPassData){true, false, false, false, false, true, false, false, 0};
sldata->renderpass_ubo.diff_color = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.diff_color");
- data = (EEVEE_RenderPassData){true, true, false, false, false, false, false};
+ data = (EEVEE_RenderPassData){true, true, false, false, false, false, false, false, 0};
sldata->renderpass_ubo.diff_light = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.diff_light");
- data = (EEVEE_RenderPassData){false, false, true, false, false, false, false};
+ data = (EEVEE_RenderPassData){false, false, true, false, false, false, false, false, 0};
sldata->renderpass_ubo.spec_color = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.spec_color");
- data = (EEVEE_RenderPassData){false, false, true, true, false, false, false};
+ data = (EEVEE_RenderPassData){false, false, true, true, false, false, false, false, 0};
sldata->renderpass_ubo.spec_light = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.spec_light");
- data = (EEVEE_RenderPassData){false, false, false, false, true, false, false};
+ data = (EEVEE_RenderPassData){false, false, false, false, true, false, false, false, 0};
sldata->renderpass_ubo.emit = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.emit");
- data = (EEVEE_RenderPassData){true, true, true, true, true, false, true};
+ data = (EEVEE_RenderPassData){true, true, true, true, true, false, true, false, 0};
sldata->renderpass_ubo.environment = GPU_uniformbuf_create_ex(
sizeof(data), &data, "renderpass_ubo.environment");
}
@@ -276,6 +276,51 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
/* Used combined pass by default. */
g_data->renderpass_ubo = sldata->renderpass_ubo.combined;
+ {
+ g_data->num_aovs_used = 0;
+ if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_AOV) != 0) {
+ EEVEE_RenderPassData data = {true, true, true, true, true, false, false, true, 0};
+ if (stl->g_data->aov_hash == EEVEE_AOV_HASH_ALL) {
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ int aov_index = 0;
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ if ((aov->flag & AOV_CONFLICT) != 0) {
+ continue;
+ }
+ if (aov_index == MAX_AOVS) {
+ break;
+ }
+ data.renderPassAOVActive = EEVEE_renderpasses_aov_hash(aov);
+ if (sldata->renderpass_ubo.aovs[aov_index]) {
+ GPU_uniformbuf_update(sldata->renderpass_ubo.aovs[aov_index], &data);
+ }
+ else {
+ sldata->renderpass_ubo.aovs[aov_index] = GPU_uniformbuf_create_ex(
+ sizeof(data), &data, "renderpass_ubo.aovs");
+ }
+ aov_index++;
+ }
+ g_data->num_aovs_used = aov_index;
+ }
+ else {
+ /* Rendering a single AOV in the 3d viewport */
+ data.renderPassAOVActive = stl->g_data->aov_hash;
+ if (sldata->renderpass_ubo.aovs[0]) {
+ GPU_uniformbuf_update(sldata->renderpass_ubo.aovs[0], &data);
+ }
+ else {
+ sldata->renderpass_ubo.aovs[0] = GPU_uniformbuf_create_ex(
+ sizeof(data), &data, "renderpass_ubo.aovs");
+ }
+ g_data->num_aovs_used = 1;
+ }
+ }
+ /* Free AOV UBO's that are not in use. */
+ for (int aov_index = g_data->num_aovs_used; aov_index < MAX_AOVS; aov_index++) {
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.aovs[aov_index]);
+ }
+ }
+
/* HACK: EEVEE_material_get can create a new context. This can only be
* done when there is no active framebuffer. We do this here otherwise
* `EEVEE_renderpasses_output_init` will fail. It cannot be done in
@@ -949,6 +994,11 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) {
material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear);
}
+ if (pd->render_passes & EEVEE_RENDER_PASS_AOV) {
+ for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) {
+ material_renderpass_init(fbl, &txl->aov_surface_accum[aov_index], texture_format, do_clear);
+ }
+ }
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear);
@@ -960,6 +1010,7 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl,
DRWPass *renderpass,
+ DRWPass *renderpass2,
EEVEE_PrivateData *pd,
GPUTexture *output_tx,
struct GPUUniformBuf *renderpass_option_ubo)
@@ -969,6 +1020,9 @@ static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl,
pd->renderpass_ubo = renderpass_option_ubo;
DRW_draw_pass(renderpass);
+ if (renderpass2) {
+ DRW_draw_pass(renderpass2);
+ }
GPU_framebuffer_texture_detach(fbl->material_accum_fb, output_tx);
}
@@ -983,38 +1037,69 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
if (fbl->material_accum_fb != NULL) {
DRWPass *material_accum_ps = psl->material_accum_ps;
+ DRWPass *background_accum_ps = psl->background_accum_ps;
if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) {
material_renderpass_accumulate(
- fbl, psl->background_accum_ps, pd, txl->env_accum, sldata->renderpass_ubo.environment);
+ fbl, background_accum_ps, NULL, pd, txl->env_accum, sldata->renderpass_ubo.environment);
}
if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) {
material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->emit_accum, sldata->renderpass_ubo.emit);
+ fbl, material_accum_ps, NULL, pd, txl->emit_accum, sldata->renderpass_ubo.emit);
}
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) {
- material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->diff_color_accum, sldata->renderpass_ubo.diff_color);
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ NULL,
+ pd,
+ txl->diff_color_accum,
+ sldata->renderpass_ubo.diff_color);
}
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) {
- material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->diff_light_accum, sldata->renderpass_ubo.diff_light);
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ NULL,
+ pd,
+ txl->diff_light_accum,
+ sldata->renderpass_ubo.diff_light);
if (effects->enabled_effects & EFFECT_SSS) {
EEVEE_subsurface_output_accumulate(sldata, vedata);
}
}
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) {
- material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->spec_color_accum, sldata->renderpass_ubo.spec_color);
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ NULL,
+ pd,
+ txl->spec_color_accum,
+ sldata->renderpass_ubo.spec_color);
}
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
- material_renderpass_accumulate(
- fbl, material_accum_ps, pd, txl->spec_light_accum, sldata->renderpass_ubo.spec_light);
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ NULL,
+ pd,
+ txl->spec_light_accum,
+ sldata->renderpass_ubo.spec_light);
if (effects->enabled_effects & EFFECT_SSR) {
EEVEE_reflection_output_accumulate(sldata, vedata);
}
}
+ if (pd->render_passes & EEVEE_RENDER_PASS_AOV) {
+ for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) {
+ material_renderpass_accumulate(fbl,
+ material_accum_ps,
+ background_accum_ps,
+ pd,
+ txl->aov_surface_accum[aov_index],
+ sldata->renderpass_ubo.aovs[aov_index]);
+ }
+ }
+ /* Free unused aov textures. */
+ for (int aov_index = pd->num_aovs_used; aov_index < MAX_AOVS; aov_index++) {
+ DRW_TEXTURE_FREE_SAFE(txl->aov_surface_accum[aov_index]);
+ }
/* Restore default. */
pd->renderpass_ubo = sldata->renderpass_ubo.combined;
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index f5cef8f3c25..1385721a569 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -53,6 +53,7 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define MAX_SHADOW_CASCADE 8
#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
#define MAX_BLOOM_STEP 16
+#define MAX_AOVS 64
// #define DEBUG_SHADOW_DISTRIBUTION
@@ -163,8 +164,9 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d)
#define EEVEE_RENDERPASSES_MATERIAL \
(EEVEE_RENDER_PASS_EMIT | EEVEE_RENDER_PASS_DIFFUSE_COLOR | EEVEE_RENDER_PASS_DIFFUSE_LIGHT | \
EEVEE_RENDER_PASS_SPECULAR_COLOR | EEVEE_RENDER_PASS_SPECULAR_LIGHT | \
- EEVEE_RENDER_PASS_ENVIRONMENT)
-
+ EEVEE_RENDER_PASS_ENVIRONMENT | EEVEE_RENDER_PASS_AOV)
+#define EEVEE_AOV_HASH_ALL -1
+#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1
/* Material shader variations */
enum {
VAR_MAT_MESH = (1 << 0),
@@ -376,6 +378,7 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *diff_light_accum;
struct GPUTexture *spec_color_accum;
struct GPUTexture *spec_light_accum;
+ struct GPUTexture *aov_surface_accum[MAX_AOVS];
struct GPUTexture *emit_accum;
struct GPUTexture *bloom_accum;
struct GPUTexture *ssr_accum;
@@ -430,7 +433,9 @@ typedef struct EEVEE_RenderPassData {
int renderPassEmit;
int renderPassSSSColor;
int renderPassEnvironment;
- int _pad[1];
+ int renderPassAOV;
+ int renderPassAOVActive;
+ int _pad[3];
} EEVEE_RenderPassData;
/* ************ LIGHT UBO ************* */
@@ -860,6 +865,7 @@ typedef struct EEVEE_ViewLayerData {
struct GPUUniformBuf *spec_color;
struct GPUUniformBuf *spec_light;
struct GPUUniformBuf *emit;
+ struct GPUUniformBuf *aovs[MAX_AOVS];
} renderpass_ubo;
/* Common Uniform Buffer */
@@ -959,6 +965,9 @@ typedef struct EEVEE_PrivateData {
/* Renderpasses */
/* Bitmask containing the active render_passes */
eViewLayerEEVEEPassType render_passes;
+ int aov_hash;
+ int num_aovs_used;
+
/* Uniform references that are referenced inside the `renderpass_pass`. They are updated
* to reuse the drawing pass and the shading group. */
int renderpass_type;
@@ -1284,10 +1293,12 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata,
bool post_effect);
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
- eViewLayerEEVEEPassType renderpass_type);
+ eViewLayerEEVEEPassType renderpass_type,
+ int aov_index);
void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata);
bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata);
+int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov);
/* eevee_temporal_sampling.c */
void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index 504e4e1d336..32e6eac2402 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -301,7 +301,7 @@ static void eevee_render_result_normal(RenderLayer *rl,
}
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_NORMAL) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_NORMAL);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_NORMAL, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_NORMAL, 3, vedata->fbl->renderpass_fb, vedata);
}
@@ -321,7 +321,7 @@ static void eevee_render_result_z(RenderLayer *rl,
}
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_Z) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_Z);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_Z, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_Z, 1, vedata->fbl->renderpass_fb, vedata);
}
@@ -334,7 +334,7 @@ static void eevee_render_result_mist(RenderLayer *rl,
EEVEE_ViewLayerData *sldata)
{
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_MIST) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_MIST);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_MIST, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_MIST, 1, vedata->fbl->renderpass_fb, vedata);
}
@@ -347,7 +347,7 @@ static void eevee_render_result_shadow(RenderLayer *rl,
EEVEE_ViewLayerData *sldata)
{
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_SHADOW) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_SHADOW);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_SHADOW, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_SHADOW, 3, vedata->fbl->renderpass_fb, vedata);
}
@@ -360,7 +360,7 @@ static void eevee_render_result_occlusion(RenderLayer *rl,
EEVEE_ViewLayerData *sldata)
{
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_AO) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AO);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AO, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_AO, 3, vedata->fbl->renderpass_fb, vedata);
}
@@ -378,7 +378,7 @@ static void eevee_render_result_bloom(RenderLayer *rl,
}
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_BLOOM) != 0) {
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_BLOOM);
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_BLOOM, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_BLOOM, 3, vedata->fbl->renderpass_fb, vedata);
}
@@ -386,7 +386,7 @@ static void eevee_render_result_bloom(RenderLayer *rl,
#define EEVEE_RENDER_RESULT_MATERIAL_PASS(pass_name, eevee_pass_type) \
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_##eevee_pass_type) != 0) { \
- EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_##eevee_pass_type); \
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_##eevee_pass_type, 0); \
eevee_render_color_result( \
rl, viewname, rect, RE_PASSNAME_##pass_name, 3, vedata->fbl->renderpass_fb, vedata); \
}
@@ -462,6 +462,35 @@ static void eevee_render_result_volume_transmittance(RenderLayer *rl,
EEVEE_RENDER_RESULT_MATERIAL_PASS(VOLUME_TRANSMITTANCE, VOLUME_TRANSMITTANCE)
}
+static void eevee_render_result_aovs(RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect,
+ EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata)
+{
+ if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_AOV) != 0) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ int aov_index = 0;
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ if ((aov->flag & AOV_CONFLICT) != 0) {
+ continue;
+ }
+ EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_AOV, aov_index);
+ switch (aov->type) {
+ case AOV_TYPE_COLOR:
+ eevee_render_color_result(
+ rl, viewname, rect, aov->name, 4, vedata->fbl->renderpass_fb, vedata);
+ break;
+ case AOV_TYPE_VALUE:
+ eevee_render_color_result(
+ rl, viewname, rect, aov->name, 1, vedata->fbl->renderpass_fb, vedata);
+ }
+ aov_index++;
+ }
+ }
+}
+
#undef EEVEE_RENDER_RESULT_MATERIAL_PASS
static void eevee_render_draw_background(EEVEE_Data *vedata)
@@ -641,6 +670,7 @@ void EEVEE_render_read_result(EEVEE_Data *vedata,
eevee_render_result_bloom(rl, viewname, rect, vedata, sldata);
eevee_render_result_volume_scatter(rl, viewname, rect, vedata, sldata);
eevee_render_result_volume_transmittance(rl, viewname, rect, vedata, sldata);
+ eevee_render_result_aovs(rl, viewname, rect, vedata, sldata);
}
void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
@@ -675,6 +705,22 @@ void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *v
CHECK_PASS_EEVEE(VOLUME_TRANSMITTANCE, SOCK_RGBA, 3, "RGB");
CHECK_PASS_EEVEE(BLOOM, SOCK_RGBA, 3, "RGB");
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ if ((aov->flag & AOV_CONFLICT) != 0) {
+ continue;
+ }
+ switch (aov->type) {
+ case AOV_TYPE_COLOR:
+ RE_engine_register_pass(engine, scene, view_layer, aov->name, 4, "RGBA", SOCK_RGBA);
+ break;
+ case AOV_TYPE_VALUE:
+ RE_engine_register_pass(engine, scene, view_layer, aov->name, 1, "X", SOCK_FLOAT);
+ break;
+ default:
+ break;
+ }
+ }
+
#undef CHECK_PASS_LEGACY
#undef CHECK_PASS_EEVEE
}
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
index be73225b348..3f75f10b204 100644
--- a/source/blender/draw/engines/eevee/eevee_renderpasses.c
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -27,6 +27,7 @@
#include "BKE_global.h" /* for G.debug_value */
+#include "BLI_hash.h"
#include "BLI_string_utils.h"
#include "DEG_depsgraph_query.h"
@@ -36,12 +37,13 @@
typedef enum eRenderPassPostProcessType {
PASS_POST_UNDEFINED = 0,
PASS_POST_ACCUMULATED_COLOR = 1,
- PASS_POST_ACCUMULATED_LIGHT = 2,
- PASS_POST_ACCUMULATED_VALUE = 3,
- PASS_POST_DEPTH = 4,
- PASS_POST_AO = 5,
- PASS_POST_NORMAL = 6,
- PASS_POST_TWO_LIGHT_BUFFERS = 7,
+ PASS_POST_ACCUMULATED_COLOR_ALPHA = 2,
+ PASS_POST_ACCUMULATED_LIGHT = 3,
+ PASS_POST_ACCUMULATED_VALUE = 4,
+ PASS_POST_DEPTH = 5,
+ PASS_POST_AO = 6,
+ PASS_POST_NORMAL = 7,
+ PASS_POST_TWO_LIGHT_BUFFERS = 8,
} eRenderPassPostProcessType;
/* bitmask containing all renderpasses that need post-processing */
@@ -70,6 +72,15 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata)
return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0;
}
+/* Calculate the hash for an AOV. The least significant bit is used to store the AOV
+ * type the rest of the bits are used for the name hash. */
+int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov)
+{
+ int hash = BLI_hash_string(aov->name);
+ SET_FLAG_FROM_TEST(hash, aov->type == AOV_TYPE_COLOR, EEVEE_AOV_HASH_COLOR_TYPE_MASK);
+ return hash;
+}
+
void EEVEE_renderpasses_init(EEVEE_Data *vedata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -81,10 +92,24 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata)
if (v3d) {
const Scene *scene = draw_ctx->scene;
eViewLayerEEVEEPassType render_pass = v3d->shading.render_pass;
+ g_data->aov_hash = 0;
+
if (render_pass == EEVEE_RENDER_PASS_BLOOM &&
((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) {
render_pass = EEVEE_RENDER_PASS_COMBINED;
}
+ if (render_pass == EEVEE_RENDER_PASS_AOV) {
+ ViewLayerAOV *aov = BLI_findstring(
+ &view_layer->aovs, v3d->shading.aov_name, offsetof(ViewLayerAOV, name));
+ if (aov != NULL) {
+ g_data->aov_hash = EEVEE_renderpasses_aov_hash(aov);
+ }
+ else {
+ /* AOV not found in view layer. */
+ render_pass = EEVEE_RENDER_PASS_COMBINED;
+ }
+ }
+
g_data->render_passes = render_pass;
}
else {
@@ -110,10 +135,14 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata)
ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT)
#undef ENABLE_FROM_LEGACY
+ if (DRW_state_is_image_render() && !BLI_listbase_is_empty(&view_layer->aovs)) {
+ enabled_render_passes |= EEVEE_RENDER_PASS_AOV;
+ g_data->aov_hash = EEVEE_AOV_HASH_ALL;
+ }
+
g_data->render_passes = (enabled_render_passes & EEVEE_RENDERPASSES_ALL) |
EEVEE_RENDER_PASS_COMBINED;
}
-
EEVEE_material_renderpasses_init(vedata);
}
@@ -216,7 +245,8 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
* After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`. */
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
EEVEE_Data *vedata,
- eViewLayerEEVEEPassType renderpass_type)
+ eViewLayerEEVEEPassType renderpass_type,
+ int aov_index)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_TextureList *txl = vedata->txl;
@@ -311,6 +341,11 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
}
break;
}
+ case EEVEE_RENDER_PASS_AOV: {
+ g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR_ALPHA;
+ g_data->renderpass_input = txl->aov_surface_accum[aov_index];
+ break;
+ }
case EEVEE_RENDER_PASS_BLOOM: {
g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR;
g_data->renderpass_input = txl->bloom_accum;
@@ -392,7 +427,7 @@ void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
if (is_valid) {
- EEVEE_renderpasses_postprocess(sldata, vedata, render_pass);
+ EEVEE_renderpasses_postprocess(sldata, vedata, render_pass, 0);
GPU_framebuffer_bind(dfbl->default_fb);
DRW_transform_none(txl->renderpass);
}
diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
index 36cf3cecf40..3e0a5e76d00 100644
--- a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
@@ -1,3 +1,4 @@
+#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1
/* ---------------------------------------------------------------------- */
/** \name Resources
@@ -12,6 +13,8 @@ layout(std140) uniform renderpass_block
bool renderPassEmit;
bool renderPassSSSColor;
bool renderPassEnvironment;
+ bool renderPassAOV;
+ int renderPassAOVActive;
};
/** \} */
@@ -40,4 +43,14 @@ vec3 render_pass_emission_mask(vec3 emission_light)
return renderPassEmit ? emission_light : vec3(0.0);
}
+bool render_pass_aov_is_color()
+{
+ return (renderPassAOVActive & EEVEE_AOV_HASH_COLOR_TYPE_MASK) != 0;
+}
+
+int render_pass_aov_hash()
+{
+ return renderPassAOVActive & ~EEVEE_AOV_HASH_COLOR_TYPE_MASK;
+}
+
/** \} */
diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
index 89a411bc7cb..eb6ca4b9de8 100644
--- a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl
@@ -4,12 +4,13 @@
#define PASS_POST_UNDEFINED 0
#define PASS_POST_ACCUMULATED_COLOR 1
-#define PASS_POST_ACCUMULATED_LIGHT 2
-#define PASS_POST_ACCUMULATED_VALUE 3
-#define PASS_POST_DEPTH 4
-#define PASS_POST_AO 5
-#define PASS_POST_NORMAL 6
-#define PASS_POST_TWO_LIGHT_BUFFERS 7
+#define PASS_POST_ACCUMULATED_COLOR_ALPHA 2
+#define PASS_POST_ACCUMULATED_LIGHT 3
+#define PASS_POST_ACCUMULATED_VALUE 4
+#define PASS_POST_DEPTH 5
+#define PASS_POST_AO 6
+#define PASS_POST_NORMAL 7
+#define PASS_POST_TWO_LIGHT_BUFFERS 8
uniform int postProcessType;
uniform int currentSample;
@@ -55,7 +56,7 @@ vec3 safe_divide_even_color(vec3 a, vec3 b)
void main()
{
- vec3 color;
+ vec4 color = vec4(0.0, 0.0, 0.0, 1.0);
ivec2 texel = ivec2(gl_FragCoord.xy);
if (postProcessType == PASS_POST_DEPTH) {
@@ -66,11 +67,11 @@ void main()
else {
depth = -get_view_z_from_depth(depth);
}
- color = vec3(depth);
+ color.rgb = vec3(depth);
}
else if (postProcessType == PASS_POST_AO) {
float ao_accum = texelFetch(inputBuffer, texel, 0).r;
- color = vec3(min(1.0, ao_accum / currentSample));
+ color.rgb = vec3(min(1.0, ao_accum / currentSample));
}
else if (postProcessType == PASS_POST_NORMAL) {
float depth = texelFetch(depthBuffer, texel, 0).r;
@@ -80,35 +81,39 @@ void main()
if (depth != 1.0 && 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;
- color = world_normal;
+ color.rgb = world_normal;
}
else {
- color = vec3(0.0);
+ color.rgb = vec3(0.0);
}
}
else if (postProcessType == PASS_POST_ACCUMULATED_VALUE) {
float accumulated_value = texelFetch(inputBuffer, texel, 0).r;
- color = vec3(accumulated_value / currentSample);
+ color.rgb = vec3(accumulated_value / currentSample);
}
else if (postProcessType == PASS_POST_ACCUMULATED_COLOR) {
vec3 accumulated_color = texelFetch(inputBuffer, texel, 0).rgb;
+ color.rgb = (accumulated_color / currentSample);
+ }
+ else if (postProcessType == PASS_POST_ACCUMULATED_COLOR_ALPHA) {
+ vec4 accumulated_color = texelFetch(inputBuffer, texel, 0);
color = (accumulated_color / currentSample);
}
else if (postProcessType == PASS_POST_ACCUMULATED_LIGHT) {
vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb;
vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb;
- color = safe_divide_even_color(accumulated_light, accumulated_color);
+ color.rgb = safe_divide_even_color(accumulated_light, accumulated_color);
}
else if (postProcessType == PASS_POST_TWO_LIGHT_BUFFERS) {
vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb +
texelFetch(inputSecondLightBuffer, texel, 0).rgb;
vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb;
- color = safe_divide_even_color(accumulated_light, accumulated_color);
+ color.rgb = safe_divide_even_color(accumulated_light, accumulated_color);
}
else {
/* Output error color: Unknown how to post process this pass. */
- color = vec3(1.0, 0.0, 1.0);
+ color.rgb = vec3(1.0, 0.0, 1.0);
}
- fragColor = vec4(color, 1.0);
+ fragColor = color;
}
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index d3a06f0fc2c..e1d03e6f3be 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -46,6 +46,8 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot);
void SCENE_OT_view_layer_add(struct wmOperatorType *ot);
void SCENE_OT_view_layer_remove(struct wmOperatorType *ot);
+void SCENE_OT_view_layer_add_aov(struct wmOperatorType *ot);
+void SCENE_OT_view_layer_remove_aov(struct wmOperatorType *ot);
void SCENE_OT_light_cache_bake(struct wmOperatorType *ot);
void SCENE_OT_light_cache_free(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c
index 706249a3f8b..e0aa02b354d 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.c
@@ -53,6 +53,8 @@ void ED_operatortypes_render(void)
WM_operatortype_append(SCENE_OT_view_layer_add);
WM_operatortype_append(SCENE_OT_view_layer_remove);
+ WM_operatortype_append(SCENE_OT_view_layer_add_aov);
+ WM_operatortype_append(SCENE_OT_view_layer_remove_aov);
WM_operatortype_append(SCENE_OT_render_view_add);
WM_operatortype_append(SCENE_OT_render_view_remove);
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 60e5c2081fd..b69337b1621 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -90,6 +90,7 @@
#include "UI_interface.h"
+#include "RE_engine.h"
#include "RE_pipeline.h"
#include "engines/eevee/eevee_lightcache.h"
@@ -1014,6 +1015,93 @@ void SCENE_OT_view_layer_remove(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name View Layer Add AOV Operator
+ * \{ */
+
+static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ BKE_view_layer_add_aov(view_layer);
+
+ RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
+ if (engine_type->update_render_passes) {
+ RenderEngine *engine = RE_engine_create(engine_type);
+ if (engine) {
+ BKE_view_layer_verify_aov(engine, scene, view_layer);
+ }
+ RE_engine_free(engine);
+ engine = NULL;
+ }
+
+ DEG_id_tag_update(&scene->id, 0);
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_view_layer_add_aov(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add AOV";
+ ot->idname = "SCENE_OT_view_layer_add_aov";
+ ot->description = "Add a Shader AOV";
+
+ /* api callbacks */
+ ot->exec = view_layer_add_aov_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Layer Remove AOV Operator
+ * \{ */
+
+static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BKE_view_layer_remove_aov(view_layer, view_layer->active_aov);
+
+ RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
+ if (engine_type->update_render_passes) {
+ RenderEngine *engine = RE_engine_create(engine_type);
+ if (engine) {
+ BKE_view_layer_verify_aov(engine, scene, view_layer);
+ }
+ RE_engine_free(engine);
+ engine = NULL;
+ }
+
+ DEG_id_tag_update(&scene->id, 0);
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_view_layer_remove_aov(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove AOV";
+ ot->idname = "SCENE_OT_view_layer_remove_aov";
+ ot->description = "Remove Active AOV";
+
+ /* api callbacks */
+ ot->exec = view_layer_remove_aov_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Light Cache Bake Operator
* \{ */
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 7e2fe753b7b..69a79e2f2ce 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -313,6 +313,7 @@ data_to_c_simple(shaders/material/gpu_shader_material_noise.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_normal.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_normal_map.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_object_info.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_output_aov.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_output_material.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_output_world.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_particle_info.glsl SRC)
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 67cd1a61aed..312da491a36 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -173,6 +173,7 @@ GPUNodeLink *GPU_uniformbuf_link_out(struct GPUMaterial *mat,
const int index);
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
+void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash);
void GPU_material_sss_profile_create(GPUMaterial *material,
float radii[3],
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 3ebe2edc89e..84da95f6fee 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -411,7 +411,7 @@ static void codegen_declare_tmps(DynStr *ds, GPUNodeGraph *graph)
BLI_dynstr_append(ds, "\n");
}
-static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *finaloutput)
+static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph)
{
LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
BLI_dynstr_appendf(ds, " %s(", node->name);
@@ -509,8 +509,11 @@ static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *f
BLI_dynstr_append(ds, ");\n");
}
+}
- BLI_dynstr_appendf(ds, "\n return tmp%d;\n", finaloutput->id);
+static void codegen_final_output(DynStr *ds, GPUOutput *finaloutput)
+{
+ BLI_dynstr_appendf(ds, "return tmp%d;\n", finaloutput->id);
}
static char *code_generate_fragment(GPUMaterial *material,
@@ -593,7 +596,35 @@ static char *code_generate_fragment(GPUMaterial *material,
}
codegen_declare_tmps(ds, graph);
- codegen_call_functions(ds, graph, graph->outlink->output);
+ codegen_call_functions(ds, graph);
+
+ BLI_dynstr_append(ds, " #ifndef VOLUMETRICS\n");
+ BLI_dynstr_append(ds, " if (renderPassAOV) {\n");
+ BLI_dynstr_append(ds, " switch (render_pass_aov_hash()) {\n");
+ GSet *aovhashes_added = BLI_gset_int_new(__func__);
+ LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) {
+ void *aov_key = POINTER_FROM_INT(aovlink->hash);
+ if (BLI_gset_haskey(aovhashes_added, aov_key)) {
+ continue;
+ }
+ BLI_dynstr_appendf(ds, " case %d: {\n ", aovlink->hash);
+ codegen_final_output(ds, aovlink->outlink->output);
+ BLI_dynstr_append(ds, " }\n");
+ BLI_gset_add(aovhashes_added, aov_key);
+ }
+ BLI_gset_free(aovhashes_added, NULL);
+ BLI_dynstr_append(ds, " default: {\n");
+ BLI_dynstr_append(ds, " Closure no_aov = CLOSURE_DEFAULT;\n");
+ BLI_dynstr_append(ds, " no_aov.holdout = 1.0;\n");
+ BLI_dynstr_append(ds, " return no_aov;\n");
+ BLI_dynstr_append(ds, " }\n");
+ BLI_dynstr_append(ds, " }\n");
+ BLI_dynstr_append(ds, " } else {\n");
+ BLI_dynstr_append(ds, " #else /* VOLUMETRICS */\n");
+ BLI_dynstr_append(ds, " {\n");
+ BLI_dynstr_append(ds, " #endif /* VOLUMETRICS */\n ");
+ codegen_final_output(ds, graph->outlink->output);
+ BLI_dynstr_append(ds, " }\n");
BLI_dynstr_append(ds, "}\n");
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index a0fe77598f2..3f22424c7c9 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -597,6 +597,14 @@ void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
}
}
+void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash)
+{
+ GPUNodeGraphOutputLink *aov_link = MEM_callocN(sizeof(GPUNodeGraphOutputLink), __func__);
+ aov_link->outlink = link;
+ aov_link->hash = hash;
+ BLI_addtail(&material->graph.outlink_aovs, aov_link);
+}
+
GPUNodeGraph *gpu_material_node_graph(GPUMaterial *material)
{
return &material->graph;
diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c
index e0165e1fa83..496988c4ba9 100644
--- a/source/blender/gpu/intern/gpu_material_library.c
+++ b/source/blender/gpu/intern/gpu_material_library.c
@@ -84,6 +84,7 @@ extern char datatoc_gpu_shader_material_noise_glsl[];
extern char datatoc_gpu_shader_material_normal_glsl[];
extern char datatoc_gpu_shader_material_normal_map_glsl[];
extern char datatoc_gpu_shader_material_object_info_glsl[];
+extern char datatoc_gpu_shader_material_output_aov_glsl[];
extern char datatoc_gpu_shader_material_output_material_glsl[];
extern char datatoc_gpu_shader_material_output_world_glsl[];
extern char datatoc_gpu_shader_material_particle_info_glsl[];
@@ -354,6 +355,11 @@ static GPUMaterialLibrary gpu_shader_material_object_info_library = {
.dependencies = {NULL},
};
+static GPUMaterialLibrary gpu_shader_material_output_aov_library = {
+ .code = datatoc_gpu_shader_material_output_aov_glsl,
+ .dependencies = {NULL},
+};
+
static GPUMaterialLibrary gpu_shader_material_output_material_library = {
.code = datatoc_gpu_shader_material_output_material_glsl,
.dependencies = {NULL},
@@ -619,6 +625,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = {
&gpu_shader_material_normal_library,
&gpu_shader_material_normal_map_library,
&gpu_shader_material_object_info_library,
+ &gpu_shader_material_output_aov_library,
&gpu_shader_material_output_material_library,
&gpu_shader_material_output_world_library,
&gpu_shader_material_particle_info_library,
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 2a2a51e32b3..08da49c3475 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -805,6 +805,7 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
/* Free both node graph and requested attributes and textures. */
void gpu_node_graph_free(GPUNodeGraph *graph)
{
+ BLI_freelistN(&graph->outlink_aovs);
gpu_node_graph_free_nodes(graph);
LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) {
@@ -847,6 +848,9 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
}
gpu_nodes_tag(graph->outlink);
+ LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) {
+ gpu_nodes_tag(aovlink->outlink);
+ }
for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) {
next = node->next;
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index a0e6298cd92..0ef95d94c0d 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -141,12 +141,20 @@ typedef struct GPUInput {
};
} GPUInput;
+typedef struct GPUNodeGraphOutputLink {
+ struct GPUNodeGraphOutputLink *next, *prev;
+ int hash;
+ GPUNodeLink *outlink;
+} GPUNodeGraphOutputLink;
+
typedef struct GPUNodeGraph {
/* Nodes */
ListBase nodes;
- /* Output. */
+ /* Main Output. */
GPUNodeLink *outlink;
+ /* List of GPUNodeGraphOutputLink */
+ ListBase outlink_aovs;
/* Requested attributes and textures. */
ListBase attributes;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl
new file mode 100644
index 00000000000..648994739bf
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl
@@ -0,0 +1,13 @@
+
+void node_output_aov(vec4 color, float value, out Closure result)
+{
+ result = CLOSURE_DEFAULT;
+#ifndef VOLUMETRICS
+ if (render_pass_aov_is_color()) {
+ result.radiance = color.rgb;
+ }
+ else {
+ result.radiance = vec3(value);
+ }
+#endif
+}
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 85065ba35d4..f2e3e0a3c9c 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -47,8 +47,20 @@ typedef enum eViewLayerEEVEEPassType {
EEVEE_RENDER_PASS_SHADOW = (1 << 12),
EEVEE_RENDER_PASS_AO = (1 << 13),
EEVEE_RENDER_PASS_BLOOM = (1 << 14),
+ EEVEE_RENDER_PASS_AOV = (1 << 15),
} eViewLayerEEVEEPassType;
-#define EEVEE_RENDER_PASS_MAX_BIT 15
+#define EEVEE_RENDER_PASS_MAX_BIT 16
+
+/* ViewLayerAOV.type */
+typedef enum eViewLayerAOVType {
+ AOV_TYPE_VALUE = 0,
+ AOV_TYPE_COLOR = 1,
+} eViewLayerAOVType;
+
+/* ViewLayerAOV.type */
+typedef enum eViewLayerAOVFlag {
+ AOV_CONFLICT = (1 << 0),
+} eViewLayerAOVFlag;
typedef struct Base {
struct Base *next, *prev;
@@ -104,6 +116,17 @@ typedef struct ViewLayerEEVEE {
int _pad[1];
} ViewLayerEEVEE;
+/* AOV Renderpass definition. */
+typedef struct ViewLayerAOV {
+ struct ViewLayerAOV *next, *prev;
+
+ /* Name of the AOV */
+ char name[64];
+ int flag;
+ /* Type of AOV (color/value)
+ * matches `eViewLayerAOVType` */
+ int type;
+} ViewLayerAOV;
typedef struct ViewLayer {
struct ViewLayer *next, *prev;
/** MAX_NAME. */
@@ -136,6 +159,10 @@ typedef struct ViewLayer {
struct FreestyleConfig freestyle_config;
struct ViewLayerEEVEE eevee;
+ /* List containing the `ViewLayerAOV`s */
+ ListBase aovs;
+ ViewLayerAOV *active_aov;
+
/* Runtime data */
/** ViewLayerEngineData. */
ListBase drawdata;
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 9a233878840..b8e2256c3c6 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -192,6 +192,7 @@ typedef struct View3DShading {
/* Render pass displayed in the viewport. Is an `eScenePassType` where one bit is set */
int render_pass;
+ char aov_name[64];
struct IDProperty *prop;
void *_pad2;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index f51202348b5..a581edcb04b 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -60,6 +60,7 @@ extern StructRNA RNA_AnimData;
extern StructRNA RNA_AnimViz;
extern StructRNA RNA_AnimVizMotionPaths;
extern StructRNA RNA_AnyType;
+extern StructRNA RNA_AOV;
extern StructRNA RNA_Area;
extern StructRNA RNA_AreaLight;
extern StructRNA RNA_Armature;
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 31e920a6799..1c6f83efd65 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -345,6 +345,10 @@ void rna_ViewLayer_material_override_update(struct Main *bmain,
void rna_ViewLayer_pass_update(struct Main *bmain,
struct Scene *activescene,
struct PointerRNA *ptr);
+void rna_ViewLayer_active_aov_index_range(
+ PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax);
+int rna_ViewLayer_active_aov_index_get(PointerRNA *ptr);
+void rna_ViewLayer_active_aov_index_set(PointerRNA *ptr, int value);
/* named internal so as not to conflict with obj.update() rna func */
void rna_Object_internal_update_data(struct Main *bmain,
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index c7a53757296..0dcbd8a070b 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -152,7 +152,18 @@ static void rna_ViewLayer_update_render_passes(ID *id)
if (scene->nodetree) {
ntreeCompositUpdateRLayers(scene->nodetree);
}
-}
+
+ RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
+ if (engine_type->update_render_passes) {
+ RenderEngine *engine = RE_engine_create(engine_type);
+ if (engine) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ BKE_view_layer_verify_aov(engine, scene, view_layer);
+ }
+ }
+ RE_engine_free(engine);
+ engine = NULL;
+ }}
static PointerRNA rna_ViewLayer_objects_get(CollectionPropertyIterator *iter)
{
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 235042122e6..0f13ba29d3b 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -529,6 +529,12 @@ const EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_view_layer_aov_type_items[] = {
+ {AOV_TYPE_COLOR, "COLOR", 0, "Color", ""},
+ {AOV_TYPE_VALUE, "VALUE", 0, "Value", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
static const EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
/* interpolation */
@@ -1779,6 +1785,27 @@ void rna_ViewLayer_pass_update(Main *bmain, Scene *activescene, PointerRNA *ptr)
ntreeCompositUpdateRLayers(scene->nodetree);
}
+ ViewLayer *view_layer = NULL;
+ if (ptr->type == &RNA_ViewLayer) {
+ view_layer = (ViewLayer *)ptr->data;
+ }
+ else if (ptr->type == &RNA_AOV) {
+ ViewLayerAOV *aov = (ViewLayerAOV *)ptr->data;
+ view_layer = BKE_view_layer_find_with_aov(scene, aov);
+ }
+
+ if (view_layer) {
+ RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
+ if (engine_type->update_render_passes) {
+ RenderEngine *engine = RE_engine_create(engine_type);
+ if (engine) {
+ BKE_view_layer_verify_aov(engine, scene, view_layer);
+ }
+ RE_engine_free(engine);
+ engine = NULL;
+ }
+ }
+
rna_Scene_glsl_update(bmain, activescene, ptr);
}
@@ -2397,6 +2424,28 @@ static void rna_ViewLayer_remove(
}
}
+void rna_ViewLayer_active_aov_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&view_layer->aovs) - 1);
+}
+
+int rna_ViewLayer_active_aov_index_get(PointerRNA *ptr)
+{
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ return BLI_findindex(&view_layer->aovs, view_layer->active_aov);
+}
+
+void rna_ViewLayer_active_aov_index_set(PointerRNA *ptr, int value)
+{
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ ViewLayerAOV *aov = BLI_findlink(&view_layer->aovs, value);
+ view_layer->active_aov = aov;
+}
+
/* Fake value, used internally (not saved to DNA). */
# define V3D_ORIENT_DEFAULT -1
@@ -3963,6 +4012,33 @@ static void rna_def_view_layer_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
}
+static void rna_def_view_layer_aov(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+ srna = RNA_def_struct(brna, "AOV", NULL);
+ RNA_def_struct_sdna(srna, "ViewLayerAOV");
+ RNA_def_struct_ui_text(srna, "Shader AOV", "");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "name");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Name", "Name of the AOV");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", AOV_CONFLICT);
+ RNA_def_property_ui_text(prop, "Valid", "Is the name of the AOV conflicting");
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, rna_enum_view_layer_aov_type_items);
+ RNA_def_property_enum_default(prop, AOV_TYPE_COLOR);
+ RNA_def_property_ui_text(prop, "Type", "Data type of the AOV");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
+}
+
void rna_def_view_layer_common(StructRNA *srna, const bool scene)
{
PropertyRNA *prop;
@@ -4013,6 +4089,24 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene)
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "ViewLayerEEVEE");
RNA_def_property_ui_text(prop, "EEVEE Settings", "View layer settings for EEVEE");
+
+ prop = RNA_def_property(srna, "aovs", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "aovs", NULL);
+ RNA_def_property_struct_type(prop, "AOV");
+ RNA_def_property_ui_text(prop, "Shader AOV", "");
+
+ prop = RNA_def_property(srna, "active_aov", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "AOV");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Shader AOV", "Active AOV");
+
+ prop = RNA_def_property(srna, "active_aov_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop,
+ "rna_ViewLayer_active_aov_index_get",
+ "rna_ViewLayer_active_aov_index_set",
+ "rna_ViewLayer_active_aov_index_range");
+ RNA_def_property_ui_text(prop, "Active AOV Index", "Index of active aov");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
/* layer options */
@@ -7848,6 +7942,7 @@ void RNA_def_scene(BlenderRNA *brna)
rna_def_display_safe_areas(brna);
rna_def_scene_display(brna);
rna_def_scene_eevee(brna);
+ rna_def_view_layer_aov(brna);
rna_def_view_layer_eevee(brna);
rna_def_scene_gpencil(brna);
RNA_define_animate_sdna(true);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 8ff4336ba83..eabb71c79d3 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -426,6 +426,9 @@ static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] =
{EEVEE_RENDER_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
{EEVEE_RENDER_PASS_MIST, "MIST", 0, "Mist", ""},
+ {0, "", ICON_NONE, "Shader AOV", ""},
+ {EEVEE_RENDER_PASS_AOV, "AOV", 0, "AOV", ""},
+
{0, NULL, 0, NULL, NULL},
};
@@ -1065,6 +1068,19 @@ static Scene *rna_3DViewShading_scene(PointerRNA *ptr)
}
}
+static ViewLayer *rna_3DViewShading_view_layer(PointerRNA *ptr)
+{
+ /* Get scene, depends if using 3D view or OpenGL render settings. */
+ ID *id = ptr->owner_id;
+ if (GS(id->name) == ID_SCE) {
+ return NULL;
+ }
+ else {
+ bScreen *screen = (bScreen *)ptr->owner_id;
+ return WM_windows_view_layer_get_from_screen(G_MAIN->wm.first, screen);
+ }
+}
+
static int rna_3DViewShading_type_get(PointerRNA *ptr)
{
/* Available shading types depend on render engine. */
@@ -1292,15 +1308,33 @@ static const EnumPropertyItem *rna_3DViewShading_render_pass_itemf(bContext *C,
bool *r_free)
{
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool bloom_enabled = scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED;
+ const bool aov_available = BKE_view_layer_has_valid_aov(view_layer);
int totitem = 0;
EnumPropertyItem *result = NULL;
+ EnumPropertyItem aov_template;
for (int i = 0; rna_enum_view3dshading_render_pass_type_items[i].identifier != NULL; i++) {
const EnumPropertyItem *item = &rna_enum_view3dshading_render_pass_type_items[i];
- if (!((!bloom_enabled &&
- (item->value == EEVEE_RENDER_PASS_BLOOM || STREQ(item->name, "Effects"))))) {
+ if (item->value == EEVEE_RENDER_PASS_AOV) {
+ aov_template.value = item->value;
+ aov_template.icon = 0;
+ aov_template.description = item->description;
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
+ if ((aov->flag & AOV_CONFLICT) != 0) {
+ continue;
+ }
+ aov_template.name = aov->name;
+ aov_template.identifier = aov->name;
+ RNA_enum_item_add(&result, &totitem, &aov_template);
+ aov_template.value++;
+ }
+ }
+ else if (!((!bloom_enabled &&
+ (item->value == EEVEE_RENDER_PASS_BLOOM || STREQ(item->name, "Effects"))) ||
+ (!aov_available && STREQ(item->name, "Shader AOV")))) {
RNA_enum_item_add(&result, &totitem, item);
}
}
@@ -1314,14 +1348,58 @@ static int rna_3DViewShading_render_pass_get(PointerRNA *ptr)
View3DShading *shading = (View3DShading *)ptr->data;
eViewLayerEEVEEPassType result = shading->render_pass;
Scene *scene = rna_3DViewShading_scene(ptr);
+ ViewLayer *view_layer = rna_3DViewShading_view_layer(ptr);
if (result == EEVEE_RENDER_PASS_BLOOM && ((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) {
- result = EEVEE_RENDER_PASS_COMBINED;
+ return EEVEE_RENDER_PASS_COMBINED;
+ }
+ else if (result == EEVEE_RENDER_PASS_AOV) {
+ if (!view_layer) {
+ return EEVEE_RENDER_PASS_COMBINED;
+ }
+ const int aov_index = BLI_findstringindex(
+ &view_layer->aovs, shading->aov_name, offsetof(ViewLayerAOV, name));
+ if (aov_index == -1) {
+ return EEVEE_RENDER_PASS_COMBINED;
+ }
+ return result + aov_index;
}
return result;
}
+static void rna_3DViewShading_render_pass_set(PointerRNA *ptr, int value)
+{
+ View3DShading *shading = (View3DShading *)ptr->data;
+ Scene *scene = rna_3DViewShading_scene(ptr);
+ ViewLayer *view_layer = rna_3DViewShading_view_layer(ptr);
+ shading->aov_name[0] = 0;
+
+ if ((value & EEVEE_RENDER_PASS_AOV) != 0) {
+ if (!view_layer) {
+ shading->render_pass = EEVEE_RENDER_PASS_COMBINED;
+ return;
+ }
+ const int aov_index = value & ~EEVEE_RENDER_PASS_AOV;
+ ViewLayerAOV *aov = BLI_findlink(&view_layer->aovs, aov_index);
+ if (!aov) {
+ /* AOV not found, cannot select AOV. */
+ shading->render_pass = EEVEE_RENDER_PASS_COMBINED;
+ return;
+ }
+
+ shading->render_pass = EEVEE_RENDER_PASS_AOV;
+ BLI_strncpy(shading->aov_name, aov->name, sizeof(aov->name));
+ }
+ else if (value == EEVEE_RENDER_PASS_BLOOM &&
+ ((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) {
+ shading->render_pass = EEVEE_RENDER_PASS_COMBINED;
+ }
+ else {
+ shading->render_pass = value;
+ }
+}
+
static void rna_SpaceView3D_use_local_collections_update(bContext *C, PointerRNA *ptr)
{
Main *bmain = CTX_data_main(C);
@@ -3488,9 +3566,17 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "render_pass");
RNA_def_property_enum_items(prop, rna_enum_view3dshading_render_pass_type_items);
RNA_def_property_ui_text(prop, "Render Pass", "Render Pass to show in the viewport");
- RNA_def_property_enum_funcs(
- prop, "rna_3DViewShading_render_pass_get", NULL, "rna_3DViewShading_render_pass_itemf");
+ RNA_def_property_enum_funcs(prop,
+ "rna_3DViewShading_render_pass_get",
+ "rna_3DViewShading_render_pass_set",
+ "rna_3DViewShading_render_pass_itemf");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "aov_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "aov_name");
+ RNA_def_property_ui_text(prop, "Shader AOV Name", "Name of the active Shader AOV");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
static void rna_def_space_view3d_overlay(BlenderRNA *brna)
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index efd0e48f41a..a385cb7039f 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -903,6 +903,16 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
/* Duplicate bump height branches for manual derivatives.
*/
nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree, 0);
+ LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
+ if (node->type == SH_NODE_OUTPUT_AOV) {
+ nodeChainIterBackwards(localtree, node, ntree_shader_bump_branches, localtree, 0);
+ nTreeTags tags = {
+ .ssr_id = 1.0,
+ .sss_id = 1.0,
+ };
+ ntree_shader_tag_nodes(localtree, node, &tags);
+ }
+ }
/* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
nTreeTags tags = {
@@ -913,6 +923,11 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
exec = ntreeShaderBeginExecTree(localtree);
ntreeExecGPUNodes(exec, mat, output);
+ LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
+ if (node->type == SH_NODE_OUTPUT_AOV) {
+ ntreeExecGPUNodes(exec, mat, node);
+ }
+ }
ntreeShaderEndExecTree(exec);
/* EEVEE: Find which material domain was used (volume, surface ...). */
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.c
index 8e73a547bf7..403b3e6d9d6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_aov.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.c
@@ -19,6 +19,8 @@
#include "../node_shader_util.h"
+#include "BLI_hash.h"
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_output_aov_in[] = {
@@ -33,6 +35,22 @@ static void node_shader_init_output_aov(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = aov;
}
+static int node_shader_gpu_output_aov(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ GPUNodeLink *outlink;
+ NodeShaderOutputAOV *aov = (NodeShaderOutputAOV *)node->storage;
+ /* Keep in sync with `renderpass_lib.glsl#render_pass_aov_hash`. */
+ unsigned int hash = BLI_hash_string(aov->name) & ~1;
+ GPU_stack_link(mat, node, "node_output_aov", in, out, &outlink);
+ GPU_material_add_output_link_aov(mat, outlink, hash);
+
+ return true;
+}
+
/* node type definition */
void register_node_type_sh_output_aov(void)
{
@@ -43,6 +61,7 @@ void register_node_type_sh_output_aov(void)
node_type_init(&ntype, node_shader_init_output_aov);
node_type_storage(
&ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, node_shader_gpu_output_aov);
/* Do not allow muting output node. */
node_type_internal_links(&ntype, NULL);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 47c5487a458..430130d4727 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -130,6 +130,9 @@ void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATT
struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm,
const struct bScreen *screen)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+struct ViewLayer *WM_windows_view_layer_get_from_screen(const struct wmWindowManager *wm,
+ const struct bScreen *screen)
+ ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
struct WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm,
const struct bScreen *screen)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 926e61f4a0e..74f352c0b62 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -656,6 +656,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
* pieces of Blender using sound may exit cleanly, see also T50676. */
BKE_sound_exit();
+ BKE_appdir_exit();
CLG_exit();
BKE_blender_atexit();
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 589b8e2f156..14798653a31 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -2261,6 +2261,17 @@ Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen
return NULL;
}
+ViewLayer *WM_windows_view_layer_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
+{
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ if (WM_window_get_active_screen(win) == screen) {
+ return WM_window_get_active_view_layer(win);
+ }
+ }
+
+ return NULL;
+}
+
WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {