From a0915217ff74256ffc4797e77d7a869501c4deb2 Mon Sep 17 00:00:00 2001
From: Jens Koenen <koenen@vr.rwth-aachen.de>
Date: Thu, 1 Dec 2022 13:51:37 +0100
Subject: [PATCH] Indirect lighting can now be disabled using
 --disable-indirect-lighting and shadows can be disabled using
 --disable-shadows

---
 CMakeLists.txt                                |  6 ++
 .../multi_view/multi_view_stereo.frag         | 52 +--------------
 .../multi_view/multi_view_stereo_base.glsl    | 49 ++++++++++++++
 .../multi_view_stereo_indirect.frag           |  9 +++
 .../multi_view_stereo_indirect_shadow.frag    | 10 +++
 .../multi_view/multi_view_stereo_shadow.frag  |  9 +++
 .../native_forward/native_stereo_forward.frag | 35 +---------
 .../native_stereo_forward_base.glsl           | 32 +++++++++
 .../native_stereo_forward_indirect.frag       |  8 +++
 ...native_stereo_forward_indirect_shadow.frag |  9 +++
 .../native_stereo_forward_shadow.frag         |  8 +++
 src/strategy/multi_view_stereo.cpp            | 65 ++++++++++++++++---
 src/strategy/native_stereo_deferred.cpp       | 11 +++-
 src/strategy/native_stereo_forward.cpp        | 65 ++++++++++++++++---
 src/utility/command_parser.cpp                | 22 +++++++
 src/utility/command_parser.hpp                |  4 ++
 src/utility/geometry_buffer.cpp               |  2 +-
 src/vr_application.cpp                        | 37 +++++++----
 src/vr_application.hpp                        |  4 +-
 19 files changed, 318 insertions(+), 119 deletions(-)
 create mode 100644 res/dpr/strategy/multi_view/multi_view_stereo_base.glsl
 create mode 100644 res/dpr/strategy/multi_view/multi_view_stereo_indirect.frag
 create mode 100644 res/dpr/strategy/multi_view/multi_view_stereo_indirect_shadow.frag
 create mode 100644 res/dpr/strategy/multi_view/multi_view_stereo_shadow.frag
 create mode 100644 res/dpr/strategy/native_forward/native_stereo_forward_base.glsl
 create mode 100644 res/dpr/strategy/native_forward/native_stereo_forward_indirect.frag
 create mode 100644 res/dpr/strategy/native_forward/native_stereo_forward_indirect_shadow.frag
 create mode 100644 res/dpr/strategy/native_forward/native_stereo_forward_shadow.frag

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d50d7b89..89e362ad 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -742,12 +742,18 @@ message("=======================================================================
             SOURCE_FILES
                 strategy/native_forward/native_stereo_forward.vert
                 strategy/native_forward/native_stereo_forward.frag
+                strategy/native_forward/native_stereo_forward_shadow.frag
+                strategy/native_forward/native_stereo_forward_indirect.frag
+                strategy/native_forward/native_stereo_forward_indirect_shadow.frag
 
                 strategy/native_deferred/native_stereo_deferred.vert
                 strategy/native_deferred/native_stereo_deferred.frag
 
                 strategy/multi_view/multi_view_stereo.vert
                 strategy/multi_view/multi_view_stereo.frag
+                strategy/multi_view/multi_view_stereo_shadow.frag
+                strategy/multi_view/multi_view_stereo_indirect.frag
+                strategy/multi_view/multi_view_stereo_indirect_shadow.frag
 
                 strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.vert
                 strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.geom
diff --git a/res/dpr/strategy/multi_view/multi_view_stereo.frag b/res/dpr/strategy/multi_view/multi_view_stereo.frag
index 9dd9da3b..086b6ff2 100644
--- a/res/dpr/strategy/multi_view/multi_view_stereo.frag
+++ b/res/dpr/strategy/multi_view/multi_view_stereo.frag
@@ -4,55 +4,5 @@
 
 #define MATERIAL_DESCRIPTOR_SET 3
 #define LIGHT_DESCRIPTOR_SET 4
-#define SHADOW_DESCRIPTOR_SET 5
-#define INDIRECT_DESCRIPTOR_SET 6
 
-#include "math_library.glsl"
-#include "material_library.glsl"
-#include "light_library.glsl"
-
-#include "per_frame.inc"
-
-layout(location = 0) out vec4 outFragColor;
-
-layout(location = 0) in vec3 inPos;
-layout(location = 1) in vec3 inNormal;
-layout(location = 2) in vec3 inTangent;
-layout(location = 3) in vec2 inUV;
-
-layout(set = 0, binding = 0) uniform LeftFrame 
-{
-    PerFrameData left_frame;
-};
-
-layout(set = 1, binding = 0) uniform RightFrame
-{
-    PerFrameData right_frame;
-};
-
-void main()
-{
-    Material material = lookup_material(inUV);
-    
-    if (material.opacity < EPSILON)
-    {
-        discard;
-    }
-
-    vec3 eye_position = vec3(0.0);
-
-    if (gl_ViewIndex == 0) //Left Eye
-    {
-        eye_position = left_frame.eyePosition;
-    }
-
-    else if (gl_ViewIndex == 1) //Right Eye
-    {
-        eye_position = right_frame.eyePosition;
-    }
-    
-    vec3 normal = lookup_normal(inUV, inNormal, inTangent);
-    vec3 lighting = apply_lighting(eye_position, inPos, normal, material);
-
-    outFragColor = vec4(lighting, 1.0);
-}
+#include "multi_view_stereo_base.glsl"
\ No newline at end of file
diff --git a/res/dpr/strategy/multi_view/multi_view_stereo_base.glsl b/res/dpr/strategy/multi_view/multi_view_stereo_base.glsl
new file mode 100644
index 00000000..01cff121
--- /dev/null
+++ b/res/dpr/strategy/multi_view/multi_view_stereo_base.glsl
@@ -0,0 +1,49 @@
+#include "math_library.glsl"
+#include "material_library.glsl"
+#include "light_library.glsl"
+
+#include "per_frame.inc"
+
+layout(location = 0) out vec4 outFragColor;
+
+layout(location = 0) in vec3 inPos;
+layout(location = 1) in vec3 inNormal;
+layout(location = 2) in vec3 inTangent;
+layout(location = 3) in vec2 inUV;
+
+layout(set = 0, binding = 0) uniform LeftFrame 
+{
+    PerFrameData left_frame;
+};
+
+layout(set = 1, binding = 0) uniform RightFrame
+{
+    PerFrameData right_frame;
+};
+
+void main()
+{
+    Material material = lookup_material(inUV);
+    
+    if (material.opacity < EPSILON)
+    {
+        discard;
+    }
+
+    vec3 eye_position = vec3(0.0);
+
+    if (gl_ViewIndex == 0) //Left Eye
+    {
+        eye_position = left_frame.eyePosition;
+    }
+
+    else if (gl_ViewIndex == 1) //Right Eye
+    {
+        eye_position = right_frame.eyePosition;
+    }
+    
+    vec3 normal = lookup_normal(inUV, inNormal, inTangent);
+    vec3 lighting = apply_lighting(eye_position, inPos, normal, material);
+
+    outFragColor = vec4(lighting, 1.0);
+}
diff --git a/res/dpr/strategy/multi_view/multi_view_stereo_indirect.frag b/res/dpr/strategy/multi_view/multi_view_stereo_indirect.frag
new file mode 100644
index 00000000..7a4d1a83
--- /dev/null
+++ b/res/dpr/strategy/multi_view/multi_view_stereo_indirect.frag
@@ -0,0 +1,9 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+#extension GL_EXT_multiview : require
+
+#define MATERIAL_DESCRIPTOR_SET 3
+#define LIGHT_DESCRIPTOR_SET 4
+#define INDIRECT_DESCRIPTOR_SET 5
+
+#include "multi_view_stereo_base.glsl"
\ No newline at end of file
diff --git a/res/dpr/strategy/multi_view/multi_view_stereo_indirect_shadow.frag b/res/dpr/strategy/multi_view/multi_view_stereo_indirect_shadow.frag
new file mode 100644
index 00000000..5c938628
--- /dev/null
+++ b/res/dpr/strategy/multi_view/multi_view_stereo_indirect_shadow.frag
@@ -0,0 +1,10 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+#extension GL_EXT_multiview : require
+
+#define MATERIAL_DESCRIPTOR_SET 3
+#define LIGHT_DESCRIPTOR_SET 4
+#define SHADOW_DESCRIPTOR_SET 5
+#define INDIRECT_DESCRIPTOR_SET 6
+
+#include "multi_view_stereo_base.glsl"
\ No newline at end of file
diff --git a/res/dpr/strategy/multi_view/multi_view_stereo_shadow.frag b/res/dpr/strategy/multi_view/multi_view_stereo_shadow.frag
new file mode 100644
index 00000000..5cec8046
--- /dev/null
+++ b/res/dpr/strategy/multi_view/multi_view_stereo_shadow.frag
@@ -0,0 +1,9 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+#extension GL_EXT_multiview : require
+
+#define MATERIAL_DESCRIPTOR_SET 3
+#define LIGHT_DESCRIPTOR_SET 4
+#define SHADOW_DESCRIPTOR_SET 5
+
+#include "multi_view_stereo_base.glsl"
\ No newline at end of file
diff --git a/res/dpr/strategy/native_forward/native_stereo_forward.frag b/res/dpr/strategy/native_forward/native_stereo_forward.frag
index 1245f0d2..2958a87d 100644
--- a/res/dpr/strategy/native_forward/native_stereo_forward.frag
+++ b/res/dpr/strategy/native_forward/native_stereo_forward.frag
@@ -3,38 +3,5 @@
 
 #define MATERIAL_DESCRIPTOR_SET 1
 #define LIGHT_DESCRIPTOR_SET 3
-#define SHADOW_DESCRIPTOR_SET 4
-#define INDIRECT_DESCRIPTOR_SET 5
 
-#include "math_library.glsl"
-#include "material_library.glsl"
-#include "light_library.glsl"
-
-#include "per_frame.inc"
-
-layout(location = 0) out vec4 outFragColor;
-
-layout(location = 0) in vec3 inPos;
-layout(location = 1) in vec3 inNormal;
-layout(location = 2) in vec3 inTangent;
-layout(location = 3) in vec2 inUV;
-
-layout(set = 0, binding = 0) uniform Frame
-{
-    PerFrameData frame;
-};
-
-void main()
-{
-    Material material = lookup_material(inUV);
-    
-    if (material.opacity < EPSILON)
-    {
-        discard;
-    }
-    
-    vec3 normal = lookup_normal(inUV, inNormal, inTangent);
-    vec3 lighting = apply_lighting(frame.eyePosition, inPos, normal, material);
-
-    outFragColor = vec4(lighting, 1.0);
-}
+#include "native_stereo_forward_base.glsl"
\ No newline at end of file
diff --git a/res/dpr/strategy/native_forward/native_stereo_forward_base.glsl b/res/dpr/strategy/native_forward/native_stereo_forward_base.glsl
new file mode 100644
index 00000000..703e6082
--- /dev/null
+++ b/res/dpr/strategy/native_forward/native_stereo_forward_base.glsl
@@ -0,0 +1,32 @@
+#include "math_library.glsl"
+#include "material_library.glsl"
+#include "light_library.glsl"
+
+#include "per_frame.inc"
+
+layout(location = 0) out vec4 outFragColor;
+
+layout(location = 0) in vec3 inPos;
+layout(location = 1) in vec3 inNormal;
+layout(location = 2) in vec3 inTangent;
+layout(location = 3) in vec2 inUV;
+
+layout(set = 0, binding = 0) uniform Frame
+{
+    PerFrameData frame;
+};
+
+void main()
+{
+    Material material = lookup_material(inUV);
+    
+    if (material.opacity < EPSILON)
+    {
+        discard;
+    }
+    
+    vec3 normal = lookup_normal(inUV, inNormal, inTangent);
+    vec3 lighting = apply_lighting(frame.eyePosition, inPos, normal, material);
+
+    outFragColor = vec4(lighting, 1.0);
+}
diff --git a/res/dpr/strategy/native_forward/native_stereo_forward_indirect.frag b/res/dpr/strategy/native_forward/native_stereo_forward_indirect.frag
new file mode 100644
index 00000000..adf9e9b6
--- /dev/null
+++ b/res/dpr/strategy/native_forward/native_stereo_forward_indirect.frag
@@ -0,0 +1,8 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+
+#define MATERIAL_DESCRIPTOR_SET 1
+#define LIGHT_DESCRIPTOR_SET 3
+#define INDIRECT_DESCRIPTOR_SET 4
+
+#include "native_stereo_forward_base.glsl"
\ No newline at end of file
diff --git a/res/dpr/strategy/native_forward/native_stereo_forward_indirect_shadow.frag b/res/dpr/strategy/native_forward/native_stereo_forward_indirect_shadow.frag
new file mode 100644
index 00000000..52d863f3
--- /dev/null
+++ b/res/dpr/strategy/native_forward/native_stereo_forward_indirect_shadow.frag
@@ -0,0 +1,9 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+
+#define MATERIAL_DESCRIPTOR_SET 1
+#define LIGHT_DESCRIPTOR_SET 3
+#define SHADOW_DESCRIPTOR_SET 4
+#define INDIRECT_DESCRIPTOR_SET 5
+
+#include "native_stereo_forward_base.glsl"
\ No newline at end of file
diff --git a/res/dpr/strategy/native_forward/native_stereo_forward_shadow.frag b/res/dpr/strategy/native_forward/native_stereo_forward_shadow.frag
new file mode 100644
index 00000000..c57004b0
--- /dev/null
+++ b/res/dpr/strategy/native_forward/native_stereo_forward_shadow.frag
@@ -0,0 +1,8 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+
+#define MATERIAL_DESCRIPTOR_SET 1
+#define LIGHT_DESCRIPTOR_SET 3
+#define SHADOW_DESCRIPTOR_SET 4
+
+#include "native_stereo_forward_base.glsl"
\ No newline at end of file
diff --git a/src/strategy/multi_view_stereo.cpp b/src/strategy/multi_view_stereo.cpp
index b76e3cac..ba8d0073 100644
--- a/src/strategy/multi_view_stereo.cpp
+++ b/src/strategy/multi_view_stereo.cpp
@@ -78,9 +78,14 @@ bool MultiViewStereo::on_render(VkCommandBuffer command_buffer, lava::index fram
     std::array<uint8_t, 1> metadata = { 0x00 };
     this->get_headset()->submit_metadata(metadata);
 
-    this->get_pass_timer()->begin_pass(command_buffer, "shadow");
-    this->get_application()->get_shadow_cache()->compute_shadow(command_buffer, frame);
-    this->get_pass_timer()->end_pass(command_buffer);
+    ShadowCache::Ptr shadow_cache = this->get_application()->get_shadow_cache();
+
+    if (shadow_cache != nullptr)
+    {
+        this->get_pass_timer()->begin_pass(command_buffer, "shadow");
+        shadow_cache->compute_shadow(command_buffer, frame);
+        this->get_pass_timer()->end_pass(command_buffer);
+    }
 
     this->get_pass_timer()->begin_pass(command_buffer, "multi_eye");
     this->render_pass->process(command_buffer, 0);
@@ -109,15 +114,26 @@ const char* MultiViewStereo::get_name() const
 
 bool MultiViewStereo::create_pipeline_layout()
 {
+    ShadowCache::Ptr shadow_cache = this->get_application()->get_shadow_cache();
+    IndirectCache::Ptr indirect_cache = this->get_application()->get_indirect_cache();
+
     this->pipeline_layout = lava::make_pipeline_layout();
     this->pipeline_layout->add(this->get_stereo_transform()->get_descriptor());
     this->pipeline_layout->add(this->get_stereo_transform()->get_descriptor());
     this->pipeline_layout->add(this->get_scene()->get_mesh_descriptor());
     this->pipeline_layout->add(this->get_scene()->get_material_descriptor());
     this->pipeline_layout->add(this->get_scene()->get_light_descriptor());
-    this->pipeline_layout->add(this->get_application()->get_shadow_cache()->get_descriptor());
-    this->pipeline_layout->add(this->get_application()->get_indirect_cache()->get_descriptor());
     
+    if (shadow_cache != nullptr)
+    {
+        this->pipeline_layout->add(shadow_cache->get_descriptor());    
+    }
+    
+    if (indirect_cache != nullptr)
+    {
+        this->pipeline_layout->add(indirect_cache->get_descriptor());
+    }
+
     if (!this->pipeline_layout->create(this->get_device()))
     {
         lava::log()->error("Can't create pipeline layout for multi-view stereo!");
@@ -229,6 +245,9 @@ bool MultiViewStereo::create_render_pass()
 
 bool MultiViewStereo::create_pipeline()
 {
+    ShadowCache::Ptr shadow_cache = this->get_application()->get_shadow_cache();
+    IndirectCache::Ptr indirect_cache = this->get_application()->get_indirect_cache();
+
     VkPipelineColorBlendAttachmentState blend_state;
     blend_state.blendEnable = VK_FALSE;
     blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO;
@@ -255,7 +274,21 @@ bool MultiViewStereo::create_pipeline()
         return false;
     }
 
-    if (!this->pipeline->add_shader(lava::file_data("dpr/binary/multi_view_stereo_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    std::string shader_name = "dpr/binary/multi_view_stereo";
+
+    if (indirect_cache != nullptr)
+    {
+        shader_name += "_indirect";
+    }
+
+    if (shadow_cache != nullptr)
+    {
+        shader_name += "_shadow";
+    }
+
+    shader_name += "_fragment.spirv";
+
+    if (!this->pipeline->add_shader(lava::file_data(shader_name), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         lava::log()->error("Can't load fragment shader for multi-view stereo!");
 
@@ -281,13 +314,29 @@ bool MultiViewStereo::create_pipeline()
 
 void MultiViewStereo::pipeline_function(VkCommandBuffer command_buffer)
 {
+    ShadowCache::Ptr shadow_cache = this->get_application()->get_shadow_cache();
+    IndirectCache::Ptr indirect_cache = this->get_application()->get_indirect_cache();
     uint32_t frame_index = this->get_application()->get_frame_index();
 
     this->pipeline_layout->bind(command_buffer, this->get_stereo_transform()->get_descriptor_set(EYE_LEFT, frame_index), 0);
     this->pipeline_layout->bind(command_buffer, this->get_stereo_transform()->get_descriptor_set(EYE_RIGHT, frame_index), 1);
     this->pipeline_layout->bind(command_buffer, this->get_scene()->get_light_descriptor_set(frame_index), 4);
-    this->pipeline_layout->bind(command_buffer, this->get_application()->get_shadow_cache()->get_descriptor_set(), 5);
-    this->pipeline_layout->bind(command_buffer, this->get_application()->get_indirect_cache()->get_descriptor_set(), 6);
+    
+    if (shadow_cache != nullptr && indirect_cache != nullptr)
+    {
+        this->pipeline_layout->bind(command_buffer, shadow_cache->get_descriptor_set(), 5);
+        this->pipeline_layout->bind(command_buffer, indirect_cache->get_descriptor_set(), 6);
+    }
+
+    else if (shadow_cache != nullptr)
+    {
+        this->pipeline_layout->bind(command_buffer, shadow_cache->get_descriptor_set(), 5);
+    }
+
+    else if (indirect_cache != nullptr)
+    {
+        this->pipeline_layout->bind(command_buffer, indirect_cache->get_descriptor_set(), 5);
+    }
 
     const std::vector<SceneMaterial>& materials = this->get_scene()->get_materials();
 
diff --git a/src/strategy/native_stereo_deferred.cpp b/src/strategy/native_stereo_deferred.cpp
index 37be5aa6..179a7fbb 100644
--- a/src/strategy/native_stereo_deferred.cpp
+++ b/src/strategy/native_stereo_deferred.cpp
@@ -72,9 +72,14 @@ bool NativeStereoDeferred::on_render(VkCommandBuffer command_buffer, lava::index
     std::array<uint8_t, 1> metadata = { 0x00 };
     this->get_headset()->submit_metadata(metadata);
 
-    this->get_pass_timer()->begin_pass(command_buffer, "shadow");
-    this->get_application()->get_shadow_cache()->compute_shadow(command_buffer, frame);
-    this->get_pass_timer()->end_pass(command_buffer);
+    ShadowCache::Ptr shadow_cache = this->get_application()->get_shadow_cache();
+
+    if (shadow_cache != nullptr)
+    {
+        this->get_pass_timer()->begin_pass(command_buffer, "shadow");
+        shadow_cache->compute_shadow(command_buffer, frame);
+        this->get_pass_timer()->end_pass(command_buffer);
+    }
 
     this->get_pass_timer()->begin_pass(command_buffer, "left_eye");
     this->eye_passes[0].render_pass->process(command_buffer, 0);
diff --git a/src/strategy/native_stereo_forward.cpp b/src/strategy/native_stereo_forward.cpp
index bbe14e4e..df6cfad1 100644
--- a/src/strategy/native_stereo_forward.cpp
+++ b/src/strategy/native_stereo_forward.cpp
@@ -72,9 +72,14 @@ bool NativeStereoForward::on_render(VkCommandBuffer command_buffer, lava::index
     std::array<uint8_t, 1> metadata = { 0x00 };
     this->get_headset()->submit_metadata(metadata);
 
-    this->get_pass_timer()->begin_pass(command_buffer, "shadow");
-    this->get_application()->get_shadow_cache()->compute_shadow(command_buffer, frame);
-    this->get_pass_timer()->end_pass(command_buffer);
+    ShadowCache::Ptr shadow_cache = this->get_application()->get_shadow_cache();
+
+    if (shadow_cache != nullptr)
+    {
+        this->get_pass_timer()->begin_pass(command_buffer, "shadow");
+        shadow_cache->compute_shadow(command_buffer, frame);
+        this->get_pass_timer()->end_pass(command_buffer);
+    }
 
     this->get_pass_timer()->begin_pass(command_buffer, "left_eye");
     this->eye_passes[0].render_pass->process(command_buffer, 0);
@@ -107,13 +112,24 @@ const char* NativeStereoForward::get_name() const
 
 bool NativeStereoForward::create_pipeline_layout()
 {
+    ShadowCache::Ptr shadow_cache = this->get_application()->get_shadow_cache();
+    IndirectCache::Ptr indirect_cache = this->get_application()->get_indirect_cache();
+
     this->pipeline_layout = lava::make_pipeline_layout();
     this->pipeline_layout->add(this->get_stereo_transform()->get_descriptor());
     this->pipeline_layout->add(this->get_scene()->get_material_descriptor());
     this->pipeline_layout->add(this->get_scene()->get_mesh_descriptor());
     this->pipeline_layout->add(this->get_scene()->get_light_descriptor());
-    this->pipeline_layout->add(this->get_application()->get_shadow_cache()->get_descriptor());
-    this->pipeline_layout->add(this->get_application()->get_indirect_cache()->get_descriptor());
+
+    if (shadow_cache != nullptr)
+    {
+        this->pipeline_layout->add(shadow_cache->get_descriptor());    
+    }
+    
+    if (indirect_cache != nullptr)
+    {
+        this->pipeline_layout->add(indirect_cache->get_descriptor());
+    }
     
     if (!this->pipeline_layout->create(this->get_device()))
     {
@@ -215,6 +231,9 @@ bool NativeStereoForward::create_render_pass(Eye eye)
 
 bool NativeStereoForward::create_pipeline(Eye eye)
 {
+    ShadowCache::Ptr shadow_cache = this->get_application()->get_shadow_cache();
+    IndirectCache::Ptr indirect_cache = this->get_application()->get_indirect_cache();
+
     VkPipelineColorBlendAttachmentState blend_state;
     blend_state.blendEnable = VK_FALSE;
     blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO;
@@ -241,7 +260,21 @@ bool NativeStereoForward::create_pipeline(Eye eye)
         return false;
     }
 
-    if (!pipeline->add_shader(lava::file_data("dpr/binary/native_stereo_forward_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    std::string shader_name = "dpr/binary/native_stereo_forward";
+
+    if (indirect_cache != nullptr)
+    {
+        shader_name += "_indirect";
+    }
+
+    if (shadow_cache != nullptr)
+    {
+        shader_name += "_shadow";
+    }
+
+    shader_name += "_fragment.spirv";
+
+    if (!pipeline->add_shader(lava::file_data(shader_name), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         lava::log()->error("Can't load fragment shader for native stereo forward!");
 
@@ -270,12 +303,28 @@ bool NativeStereoForward::create_pipeline(Eye eye)
 
 void NativeStereoForward::pipeline_function(VkCommandBuffer command_buffer, Eye eye)
 {
+    ShadowCache::Ptr shadow_cache = this->get_application()->get_shadow_cache();
+    IndirectCache::Ptr indirect_cache = this->get_application()->get_indirect_cache();
     uint32_t frame_index = this->get_application()->get_frame_index();
 
     this->pipeline_layout->bind(command_buffer, this->get_stereo_transform()->get_descriptor_set(eye, frame_index), 0);
     this->pipeline_layout->bind(command_buffer, this->get_scene()->get_light_descriptor_set(frame_index), 3);
-    this->pipeline_layout->bind(command_buffer, this->get_application()->get_shadow_cache()->get_descriptor_set(), 4);
-    this->pipeline_layout->bind(command_buffer, this->get_application()->get_indirect_cache()->get_descriptor_set(), 5);
+
+    if (shadow_cache != nullptr && indirect_cache != nullptr)
+    {
+        this->pipeline_layout->bind(command_buffer, shadow_cache->get_descriptor_set(), 4);
+        this->pipeline_layout->bind(command_buffer, indirect_cache->get_descriptor_set(), 5);
+    }
+
+    else if (shadow_cache != nullptr)
+    {
+        this->pipeline_layout->bind(command_buffer, shadow_cache->get_descriptor_set(), 4);
+    }
+
+    else if (indirect_cache != nullptr)
+    {
+        this->pipeline_layout->bind(command_buffer, indirect_cache->get_descriptor_set(), 4);
+    }
 
     const std::vector<SceneMaterial>& materials = this->get_scene()->get_materials();
 
diff --git a/src/utility/command_parser.cpp b/src/utility/command_parser.cpp
index 7face99e..a46039b5 100644
--- a/src/utility/command_parser.cpp
+++ b/src/utility/command_parser.cpp
@@ -20,6 +20,16 @@ bool CommandParser::parse_command(const argh::parser& cmd_line)
             this->write_frames = true;
         }
 
+        else if (flag == "disable-indirect-lighting")
+        {
+            this->disable_indirect_lighting = true;
+        }
+
+        else if (flag == "disable-shadows")
+        {
+            this->disable_shadows = true;
+        }
+
         else if (flag == "help")
         {
             this->show_help();
@@ -294,6 +304,16 @@ bool CommandParser::should_write_frames() const
     return this->write_frames;
 }
 
+bool CommandParser::should_disable_indirect_lighting() const
+{
+    return this->disable_indirect_lighting;
+}
+
+bool CommandParser::should_disbale_shadows() const
+{
+    return this->disable_shadows;
+}
+
 void CommandParser::show_help()
 {
     std::cout << "Usage:" << std::endl;
@@ -328,6 +348,8 @@ void CommandParser::show_help()
     std::cout << "   --show-companion-window              Show companion window. If not set, writes to the companion window are ignored." << std::endl;
     std::cout << "   --write-frames                       Write frames to files. If not set, frames will not be written to files." << std::endl;
     std::cout << "                                        This parameter is only allowed during a benchmark." << std::endl;
+    std::cout << "   --disable-indirect-lighting          Disable indirect lighting and the allocation and computation of an indirect light cache." << std::endl;
+    std::cout << "   --disable-shadows                    Disable shadows and the allocation and computation of shadow maps." << std::endl;
     std::cout << "   --help                               Show help information." << std::endl;
 }
 
diff --git a/src/utility/command_parser.hpp b/src/utility/command_parser.hpp
index 9d8759d8..77454760 100644
--- a/src/utility/command_parser.hpp
+++ b/src/utility/command_parser.hpp
@@ -41,6 +41,8 @@ public:
     bool should_benchmark() const;
     bool should_show_companion_window() const;
     bool should_write_frames() const;
+    bool should_disable_indirect_lighting() const;
+    bool should_disbale_shadows() const;
 
 private:
     void show_help();
@@ -72,4 +74,6 @@ private:
     bool benchmark = false;
     bool show_companion_window = false;
     bool write_frames = false;
+    bool disable_indirect_lighting = false;
+    bool disable_shadows = false;
 };
\ No newline at end of file
diff --git a/src/utility/geometry_buffer.cpp b/src/utility/geometry_buffer.cpp
index 27ff6920..313446d3 100644
--- a/src/utility/geometry_buffer.cpp
+++ b/src/utility/geometry_buffer.cpp
@@ -573,7 +573,7 @@ void GeometryBuffer::pipline_function(VkCommandBuffer command_buffer)
 
     else if (this->indirect_cache != nullptr)
     {
-        this->pipeline_layout->bind(command_buffer, this->indirect_cache->get_descriptor_set(), 4);
+        this->pipeline_layout->bind(command_buffer, this->indirect_cache->get_descriptor_set(), 3);
     }
 
     vkCmdDraw(command_buffer, 4, 1, 0, 0); //draw fullscreen quad
diff --git a/src/vr_application.cpp b/src/vr_application.cpp
index 9168aac7..ffb8fa3e 100644
--- a/src/vr_application.cpp
+++ b/src/vr_application.cpp
@@ -444,22 +444,28 @@ bool VRApplication::on_create()
         return false;
     }
 
-    this->shadow_cache = make_shadow_cache();
-
-    if (!this->shadow_cache->create(this->scene, ShadowCacheSettings()))
+    if (!this->command_parser.should_disbale_shadows())
     {
-        lava::log()->error("Can't create shadow cache!");
+        this->shadow_cache = make_shadow_cache();
 
-        return false;
-    }
+        if (!this->shadow_cache->create(this->scene, ShadowCacheSettings()))
+        {
+            lava::log()->error("Can't create shadow cache!");
 
-    this->indirect_cache = make_indirect_cache();
+            return false;
+        }
+    }
 
-    if (!this->indirect_cache->create(this->scene, IndirectCacheSettings()))
+    if (!this->command_parser.should_disable_indirect_lighting())
     {
-        lava::log()->error("Can't create indirect cache!");
+        this->indirect_cache = make_indirect_cache();
 
-        return false;
+        if (!this->indirect_cache->create(this->scene, IndirectCacheSettings()))
+        {
+            lava::log()->error("Can't create indirect cache!");
+
+            return false;
+        }
     }
 
     return this->create_config();
@@ -704,9 +710,16 @@ bool VRApplication::on_render(VkCommandBuffer command_buffer, lava::index frame)
 
     if (!this->cache_filled)
     {
-        this->shadow_cache->compute_shadow(command_buffer, frame);
-        this->indirect_cache->compute_indirect(command_buffer, frame);
+        if (this->shadow_cache != nullptr)
+        {
+            this->shadow_cache->compute_shadow(command_buffer, frame);
+        }
 
+        if (this->indirect_cache != nullptr)
+        {
+            this->indirect_cache->compute_indirect(command_buffer, frame);
+        }
+        
         this->cache_filled = true;
     }
 
diff --git a/src/vr_application.hpp b/src/vr_application.hpp
index 63cccf91..5735831a 100644
--- a/src/vr_application.hpp
+++ b/src/vr_application.hpp
@@ -43,8 +43,8 @@ public:
     FrameCapture::Ptr get_frame_capture() const;
     StereoTransform::Ptr get_stereo_transform() const;
 
-    ShadowCache::Ptr get_shadow_cache() const;
-    IndirectCache::Ptr get_indirect_cache() const;
+    ShadowCache::Ptr get_shadow_cache() const;          //NOTE: If shadow is disabled, nullptr is returned
+    IndirectCache::Ptr get_indirect_cache() const;      //NOTE: If indirect lighting is disabled, nullptr is returned
 
     StatisticLog::Ptr get_statistic_log() const;
 
-- 
GitLab