diff --git a/CMakeLists.txt b/CMakeLists.txt
index faf790091cd9361aebe654c38c37ce9a807e9e6d..b8de6521e209f00a7d6272a6f6d9b20f618d066e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -678,7 +678,7 @@ message("=======================================================================
 
         include(cmake/Shaders.cmake)
 
-        set(NAME multi-layer-reprojection)
+        set(NAME depth-peeling-reprojection)
 
         message("> ${NAME}")
 
@@ -711,6 +711,7 @@ message("=======================================================================
             ${SRC_DIR}/strategy/native_stereo_forward.hpp ${SRC_DIR}/strategy/native_stereo_forward.cpp
             ${SRC_DIR}/strategy/native_stereo_deferred.hpp ${SRC_DIR}/strategy/native_stereo_deferred.cpp
             ${SRC_DIR}/strategy/multi_view_stereo.hpp ${SRC_DIR}/strategy/multi_view_stereo.cpp
+            ${SRC_DIR}/strategy/depth_peeling_reprojection_stereo.hpp ${SRC_DIR}/strategy/depth_peeling_reprojection_stereo.cpp
             
             #Transport
             ${SRC_DIR}/transport/transport.hpp ${SRC_DIR}/transport/transport.cpp
@@ -735,7 +736,7 @@ message("=======================================================================
 
         add_shaders(
             TARGET ${NAME}
-            DIRECTORY ${RES_DIR}/shaders
+            DIRECTORY ${RES_DIR}/dpr
             INCLUDE_DIRECTORIES
               utility
               data
@@ -749,6 +750,18 @@ message("=======================================================================
                 strategy/multi_view/multi_view_stereo.vert
                 strategy/multi_view/multi_view_stereo.frag
 
+                strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.vert
+                strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.geom
+                strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.frag
+
+                strategy/depth_peeling_reprojection/dpr_companion.vert
+                strategy/depth_peeling_reprojection/dpr_companion.frag
+
+                strategy/depth_peeling_reprojection/dpr_reproject.vert
+                strategy/depth_peeling_reprojection/dpr_reproject.tesc
+                strategy/depth_peeling_reprojection/dpr_reproject.tese
+                strategy/depth_peeling_reprojection/dpr_reproject.frag
+
                 utility/deferred_lighting.vert
                 utility/deferred_lighting.frag
                 utility/deferred_lighting_shadow.frag
diff --git a/res/controllers/Actions.json b/res/dpr-controller/Actions.json
similarity index 100%
rename from res/controllers/Actions.json
rename to res/dpr-controller/Actions.json
diff --git a/res/controllers/Default.json b/res/dpr-controller/Default.json
similarity index 100%
rename from res/controllers/Default.json
rename to res/dpr-controller/Default.json
diff --git a/res/controllers/ObjModelViveFocus3ControllerLeft.fbx b/res/dpr-controller/ObjModelViveFocus3ControllerLeft.fbx
similarity index 100%
rename from res/controllers/ObjModelViveFocus3ControllerLeft.fbx
rename to res/dpr-controller/ObjModelViveFocus3ControllerLeft.fbx
diff --git a/res/controllers/ObjModelViveFocus3ControllerRight.fbx b/res/dpr-controller/ObjModelViveFocus3ControllerRight.fbx
similarity index 100%
rename from res/controllers/ObjModelViveFocus3ControllerRight.fbx
rename to res/dpr-controller/ObjModelViveFocus3ControllerRight.fbx
diff --git a/res/controllers/Reference.txt b/res/dpr-controller/Reference.txt
similarity index 100%
rename from res/controllers/Reference.txt
rename to res/dpr-controller/Reference.txt
diff --git a/res/shaders/.gitignore b/res/dpr/.gitignore
similarity index 100%
rename from res/shaders/.gitignore
rename to res/dpr/.gitignore
diff --git a/res/shaders/data/indirect_data.inc b/res/dpr/data/indirect_data.inc
similarity index 100%
rename from res/shaders/data/indirect_data.inc
rename to res/dpr/data/indirect_data.inc
diff --git a/res/shaders/data/light_data.inc b/res/dpr/data/light_data.inc
similarity index 100%
rename from res/shaders/data/light_data.inc
rename to res/dpr/data/light_data.inc
diff --git a/res/shaders/data/material_data.inc b/res/dpr/data/material_data.inc
similarity index 100%
rename from res/shaders/data/material_data.inc
rename to res/dpr/data/material_data.inc
diff --git a/res/shaders/data/mesh_data.inc b/res/dpr/data/mesh_data.inc
similarity index 100%
rename from res/shaders/data/mesh_data.inc
rename to res/dpr/data/mesh_data.inc
diff --git a/res/shaders/data/per_frame.inc b/res/dpr/data/per_frame.inc
similarity index 100%
rename from res/shaders/data/per_frame.inc
rename to res/dpr/data/per_frame.inc
diff --git a/res/shaders/data/shadow_data.inc b/res/dpr/data/shadow_data.inc
similarity index 100%
rename from res/shaders/data/shadow_data.inc
rename to res/dpr/data/shadow_data.inc
diff --git a/res/dpr/strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.frag b/res/dpr/strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.frag
new file mode 100644
index 0000000000000000000000000000000000000000..7274e2d31b7a4c201d3c5a76936141961503ff15
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.frag
@@ -0,0 +1,53 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+
+#include "dpr_parameters.inc"
+layout(set = 4, binding = 0) uniform Frame {
+  DprParameters params;
+};
+
+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(location = 4) in vec4 inClipPos;
+
+layout(set = 1, binding = 0) uniform sampler2D samplerDiffuse;
+layout(set = 1, binding = 1) uniform sampler2D samplerNormal;
+
+layout(set = 3, binding = 1) uniform sampler2DArray samplerPreviousDepthBuffer;
+
+layout(location = 0) out vec4 outFragColor;
+// layout(location = 1) out vec4 outSecondLayer;
+
+void main() {
+    if (gl_Layer == 1) {
+      vec4 clipPos = inClipPos / inClipPos.w;
+      vec2 depthUV = clipPos.xy * 0.5 + 0.5;
+      float depth = texture(samplerPreviousDepthBuffer, vec3(depthUV, 0)).r;
+      /* if (clipPos.z <= depth + params.zThreshold) { */
+      /*   discard; */
+      /* } */
+      float zNear = 0.1;
+      float zFar = 256.0;
+      float linearDepth = zNear * zFar / (zFar + depth * (zNear - zFar)); 
+      // outFragColor = vec4(vec3(pow(depth, 64.0)), 1.0);
+    }
+
+    vec3 vertexNormal = normalize(inNormal);
+    vec3 vertexTangent = normalize(inTangent);
+    vec3 vertexBitangent = cross(vertexTangent, vertexNormal);
+    mat3 tangentToWorldSpace = mat3(vertexTangent, vertexBitangent, vertexNormal);
+    vec3 normalMapNormal = texture(samplerNormal, inUV).xyz * 2.0 - 1.0;
+    normalMapNormal.z = 1.0 - sqrt(normalMapNormal.x * normalMapNormal.x + normalMapNormal.y * normalMapNormal.y);
+    vec3 normal = tangentToWorldSpace * normalMapNormal;
+    vec4 diffuse = texture(samplerDiffuse, inUV);
+    float nDotL = dot(normal, normalize(vec3(0.1, 0.14, 1.0)));
+
+    /* if (gl_Layer == 0) { */
+    outFragColor = vec4(max(nDotL, 0.23) * diffuse.rgb, diffuse.a);
+    /* } */
+
+    // outFragColor = vec4(1.0);
+
+}
diff --git a/res/dpr/strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.geom b/res/dpr/strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.geom
new file mode 100644
index 0000000000000000000000000000000000000000..0370f2f10aecbca9e7905c9c9512fd6fd2917506
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.geom
@@ -0,0 +1,36 @@
+#version 450 core
+
+#extension GL_ARB_viewport_array : enable
+
+layout (triangles, invocations = 2) in;
+layout (triangle_strip, max_vertices = 3) out;
+
+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(location = 4) in vec4 inClipPos[];
+
+layout(location = 0) out vec3 outPos;
+layout(location = 1) out vec3 outNormal;
+layout(location = 2) out vec3 outTangent;
+layout(location = 3) out vec2 outUV;
+layout(location = 4) out vec4 outClipPos;
+
+in gl_PerVertex {
+    vec4 gl_Position;
+} gl_in[];
+
+void main() {
+    for (int i = 0; i < 3; ++i) {
+        outPos = inPos[i];
+        outNormal = inNormal[i];
+        outTangent = inTangent[i];
+        outUV = inUV[i];
+        outClipPos = inClipPos[i];
+        gl_Position = gl_in[i].gl_Position;
+        gl_Layer = gl_InvocationID;
+        EmitVertex();
+    }
+    EndPrimitive();
+}
diff --git a/res/dpr/strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.vert b/res/dpr/strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.vert
new file mode 100644
index 0000000000000000000000000000000000000000..1fdcd763f34c3a4d25ddf83bd0e3708fa3907a35
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/depth_peeling_reprojection_stereo.vert
@@ -0,0 +1,37 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+
+#include "mesh_data.inc"
+#include "per_frame.inc"
+
+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 perFrame;
+};
+layout(set = 2, binding = 0) uniform Mesh {
+    MeshData meshData;
+};
+
+layout(location = 0) out vec3 outPos;
+layout(location = 1) out vec3 outNormal;
+layout(location = 2) out vec3 outTangent;
+layout(location = 3) out vec2 outUV;
+layout(location = 4) out vec4 outClipPos;
+
+out gl_PerVertex {
+    vec4 gl_Position;
+};
+
+void main() {
+    vec4 screenSpacePos = perFrame.viewProjection * (meshData.localToWorldSpace * vec4(inPos, 1.0));
+    gl_Position = screenSpacePos;
+    outClipPos = screenSpacePos;
+    outPos = inPos;
+    outNormal = normalize((meshData.localToWorldSpace * vec4(inNormal, 0.0)).xzy);
+    outTangent = inTangent;
+    outUV = inUV;
+}
diff --git a/res/dpr/strategy/depth_peeling_reprojection/dpr_companion.frag b/res/dpr/strategy/depth_peeling_reprojection/dpr_companion.frag
new file mode 100644
index 0000000000000000000000000000000000000000..aee0d5b5c792e5640b8603f72b58ba7956328c83
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/dpr_companion.frag
@@ -0,0 +1,12 @@
+#version 450 core
+
+layout(location = 0) in vec2 inUV;
+
+layout(binding = 0) uniform sampler2D samplerLeftEye;
+layout(binding = 1) uniform sampler2D samplerRightEye;
+
+layout(location = 0) out vec4 outFragColor;
+
+void main() {
+    outFragColor = inUV.x < 1.0 ? texture(samplerLeftEye, inUV) : texture(samplerRightEye, inUV - vec2(1.0, 0.0));
+}
diff --git a/res/dpr/strategy/depth_peeling_reprojection/dpr_companion.vert b/res/dpr/strategy/depth_peeling_reprojection/dpr_companion.vert
new file mode 100644
index 0000000000000000000000000000000000000000..cde9a08dc8f7f6a8d2f58fe8279301dba5afd7e1
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/dpr_companion.vert
@@ -0,0 +1,14 @@
+#version 450 core
+
+layout(location = 0) in vec3 inPos;
+
+layout(location = 0) out vec2 outUV;
+
+out gl_PerVertex {
+    vec4 gl_Position;
+};
+
+void main() {
+    gl_Position = vec4(inPos.xyz, 1.0);
+    outUV = inPos.xy * vec2(1.0, 0.5) + vec2(1.0, 0.5);
+}
diff --git a/res/dpr/strategy/depth_peeling_reprojection/dpr_parameters.inc b/res/dpr/strategy/depth_peeling_reprojection/dpr_parameters.inc
new file mode 100644
index 0000000000000000000000000000000000000000..a765f0b3aaafc5df7ea26a5aaf6e2377c431f56d
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/dpr_parameters.inc
@@ -0,0 +1,8 @@
+struct DprParameters {
+    mat4 left_to_right_eye;
+    float z_min;
+    float z_max;
+    float zThreshold;
+    float discard_threshold;
+    int tesselation_level;
+};
diff --git a/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.frag b/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.frag
new file mode 100644
index 0000000000000000000000000000000000000000..31f46788fb2341f3b66c173375f6bb8b462690db
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.frag
@@ -0,0 +1,22 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+
+#include "dpr_parameters.inc"
+layout(set = 0, binding = 0) uniform Frame {
+  DprParameters params;
+};
+layout(location = 0) in vec2 inUV;
+layout(location = 1) in flat int inInstanceIndex;
+
+layout(location = 0) out vec4 outFragColor;
+
+layout(binding = 2) uniform sampler2DArray samplerLeftEye;
+
+void main() {
+    const vec2 dx = abs(dFdx(inUV));
+    if (max(dx.x, dx.y) < params.discard_threshold) {
+        discard;
+    }
+    outFragColor = texture(samplerLeftEye, vec3(inUV, 1.0 - inInstanceIndex));
+    /* outFragColor = vec4(dx * 100, 0.0, 1.0); */
+}
diff --git a/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.tesc b/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.tesc
new file mode 100644
index 0000000000000000000000000000000000000000..4613c9c5b5782b0ca5b684bdc0adec852a015452
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.tesc
@@ -0,0 +1,28 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+
+#include "dpr_parameters.inc"
+layout(set = 0, binding = 0) uniform Frame {
+  DprParameters params;
+};
+
+layout (vertices = 4) out;
+
+layout(location = 0) in vec2 inPos[];
+layout(location = 0) out vec2 outPos[];
+layout(location = 1) in int inInstanceIndex[];
+layout(location = 1) out int outInstanceIndex[];
+
+void main() {
+  outPos[gl_InvocationID] = inPos[gl_InvocationID];
+  outInstanceIndex[gl_InvocationID] = inInstanceIndex[gl_InvocationID];
+
+  const float tessFactor = params.tesselation_level;
+  gl_TessLevelOuter[0] = tessFactor;
+  gl_TessLevelOuter[1] = tessFactor;
+  gl_TessLevelOuter[2] = tessFactor;
+  gl_TessLevelOuter[3] = tessFactor;
+  gl_TessLevelInner[0] = tessFactor;
+  gl_TessLevelInner[1] = tessFactor;
+}
+
diff --git a/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.tese b/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.tese
new file mode 100644
index 0000000000000000000000000000000000000000..46ff22968064439226a632ff775f595418021e32
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.tese
@@ -0,0 +1,33 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+
+#include "dpr_parameters.inc"
+
+layout(set = 0, binding = 0) uniform Frame {
+  DprParameters params;
+};
+layout(binding = 1) uniform sampler2DArray samplerDepthLeftEye;
+
+layout (quads, equal_spacing, ccw) in;
+
+layout(location = 0) in vec2 inPos[];
+layout(location = 0) out vec2 outUV;
+layout(location = 1) in int inInstanceIndex[];
+layout(location = 1) out int outInstanceIndex;
+
+void main() {
+  const vec2 oldPosition =
+    mix(
+      mix(inPos[0], inPos[3], gl_TessCoord.x),
+      mix(inPos[1], inPos[2], gl_TessCoord.x),
+      gl_TessCoord.y
+    );
+
+  outUV = oldPosition;
+  const float depth = clamp(texture(samplerDepthLeftEye, vec3(oldPosition, 1.0 - inInstanceIndex[0])).r, params.z_min, params.z_max);
+  gl_Position = params.left_to_right_eye * vec4(oldPosition * 2.0 - 1.0, depth, 1.0);
+  gl_Position /= gl_Position.w;
+  outInstanceIndex = inInstanceIndex[0];
+}
+
+
diff --git a/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.vert b/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.vert
new file mode 100644
index 0000000000000000000000000000000000000000..5bbe4053b238e864e21d1d6cbb9da531f844ee31
--- /dev/null
+++ b/res/dpr/strategy/depth_peeling_reprojection/dpr_reproject.vert
@@ -0,0 +1,11 @@
+#version 450 core
+#extension GL_GOOGLE_include_directive : require
+
+layout(location = 0) in vec2 inPos;
+layout(location = 0) out vec2 outPos;
+layout(location = 1) out int instanceIndex;
+
+void main() {
+    outPos = inPos;
+    instanceIndex = gl_InstanceIndex;
+}
diff --git a/res/shaders/strategy/multi_view/multi_view_stereo.frag b/res/dpr/strategy/multi_view/multi_view_stereo.frag
similarity index 100%
rename from res/shaders/strategy/multi_view/multi_view_stereo.frag
rename to res/dpr/strategy/multi_view/multi_view_stereo.frag
diff --git a/res/shaders/strategy/multi_view/multi_view_stereo.vert b/res/dpr/strategy/multi_view/multi_view_stereo.vert
similarity index 100%
rename from res/shaders/strategy/multi_view/multi_view_stereo.vert
rename to res/dpr/strategy/multi_view/multi_view_stereo.vert
diff --git a/res/shaders/strategy/native_deferred/native_stereo_deferred.frag b/res/dpr/strategy/native_deferred/native_stereo_deferred.frag
similarity index 100%
rename from res/shaders/strategy/native_deferred/native_stereo_deferred.frag
rename to res/dpr/strategy/native_deferred/native_stereo_deferred.frag
diff --git a/res/shaders/strategy/native_deferred/native_stereo_deferred.vert b/res/dpr/strategy/native_deferred/native_stereo_deferred.vert
similarity index 100%
rename from res/shaders/strategy/native_deferred/native_stereo_deferred.vert
rename to res/dpr/strategy/native_deferred/native_stereo_deferred.vert
diff --git a/res/shaders/strategy/native_forward/native_stereo_forward.frag b/res/dpr/strategy/native_forward/native_stereo_forward.frag
similarity index 100%
rename from res/shaders/strategy/native_forward/native_stereo_forward.frag
rename to res/dpr/strategy/native_forward/native_stereo_forward.frag
diff --git a/res/shaders/strategy/native_forward/native_stereo_forward.vert b/res/dpr/strategy/native_forward/native_stereo_forward.vert
similarity index 100%
rename from res/shaders/strategy/native_forward/native_stereo_forward.vert
rename to res/dpr/strategy/native_forward/native_stereo_forward.vert
diff --git a/res/shaders/utility/deferred_lighting.frag b/res/dpr/utility/deferred_lighting.frag
similarity index 100%
rename from res/shaders/utility/deferred_lighting.frag
rename to res/dpr/utility/deferred_lighting.frag
diff --git a/res/shaders/utility/deferred_lighting.vert b/res/dpr/utility/deferred_lighting.vert
similarity index 100%
rename from res/shaders/utility/deferred_lighting.vert
rename to res/dpr/utility/deferred_lighting.vert
diff --git a/res/shaders/utility/deferred_lighting_base.glsl b/res/dpr/utility/deferred_lighting_base.glsl
similarity index 100%
rename from res/shaders/utility/deferred_lighting_base.glsl
rename to res/dpr/utility/deferred_lighting_base.glsl
diff --git a/res/shaders/utility/deferred_lighting_indirect.frag b/res/dpr/utility/deferred_lighting_indirect.frag
similarity index 100%
rename from res/shaders/utility/deferred_lighting_indirect.frag
rename to res/dpr/utility/deferred_lighting_indirect.frag
diff --git a/res/shaders/utility/deferred_lighting_indirect_shadow.frag b/res/dpr/utility/deferred_lighting_indirect_shadow.frag
similarity index 100%
rename from res/shaders/utility/deferred_lighting_indirect_shadow.frag
rename to res/dpr/utility/deferred_lighting_indirect_shadow.frag
diff --git a/res/shaders/utility/deferred_lighting_shadow.frag b/res/dpr/utility/deferred_lighting_shadow.frag
similarity index 100%
rename from res/shaders/utility/deferred_lighting_shadow.frag
rename to res/dpr/utility/deferred_lighting_shadow.frag
diff --git a/res/shaders/utility/encode_chroma_subsampling.frag b/res/dpr/utility/encode_chroma_subsampling.frag
similarity index 100%
rename from res/shaders/utility/encode_chroma_subsampling.frag
rename to res/dpr/utility/encode_chroma_subsampling.frag
diff --git a/res/shaders/utility/encode_chroma_subsampling.vert b/res/dpr/utility/encode_chroma_subsampling.vert
similarity index 100%
rename from res/shaders/utility/encode_chroma_subsampling.vert
rename to res/dpr/utility/encode_chroma_subsampling.vert
diff --git a/res/shaders/utility/encode_color_conversion.frag b/res/dpr/utility/encode_color_conversion.frag
similarity index 100%
rename from res/shaders/utility/encode_color_conversion.frag
rename to res/dpr/utility/encode_color_conversion.frag
diff --git a/res/shaders/utility/encode_color_conversion.vert b/res/dpr/utility/encode_color_conversion.vert
similarity index 100%
rename from res/shaders/utility/encode_color_conversion.vert
rename to res/dpr/utility/encode_color_conversion.vert
diff --git a/res/shaders/utility/geometry_buffer_library.glsl b/res/dpr/utility/geometry_buffer_library.glsl
similarity index 100%
rename from res/shaders/utility/geometry_buffer_library.glsl
rename to res/dpr/utility/geometry_buffer_library.glsl
diff --git a/res/shaders/utility/indirect_capture.frag b/res/dpr/utility/indirect_capture.frag
similarity index 100%
rename from res/shaders/utility/indirect_capture.frag
rename to res/dpr/utility/indirect_capture.frag
diff --git a/res/shaders/utility/indirect_capture.vert b/res/dpr/utility/indirect_capture.vert
similarity index 100%
rename from res/shaders/utility/indirect_capture.vert
rename to res/dpr/utility/indirect_capture.vert
diff --git a/res/shaders/utility/indirect_geometry.frag b/res/dpr/utility/indirect_geometry.frag
similarity index 100%
rename from res/shaders/utility/indirect_geometry.frag
rename to res/dpr/utility/indirect_geometry.frag
diff --git a/res/shaders/utility/indirect_geometry.geom b/res/dpr/utility/indirect_geometry.geom
similarity index 100%
rename from res/shaders/utility/indirect_geometry.geom
rename to res/dpr/utility/indirect_geometry.geom
diff --git a/res/shaders/utility/indirect_geometry.vert b/res/dpr/utility/indirect_geometry.vert
similarity index 100%
rename from res/shaders/utility/indirect_geometry.vert
rename to res/dpr/utility/indirect_geometry.vert
diff --git a/res/shaders/utility/indirect_injection.frag b/res/dpr/utility/indirect_injection.frag
similarity index 100%
rename from res/shaders/utility/indirect_injection.frag
rename to res/dpr/utility/indirect_injection.frag
diff --git a/res/shaders/utility/indirect_injection.geom b/res/dpr/utility/indirect_injection.geom
similarity index 100%
rename from res/shaders/utility/indirect_injection.geom
rename to res/dpr/utility/indirect_injection.geom
diff --git a/res/shaders/utility/indirect_injection.vert b/res/dpr/utility/indirect_injection.vert
similarity index 100%
rename from res/shaders/utility/indirect_injection.vert
rename to res/dpr/utility/indirect_injection.vert
diff --git a/res/shaders/utility/indirect_library.glsl b/res/dpr/utility/indirect_library.glsl
similarity index 100%
rename from res/shaders/utility/indirect_library.glsl
rename to res/dpr/utility/indirect_library.glsl
diff --git a/res/shaders/utility/indirect_propagation.comp b/res/dpr/utility/indirect_propagation.comp
similarity index 100%
rename from res/shaders/utility/indirect_propagation.comp
rename to res/dpr/utility/indirect_propagation.comp
diff --git a/res/shaders/utility/light_library.glsl b/res/dpr/utility/light_library.glsl
similarity index 100%
rename from res/shaders/utility/light_library.glsl
rename to res/dpr/utility/light_library.glsl
diff --git a/res/shaders/utility/material_library.glsl b/res/dpr/utility/material_library.glsl
similarity index 100%
rename from res/shaders/utility/material_library.glsl
rename to res/dpr/utility/material_library.glsl
diff --git a/res/shaders/utility/material_struct.glsl b/res/dpr/utility/material_struct.glsl
similarity index 100%
rename from res/shaders/utility/material_struct.glsl
rename to res/dpr/utility/material_struct.glsl
diff --git a/res/shaders/utility/math_library.glsl b/res/dpr/utility/math_library.glsl
similarity index 100%
rename from res/shaders/utility/math_library.glsl
rename to res/dpr/utility/math_library.glsl
diff --git a/res/shaders/utility/shadow.geom b/res/dpr/utility/shadow.geom
similarity index 100%
rename from res/shaders/utility/shadow.geom
rename to res/dpr/utility/shadow.geom
diff --git a/res/shaders/utility/shadow.vert b/res/dpr/utility/shadow.vert
similarity index 100%
rename from res/shaders/utility/shadow.vert
rename to res/dpr/utility/shadow.vert
diff --git a/src/encoder/vulkan_encoder.cpp b/src/encoder/vulkan_encoder.cpp
index 1a9d8bf6c1344b2c4bf4c0be23d646dd0f7542b6..48a17447effad710a54f7f0e9856513ee2a5a0d3 100644
--- a/src/encoder/vulkan_encoder.cpp
+++ b/src/encoder/vulkan_encoder.cpp
@@ -1515,12 +1515,12 @@ bool VulkanEncoder::create_convert_pipeline(lava::device_ptr device, VulkanEncod
     frame->convert_pipeline->add_color_blend_attachment(luma_blend_state);
     frame->convert_pipeline->add_color_blend_attachment(chroma_blend_state);
 
-    if (!frame->convert_pipeline->add_shader(lava::file_data("shaders/binary/encode_color_conversion_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!frame->convert_pipeline->add_shader(lava::file_data("dpr/binary/encode_color_conversion_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         return false;
     }
 
-    if (!frame->convert_pipeline->add_shader(lava::file_data("shaders/binary/encode_color_conversion_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    if (!frame->convert_pipeline->add_shader(lava::file_data("dpr/binary/encode_color_conversion_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         return false;
     }
@@ -1618,12 +1618,12 @@ bool VulkanEncoder::create_subsample_pipeline(lava::device_ptr device, VulkanEnc
     frame->subsample_pipeline->set_input_assembly_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
     frame->subsample_pipeline->add_color_blend_attachment(chroma_blend_state);
 
-    if (!frame->subsample_pipeline->add_shader(lava::file_data("shaders/binary/encode_chroma_subsampling_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!frame->subsample_pipeline->add_shader(lava::file_data("dpr/binary/encode_chroma_subsampling_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         return false;
     }
 
-    if (!frame->subsample_pipeline->add_shader(lava::file_data("shaders/binary/encode_chroma_subsampling_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    if (!frame->subsample_pipeline->add_shader(lava::file_data("dpr/binary/encode_chroma_subsampling_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         return false;
     }
diff --git a/src/headset/openvr_headset.cpp b/src/headset/openvr_headset.cpp
index bfb08dbcbdea159ad6a439ded62a36ab9058bca5..712fc85e6cd86ca4075aece7aff91279451fd757 100644
--- a/src/headset/openvr_headset.cpp
+++ b/src/headset/openvr_headset.cpp
@@ -303,7 +303,7 @@ void OpenVRHeadset::compute_matrices(Eye eye)
 
 bool OpenVRHeadset::create_actions()
 {
-    if (vr::VRInput()->SetActionManifestPath((std::string(RESOURCE_FOLDER) + "/controllers/Actions.json").c_str()) != vr::VRInputError_None)
+    if (vr::VRInput()->SetActionManifestPath((std::string(RESOURCE_FOLDER) + "/dpr-controller/Actions.json").c_str()) != vr::VRInputError_None)
     {
         lava::log()->error("OpenVR: Can't set action manifest!");
 
diff --git a/src/headset/remote_headset.cpp b/src/headset/remote_headset.cpp
index 5250fd3d30ecfdcef11ac728e07acb6cccc5ee77..1b0f86744234e300ea066052f3855ba55d47c692 100644
--- a/src/headset/remote_headset.cpp
+++ b/src/headset/remote_headset.cpp
@@ -630,8 +630,8 @@ bool RemoteHeadset::convert_strategy(StereoStrategyType strategy_type, RemoteStr
     case STEREO_STRATEGY_TYPE_MULTI_VIEW:
         remote_strategy = REMOTE_STRATEGY_NATIVE;
         break;
-    case STEREO_STRATEGY_TYPE_MULTI_VIEW:
-        strategy_id = STEREO_STRATEGY_ID_NATIVE_STEREO;
+    case STEREO_STRATEGY_TYPE_DEPTH_PEELING_REPROJECTION:
+        remote_strategy = REMOTE_STRATEGY_NATIVE;
         break;
     default:
         lava::log()->error("Remote Headset: Unkown strategy type!");
diff --git a/src/main.cpp b/src/main.cpp
index bc9ee5be81c3a082755667cbed28931cc34f07e7..5286d6ec9cabd8de6cf936aa2f54afb2ac7cc6ad 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4,7 +4,7 @@ int main(int argc, char* argv[])
 {
     VRApplication application;
     
-    if (!application.setup("Multi Layer Reprojection", { argc, argv }))
+    if (!application.setup("Depth Peeling Reprojection", { argc, argv }))
     {
         return -1;
     }
diff --git a/src/scene.hpp b/src/scene.hpp
index 665a298c794d1e5b3bf2182ffa2a8f1c0f1714bd..591b0d261a98b96a5434fc05682c917b87821faa 100644
--- a/src/scene.hpp
+++ b/src/scene.hpp
@@ -11,9 +11,9 @@ namespace glsl
 {
 using namespace glm;
 using uint = glm::uint32;
-#include "res/shaders/data/mesh_data.inc"
-#include "res/shaders/data/light_data.inc"
-#include "res/shaders/data/material_data.inc"
+#include "res/dpr/data/mesh_data.inc"
+#include "res/dpr/data/light_data.inc"
+#include "res/dpr/data/material_data.inc"
 }
 
 #define INVALID_NODE -1
diff --git a/src/strategy/depth_peeling_reprojection_stereo.cpp b/src/strategy/depth_peeling_reprojection_stereo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8e46214e8cbb3527ea6fe815ff79e0c8d897313b
--- /dev/null
+++ b/src/strategy/depth_peeling_reprojection_stereo.cpp
@@ -0,0 +1,831 @@
+#include "depth_peeling_reprojection_stereo.hpp"
+#include "imgui.h"
+#include "vr_application.hpp"
+
+using namespace lava;
+
+//---------------------------------------------------------------------------------------------------
+// Implementation of the functions introcued by the new software architecture.
+
+bool DepthPeelingReprojectionStereo::on_create()
+{
+    VkSamplerCreateInfo const sampler_info = {
+        .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+        .magFilter = VK_FILTER_LINEAR,
+        .minFilter = VK_FILTER_LINEAR,
+        .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR
+    };
+    if (!get_device()->vkCreateSampler(&sampler_info, &sampler)) {
+        return false;
+    }
+
+    color_attachment = make_attachment(get_headset()->get_format());
+    color_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE);
+    color_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE);
+    color_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+    return this->create();
+}
+
+void DepthPeelingReprojectionStereo::on_destroy()
+{
+    vkDestroySampler(get_device()->get(), sampler, lava::memory::alloc());
+
+    this->destructor();
+}
+
+bool DepthPeelingReprojectionStereo::on_interface()
+{
+    this->draw_imgui();
+
+    return true;
+}
+
+bool DepthPeelingReprojectionStereo::on_update(lava::delta delta_time)
+{
+    this->update();
+
+    return true;
+}
+
+bool DepthPeelingReprojectionStereo::on_render(VkCommandBuffer command_buffer, lava::index frame)
+{
+    this->write_buffer(frame);
+
+    insert_image_memory_barrier(get_device(), command_buffer, this->get_headset()->get_framebuffer(EYE_LEFT)->get(),
+                                VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
+                                VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                                this->get_headset()->get_framebuffer(EYE_LEFT)->get_subresource_range());
+    insert_image_memory_barrier(get_device(), command_buffer, this->get_headset()->get_framebuffer(EYE_RIGHT)->get(),
+                                VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
+                                VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                                this->get_headset()->get_framebuffer(EYE_LEFT)->get_subresource_range());
+
+    std::array<uint8_t, 1> metadata = { 0x00 };
+    this->get_headset()->submit_metadata(metadata);
+
+    this->render(command_buffer, frame);
+    this->render_companion_window(command_buffer);
+
+    this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, EYE_LEFT);
+    this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, EYE_RIGHT);
+
+    return true;
+}
+
+uint32_t DepthPeelingReprojectionStereo::get_max_remote_frame_ids() const
+{
+    return 2;
+}
+
+const char* DepthPeelingReprojectionStereo::get_name() const
+{
+    return "Depth Peeling Reprojection";
+}
+
+DepthPeelingReprojectionStereo::Ptr make_depth_peeling_reprojection_stereo()
+{
+    return std::make_shared<DepthPeelingReprojectionStereo>();
+}
+
+//---------------------------------------------------------------------------------------------------
+// Mostly untouched code of the depth peeling reprojection strategy
+
+DepthPeelingReprojectionStereo::DepthPeelingReprojectionStereo()
+: current_render_pass_(0) {
+
+}
+
+void DepthPeelingReprojectionStereo::destructor() {
+    pipeline_layout_->destroy();
+    for (auto& render_pass : render_passes_) {
+        render_pass->destroy();
+    }
+
+    if (reprojection_pipeline_ != nullptr) {
+        reprojection_pipeline_->destroy();
+    }
+
+    if (reprojection_pipeline_layout_ != nullptr) {
+        reprojection_pipeline_layout_->destroy();
+    }
+
+    if (reprojection_render_pass_ != nullptr) {
+        reprojection_render_pass_->destroy();
+    }
+
+    if (companion_window_pipeline_ != nullptr) {
+        companion_window_pipeline_->destroy();
+    }
+
+    if (companion_window_pipeline_layout_ != nullptr) {
+        companion_window_pipeline_layout_->destroy();
+    }
+
+    if (color_layers_ != nullptr) {
+        color_layers_->destroy();
+    }
+
+    for (auto& depth_stencil_layer : depth_stencil_layers_) {
+        if (depth_stencil_layer != nullptr) {
+            depth_stencil_layer->destroy();
+        }
+    }
+
+    if (second_layer_image_ != nullptr) {
+        second_layer_image_->destroy();
+    }
+
+    for (auto& descriptor_set : descriptor_sets_) {
+        if (descriptor_set != nullptr) {
+            descriptor_->free(descriptor_set, descriptor_pool_->get());
+        }
+    }
+
+    if (descriptor_ != nullptr) {
+        descriptor_->destroy();
+    }
+
+    for (auto& descriptor_set_list : reprojection_pipeline_descriptor_set_) {
+        for (auto& descriptor_set : descriptor_set_list) {
+            reprojection_pipeline_descriptor_->free(descriptor_set, descriptor_pool_->get());
+        }
+    }
+
+    if (reprojection_pipeline_descriptor_ != nullptr) {
+        reprojection_pipeline_descriptor_->destroy();
+    }
+
+    if (companion_window_pipeline_descriptor_set_ != nullptr) {
+        companion_window_pipeline_descriptor_->free(companion_window_pipeline_descriptor_set_, descriptor_pool_->get());
+    }
+
+    if (companion_window_pipeline_descriptor_ != nullptr) {
+        companion_window_pipeline_descriptor_->destroy();
+    }
+
+    if (descriptor_pool_ != nullptr) {
+        descriptor_pool_->destroy();
+    }
+}
+
+bool DepthPeelingReprojectionStereo::create() {
+    framebuffer_size_ = get_headset()->get_resolution();
+    descriptor_ = make_descriptor();
+    descriptor_->add_binding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT);
+    descriptor_->add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
+    if (!descriptor_->create(get_device())) {
+        return false;
+    }
+
+    reprojection_pipeline_descriptor_ = make_descriptor();
+    reprojection_pipeline_descriptor_->add_binding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
+    reprojection_pipeline_descriptor_->add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
+    reprojection_pipeline_descriptor_->add_binding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
+    if (!reprojection_pipeline_descriptor_->create(get_device())) {
+        return false;
+    }
+
+    pipeline_layout_ = make_pipeline_layout();
+    pipeline_layout_->add(get_stereo_transform()->get_descriptor());
+    pipeline_layout_->add(get_scene()->get_material_descriptor());
+    pipeline_layout_->add(get_scene()->get_mesh_descriptor());
+    pipeline_layout_->add(descriptor_);
+    pipeline_layout_->add(reprojection_pipeline_descriptor_);
+    if (!pipeline_layout_->create(get_device())) {
+        return false;
+    }
+
+    descriptor_pool_ = make_descriptor_pool();
+    if (!descriptor_pool_->create(get_device(), {
+            { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2 + 4 * get_application()->get_frame_count() }, //4 * app()->frame_count() for reprojection_pipeline_descriptor_set_
+            { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 + 2 * get_application()->get_frame_count() }, //2 * app()->frame_count() for reprojection_pipeline_descriptor_set_
+        }, 2 + 2 * get_application()->get_frame_count())) { //2 * app()->frame_count() for reprojection_pipeline_descriptor_set_
+        return false;
+    }
+
+    color_layers_ = make_image_array(VK_FORMAT_R8G8B8A8_UNORM);
+    color_layers_->set_usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+    color_layers_->set_tiling(VK_IMAGE_TILING_OPTIMAL);
+    if (!color_layers_->create(get_device(), framebuffer_size_, 2)) {
+        log()->error("Failed to create color layer images");
+        return {};
+    }
+    color_layers_attachment_ = make_attachment(VK_FORMAT_R8G8B8A8_UNORM);
+    color_layers_attachment_->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE);
+    color_layers_attachment_->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE);
+    color_layers_attachment_->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+    depth_stencil_layers_[0] = make_image_array(VK_FORMAT_D32_SFLOAT);
+    depth_stencil_layers_[0]->set_usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+    depth_stencil_layers_[0]->set_tiling(VK_IMAGE_TILING_OPTIMAL);
+    if (!depth_stencil_layers_[0]->create(get_device(), framebuffer_size_, 2)) {
+        log()->error("Failed to depth stencil layer images 1");
+        return {};
+    }
+    depth_stencil_layers_attachment_[0] = make_attachment(VK_FORMAT_D32_SFLOAT);
+    depth_stencil_layers_attachment_[0]->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE);
+    depth_stencil_layers_attachment_[0]->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE);
+    depth_stencil_layers_attachment_[0]->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+    depth_stencil_layers_[1] = make_image_array(VK_FORMAT_D32_SFLOAT);
+    depth_stencil_layers_[1]->set_usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+    depth_stencil_layers_[1]->set_tiling(VK_IMAGE_TILING_OPTIMAL);
+    if (!depth_stencil_layers_[1]->create(get_device(), framebuffer_size_, 2)) {
+        log()->error("Failed to depth stencil layer images 1");
+        return {};
+    }
+    depth_stencil_layers_attachment_[1] = make_attachment(VK_FORMAT_D32_SFLOAT);
+    depth_stencil_layers_attachment_[1]->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE);
+    depth_stencil_layers_attachment_[1]->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE);
+    depth_stencil_layers_attachment_[1]->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+    render_passes_[0] = create_render_pass(0);
+    render_passes_[1] = create_render_pass(1);
+    if (!create_reprojection_render_pass()) {
+      return false;
+    }
+
+    return true;
+}
+
+void DepthPeelingReprojectionStereo::render(VkCommandBuffer command_buffer, lava::index frame) {
+    current_render_pass_ = (current_render_pass_ + 1) & 1;
+    uint32_t depth_read_layer = (current_render_pass_ + 1) & 1;
+    VkImageSubresourceRange const image_range{
+        .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
+        .levelCount = 1,
+        .layerCount = 1,
+    };
+    insert_image_memory_barrier(get_device(), command_buffer, depth_stencil_layers_[depth_read_layer]->get(),
+                        VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
+                        VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                        VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                        image_range);
+
+    render_passes_[current_render_pass_]->process(command_buffer, 0);
+
+    VkImageSubresourceRange const color_range {
+        .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+        .levelCount = 1,
+        .layerCount = 2,
+    };
+    insert_image_memory_barrier(get_device(), command_buffer, color_layers_->get(),
+                        VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
+                        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                        VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                        color_range);
+    reprojection_render_pass_->process(command_buffer, 0);
+    // insert_image_memory_barrier(app()->device(), command_buffer, depth_stencil_layers_[depth_read_layer]->get(),
+    //                     VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
+    //                     VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+    //                     VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+    //                     image_range);
+}
+
+void DepthPeelingReprojectionStereo::render_companion_window(VkCommandBuffer command_buffer) {
+    VkImageSubresourceRange const color_range {
+        .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+        .levelCount = 1,
+        .layerCount = 1,
+    };
+    insert_image_memory_barrier(get_device(), command_buffer, color_layers_->get(),
+                        VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
+                        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                        VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                        color_range);
+    VkImageCopy left_eye_region {
+        .srcSubresource = VkImageSubresourceLayers {
+            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+            .mipLevel = 0,
+            .baseArrayLayer = 0,
+            .layerCount = 1,
+        },
+        .srcOffset = VkOffset3D {
+            .x = 0,
+            .y = 0,
+            .z = 0,
+        },
+        .dstSubresource = get_headset()->get_framebuffer(EYE_LEFT)->get_subresource_layers(),
+        .dstOffset = VkOffset3D {
+            .x = 0,
+            .y = 0,
+            .z = 0,
+        },
+        .extent = VkExtent3D {
+            .width = get_headset()->get_resolution().x,
+            .height = get_headset()->get_resolution().y,
+            .depth = 1,
+        },
+    };
+
+    vkCmdCopyImage(
+        command_buffer,
+        color_layers_->get(),
+        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+        get_headset()->get_framebuffer(EYE_LEFT)->get(),
+        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+        1, &left_eye_region);
+
+    VkImageCopy right_eye_region {
+        .srcSubresource = VkImageSubresourceLayers {
+            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+            .mipLevel = 0,
+            .baseArrayLayer = 1,
+            .layerCount = 1,
+        },
+        .srcOffset = VkOffset3D {
+            .x = 0,
+            .y = 0,
+            .z = 0,
+        },
+        .dstSubresource = VkImageSubresourceLayers {
+            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+            .mipLevel = 0,
+            .baseArrayLayer = 0,
+            .layerCount = 1,
+        },
+        .dstOffset = VkOffset3D {
+            .x = 0,
+            .y = 0,
+            .z = 0,
+        },
+        .extent = VkExtent3D {
+            .width = get_headset()->get_resolution().x,
+            .height = get_headset()->get_resolution().y,
+            .depth = 1,
+        },
+    };
+
+    VkImageSubresourceRange const image_range{
+        .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+        .levelCount = 1,
+        .layerCount = 1,
+    };
+    insert_image_memory_barrier(get_device(), command_buffer, get_headset()->get_framebuffer(EYE_LEFT)->get(),
+                        VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
+                        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                        VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                        get_headset()->get_framebuffer(EYE_LEFT)->get_subresource_range());
+    // insert_image_memory_barrier(app()->device(), command_buffer, app()->right_eye_framebuffer()->color_image->get(),
+    //                     VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
+    //                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+    //                     VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+    //                     image_range);
+}
+
+void DepthPeelingReprojectionStereo::update() {
+    const glm::dmat4 right_eye_transform = get_stereo_transform()->get_view_eye_projection_matrix(EYE_RIGHT);
+    const glm::dmat4 left_eye_transform = get_stereo_transform()->get_view_eye_projection_matrix(EYE_LEFT);
+
+    params.left_to_right_eye = glm::mat4(right_eye_transform * glm::inverse(left_eye_transform));
+}
+
+void DepthPeelingReprojectionStereo::write_buffer(lava::index frame) {
+    std::memcpy(reproject_ubo_[frame]->get_mapped_data(), &params, sizeof(glsl::DprParameters));
+}
+
+void DepthPeelingReprojectionStereo::draw_imgui() {
+    if (ImGui::CollapsingHeader("Depth Peeling Reprojection", ImGuiTreeNodeFlags_DefaultOpen)) {
+        ImGui::InputFloat("Discard Threshold", &params.discard_threshold, 0.0001, 0.001, "%.10f");
+        ImGui::InputInt("Tesselation Level", &params.tesselation_level, 1.0);
+        ImGui::InputFloat("Z-min", &params.z_min, 0.00001, 0.00001, "%.10f");
+        ImGui::InputFloat("Z-max", &params.z_max, 0.00001, 0.00001, "%.10f");
+        ImGui::InputFloat("Depth Threshold", &params.zThreshold, 0.00001, 0.00001, "%.20f");
+
+        bool draw_first_layer = (layers_to_draw_ & 0b01) != 0;
+        ImGui::Checkbox("First Layer", &draw_first_layer);
+        bool draw_second_layer = (layers_to_draw_ & 0b10) != 0;
+        ImGui::Checkbox("Second Layer", &draw_second_layer);
+        layers_to_draw_ = (draw_first_layer ? 0b01 : 0) | (draw_second_layer ? 0b10 : 0);
+    }
+}
+
+render_pass::ptr DepthPeelingReprojectionStereo::create_render_pass(lava::index render_pass_index) {
+    descriptor_sets_[render_pass_index] = descriptor_->allocate_set(descriptor_pool_->get());
+    VkDescriptorImageInfo previous_depth_buffer;
+    previous_depth_buffer.sampler = sampler;
+    previous_depth_buffer.imageView = depth_stencil_layers_[(render_pass_index + 1) % 2]->get_layer_view(0);
+    previous_depth_buffer.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+    get_device()->vkUpdateDescriptorSets({
+        {
+            .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+            .dstSet = descriptor_sets_[render_pass_index],
+            .dstBinding = 1,
+            .descriptorCount = 1,
+            .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+            .pImageInfo = &previous_depth_buffer,
+        },
+    });
+
+    auto pipeline = make_graphics_pipeline(get_device());
+
+    Scene::set_vertex_input(pipeline.get());
+
+    const VkPipelineColorBlendAttachmentState blend_state = {
+        .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+    };
+    pipeline->add_color_blend_attachment(blend_state);
+    pipeline->set_depth_test_and_write(true, true);
+    pipeline->set_depth_compare_op(VK_COMPARE_OP_LESS);
+
+    pipeline->on_process = [this, render_pass_index](VkCommandBuffer command_buffer) {
+        pipeline_layout_->bind(command_buffer, get_stereo_transform()->get_descriptor_set(EYE_LEFT, get_application()->get_frame_index()), 0);
+        pipeline_layout_->bind(command_buffer, descriptor_sets_[render_pass_index], 3);
+        pipeline_layout_->bind(command_buffer, reprojection_pipeline_descriptor_set_[0][get_application()->get_frame_index()], 4);
+
+        for (size_t i = 0; i < get_scene()->get_meshes().size(); ++i) {
+            const auto& mesh = get_scene()->get_meshes()[i];
+            const auto& material = get_scene()->get_materials()[mesh.material_index];
+
+            if (!mesh.visible) {
+                continue;
+            }
+
+            pipeline_layout_->bind(command_buffer, material.descriptor_set, 1);
+            pipeline_layout_->bind(command_buffer, mesh.descriptor_set[get_application()->get_frame_index()], 2);
+
+            mesh.mesh->bind_draw(command_buffer);
+        }
+    };
+    pipeline->set_layout(pipeline_layout_);
+
+    if (!pipeline->add_shader(file_data("dpr/binary/depth_peeling_reprojection_stereo_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) {
+        log()->error("Failed to load shader");
+        throw std::runtime_error("Failed to load shader");
+    }
+
+    if (!pipeline->add_shader(file_data("dpr/binary/depth_peeling_reprojection_stereo_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT)) {
+        log()->error("Failed to load shader");
+        throw std::runtime_error("Failed to load shader");
+    }
+
+    if (!pipeline->add_shader(file_data("dpr/binary/depth_peeling_reprojection_stereo_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) {
+        log()->error("Failed to load shader");
+        throw std::runtime_error("Failed to load shader");
+    }
+
+    auto render_pass = make_render_pass(get_device());
+    render_pass->set_clear_color();
+    render_pass->set_layers(2);
+
+    subpass::ptr subpass = make_subpass();
+
+    VkAttachmentReference color_attachment {
+        .attachment = 0,
+        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+    };
+    subpass->set_color_attachment(color_attachment);
+
+    VkAttachmentReference depth_stencil_attachment;
+    depth_stencil_attachment.attachment = 1;
+    depth_stencil_attachment.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+    subpass->set_depth_stencil_attachment(depth_stencil_attachment);
+
+    render_pass->add(color_layers_attachment_);
+    render_pass->add(depth_stencil_layers_attachment_[render_pass_index]);
+    render_pass->add(subpass);
+
+    subpass_dependency::ptr dependency = make_subpass_dependency(VK_SUBPASS_EXTERNAL, 0);
+    // wait for previous fragment shader to finish reading before clearing attachments
+    dependency->set_stage_mask(
+        VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT);
+    // we need a memory barrier because this isn't a standard write-after-read hazard
+    // subpass deps have an implicit attachment layout transition, so the dst access mask must be correct
+    dependency->set_access_mask(0,
+                                VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
+    render_pass->add(dependency);
+
+    dependency = make_subpass_dependency(render_pass->get_subpass_count() - 1, VK_SUBPASS_EXTERNAL);
+    // don't run any fragment shader (sample attachments) before we're done writing to attachments
+    dependency->set_stage_mask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
+                               VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+    // make attachment writes visible to subsequent reads
+    dependency->set_access_mask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+                                VK_ACCESS_SHADER_READ_BIT);
+    render_pass->add(dependency);
+
+    dependency = make_subpass_dependency(VK_SUBPASS_EXTERNAL, 0);
+    dependency->set_stage_mask(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+    dependency->set_access_mask(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
+    render_pass->add(dependency);
+
+    dependency = make_subpass_dependency(0, VK_SUBPASS_EXTERNAL);
+    dependency->set_stage_mask(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+    dependency->set_access_mask(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
+    render_pass->add(dependency);
+
+    rect area = { glm::vec2(0.0f, 0.0f), get_headset()->get_resolution() };
+    VkImageViews views {
+        color_layers_->get_view(),
+        depth_stencil_layers_[render_pass_index]->get_view(),
+    };
+    render_pass->create({ views }, area);
+
+    pipeline->create(render_pass->get());
+    render_pass->add_front(pipeline);
+
+    return render_pass;
+}
+
+bool DepthPeelingReprojectionStereo::create_reprojection_render_pass() {
+    reprojection_mesh_ = make_mesh();
+    int blocks_x = 1024 / 64;
+    int blocks_y = 1024 / 64;
+
+    std::vector<lava::vertex> vertices((blocks_x + 1) * (blocks_y + 1));
+    for (int y = 0; y < blocks_y + 1; ++y) {
+        for (int x = 0; x < blocks_x + 1; ++x) {
+            auto& vertex = vertices[y * (blocks_x + 1) + x];
+            vertex.position.x = x / static_cast<float>(blocks_x);
+            vertex.position.y = y / static_cast<float>(blocks_y);
+            vertex.position.z = 0.0f;
+        }
+    }
+    std::vector<lava::index> indices;
+    indices.reserve(blocks_x * blocks_y * 4);
+    for (int y = 0; y < blocks_y; ++y) {
+        for (int x = 0; x < blocks_x; ++x) {
+            indices.push_back(y * (blocks_x + 1) + x);
+            indices.push_back((y + 1) * (blocks_x + 1) + x);
+            indices.push_back((y + 1) * (blocks_x + 1) + x + 1);
+            indices.push_back(y * (blocks_x + 1) + x + 1);
+        }
+    }
+    reprojection_mesh_->get_vertices() = vertices;
+    reprojection_mesh_->get_indices() = indices;
+
+    if (!reprojection_mesh_->create(get_device())) {
+        log()->error("Failed to create mesh");
+        return false;
+    }
+    reprojection_pipeline_ = make_graphics_pipeline(get_device());
+
+    if (!reprojection_pipeline_->add_shader(file_data("dpr/binary/dpr_reproject_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) {
+        return false;
+    }
+
+    if (!reprojection_pipeline_->add_shader(file_data("dpr/binary/dpr_reproject_tesselation_control.spirv"), VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)) {
+        return false;
+    }
+
+    if (!reprojection_pipeline_->add_shader(file_data("dpr/binary/dpr_reproject_tesselation_evaluation.spirv"), VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
+        return false;
+    }
+
+    if (!reprojection_pipeline_->add_shader(file_data("dpr/binary/dpr_reproject_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) {
+        return false;
+    }
+    reprojection_pipeline_->set_tesselation_patch_control_points(4);
+    reprojection_pipeline_->set_input_assembly_topology(VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
+
+    const VkPipelineColorBlendAttachmentState blend_state = {
+        .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+    };
+    reprojection_pipeline_->set_depth_test_and_write(false, false);
+    reprojection_pipeline_->add_color_blend_attachment(blend_state);
+
+    reprojection_pipeline_->set_vertex_input_binding({ 0, sizeof(vertex), VK_VERTEX_INPUT_RATE_VERTEX });
+    reprojection_pipeline_->set_vertex_input_attributes({
+        { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, to_ui32(offsetof(vertex, position)) },
+        { 1, 0, VK_FORMAT_R32G32_SFLOAT, to_ui32(offsetof(vertex, uv)) },
+    });
+    // reprojection_pipeline_->set_rasterization_polygon_mode(VK_POLYGON_MODE_LINE);
+
+    params.left_to_right_eye = glm::mat4(1.0f);
+    params.discard_threshold = 0.0001;
+    params.tesselation_level = 16.0f;
+    params.z_min = 0.0;
+    params.z_max = 0.99987784;
+
+    reproject_ubo_.resize(get_application()->get_frame_count());
+
+    for (auto& buffer : reproject_ubo_) {
+        buffer = make_buffer();
+        
+        if (!buffer->create_mapped(get_device(), &params, sizeof(glsl::DprParameters), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) {
+            return {};
+        }
+    }
+
+    VkDescriptorImageInfo left_depth_buffers[2];
+    left_depth_buffers[0].sampler = sampler;
+    left_depth_buffers[0].imageView = depth_stencil_layers_[0]->get_view();
+    left_depth_buffers[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    left_depth_buffers[1].sampler = sampler;
+    left_depth_buffers[1].imageView = depth_stencil_layers_[1]->get_view();
+    left_depth_buffers[1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+    VkDescriptorImageInfo color_layers;
+    color_layers.sampler = sampler;
+    color_layers.imageView = color_layers_->get_view();
+    color_layers.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+    for (uint32_t eye = 0; eye < 2; eye++) {
+        auto& descriptor_set_list = reprojection_pipeline_descriptor_set_[eye];
+        descriptor_set_list.resize(get_application()->get_frame_count());
+
+        for (uint32_t frame = 0; frame < get_application()->get_frame_count(); frame++) {
+            descriptor_set_list[frame] = reprojection_pipeline_descriptor_->allocate_set(descriptor_pool_->get());
+            
+            get_device()->vkUpdateDescriptorSets({
+                {
+                    .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+                    .dstSet = descriptor_set_list[frame],
+                    .dstBinding = 0,
+                    .descriptorCount = 1,
+                    .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+                    .pBufferInfo = reproject_ubo_[frame]->get_descriptor_info(),
+                },
+                { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+                  .dstSet = descriptor_set_list[frame],
+                  .dstBinding = 1,
+                  .descriptorCount = 1,
+                  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                  .pImageInfo = &left_depth_buffers[eye]
+                },
+                { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+                  .dstSet = descriptor_set_list[frame],
+                  .dstBinding = 2,
+                  .descriptorCount = 1,
+                  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                  .pImageInfo = &color_layers
+                },
+            });
+        }
+    }
+
+    reprojection_pipeline_layout_ = make_pipeline_layout();
+    reprojection_pipeline_layout_->add(reprojection_pipeline_descriptor_);
+    if (!reprojection_pipeline_layout_ ->create(get_device())) {
+        return false;
+    }
+
+    reprojection_render_pass_ = make_render_pass(get_device());
+    reprojection_render_pass_->set_clear_color();
+
+    subpass::ptr subpass = make_subpass();
+
+    VkAttachmentReference color_attachment {
+        .attachment = 0,
+        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+    };
+    subpass->set_color_attachment(color_attachment);
+
+    reprojection_render_pass_->add(this->color_attachment);
+    reprojection_render_pass_->add(subpass);
+
+    reprojection_pipeline_->on_process = [this](VkCommandBuffer command_buffer) {
+        reprojection_pipeline_layout_->bind(command_buffer, reprojection_pipeline_descriptor_set_[current_render_pass_][get_application()->get_frame_index()], 0);
+        switch (layers_to_draw_) {
+          case 0b01:
+            reprojection_mesh_->bind_draw(command_buffer, 1, 1);
+            break;
+
+          case 0b10:
+            reprojection_mesh_->bind_draw(command_buffer, 1, 0);
+            break;
+
+          case 0b11:
+            reprojection_mesh_->bind_draw(command_buffer, 2);
+            break;
+        }
+    };
+    reprojection_pipeline_->set_layout(reprojection_pipeline_layout_);
+
+    subpass_dependency::ptr dependency = make_subpass_dependency(VK_SUBPASS_EXTERNAL, 0);
+    // wait for previous fragment shader to finish reading before clearing attachments
+    dependency->set_stage_mask(
+        VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT);
+    // we need a memory barrier because this isn't a standard write-after-read hazard
+    // subpass deps have an implicit attachment layout transition, so the dst access mask must be correct
+    dependency->set_access_mask(0,
+                                VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
+    reprojection_render_pass_->add(dependency);
+
+    dependency = make_subpass_dependency(reprojection_render_pass_->get_subpass_count() - 1, VK_SUBPASS_EXTERNAL);
+    // don't run any fragment shader (sample attachments) before we're done writing to attachments
+    dependency->set_stage_mask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
+                               VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+    // make attachment writes visible to subsequent reads
+    dependency->set_access_mask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+                                VK_ACCESS_SHADER_READ_BIT);
+    reprojection_render_pass_->add(dependency);
+
+    rect area = { glm::vec2(0.0f, 0.0f), get_headset()->get_resolution()};
+    VkImageViews views {
+        get_headset()->get_framebuffer(EYE_RIGHT)->get_view(),
+    };
+    if (!reprojection_render_pass_->create({ views }, area)) {
+      return false;
+    }
+
+    reprojection_pipeline_->create(reprojection_render_pass_->get());
+    reprojection_render_pass_->add_front(reprojection_pipeline_);
+
+    return true;
+}
+
+bool DepthPeelingReprojectionStereo::setup_companion_window_pipeline() {
+    // companion_window_pipeline_ = make_graphics_pipeline(app()->device());
+
+    // if (!companion_window_pipeline_->add_shader(file_data("dpr/binary/dpr_companion_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) {
+    //     return false;
+    // }
+
+    // if (!companion_window_pipeline_->add_shader(file_data("dpr/binary/dpr_companion_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) {
+    //     return false;
+    // }
+
+    // companion_window_pipeline_->add_color_blend_attachment();
+
+    // companion_window_pipeline_->set_vertex_input_binding({ 0, sizeof(vertex), VK_VERTEX_INPUT_RATE_VERTEX });
+    // companion_window_pipeline_->set_vertex_input_attributes({
+    //     { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, to_ui32(offsetof(vertex, position)) },
+    //     { 1, 0, VK_FORMAT_R32G32_SFLOAT, to_ui32(offsetof(vertex, uv)) },
+    // });
+
+    // companion_window_pipeline_descriptor_ = make_descriptor();
+    // companion_window_pipeline_descriptor_->add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
+    // companion_window_pipeline_descriptor_->add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
+    // if (!companion_window_pipeline_descriptor_->create(app()->device())) {
+    //     return false;
+    // }
+
+    // companion_window_pipeline_layout_ = make_pipeline_layout();
+    // companion_window_pipeline_layout_->add(companion_window_pipeline_descriptor_);
+    // if (!companion_window_pipeline_layout_ ->create(app()->device())) {
+    //     return false;
+    // }
+
+    // companion_window_pipeline_descriptor_set_ = companion_window_pipeline_descriptor_->allocate(descriptor_pool_->get());
+
+    // VkSamplerCreateInfo const sampler_info = {
+    //     .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+    //     .magFilter = VK_FILTER_NEAREST,
+    //     .minFilter = VK_FILTER_NEAREST,
+    //     .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST
+    // };
+    // if (!device()->vkCreateSampler(&sampler_info, &sampler)) {
+    //     return false;
+    // }
+    
+    // VkDescriptorImageInfo left_eye_image_descriptor_info = {
+    //     .sampler = sampler,
+    //     .imageView = framebuffers_[0]->color_image->get_view(),
+    //     .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+    // };
+    // VkDescriptorImageInfo right_eye_image_descriptor_info = {
+    //     .sampler = sampler,
+    //     .imageView = framebuffers_[1]->color_image->get_view(),
+    //     .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+    // };
+
+    // VkWriteDescriptorSet const write_desc_left_eye {
+    //     .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+    //     .dstSet = companion_window_pipeline_descriptor_set_,
+    //     .dstBinding = 0,
+    //     .descriptorCount = 1,
+    //     .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+    //     .pImageInfo = &left_eye_image_descriptor_info,
+    // };
+
+    // VkWriteDescriptorSet const write_desc_right_eye {
+    //     .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+    //     .dstSet = companion_window_pipeline_descriptor_set_,
+    //     .dstBinding = 1,
+    //     .descriptorCount = 1,
+    //     .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+    //     .pImageInfo = &right_eye_image_descriptor_info,
+    // };
+
+    // app()->device()->vkUpdateDescriptorSets({ write_desc_left_eye, write_desc_right_eye });
+
+    // companion_window_pipeline_->on_process = [this](VkCommandBuffer command_buffer) {
+    //     companion_window_pipeline_layout_->bind(command_buffer, companion_window_pipeline_descriptor_set_);
+    //     quad_mesh_->bind_draw(command_buffer);
+    // };
+
+    // companion_window_pipeline_->set_layout(companion_window_pipeline_layout_);
+    // companion_window_pipeline_->create(app()->shading.get_pass()->get());
+    // app()->shading.get_pass()->add_front(companion_window_pipeline_);
+
+    // app()->add_run_end([this]() {
+    //     companion_window_pipeline_descriptor_->free(companion_window_pipeline_descriptor_set_, descriptor_pool_->get());
+    //     descriptor_pool_->destroy();
+    //     companion_window_pipeline_descriptor_->destroy();
+    //     companion_window_pipeline_->destroy();
+    //     companion_window_pipeline_layout_->destroy();
+    //     for (auto& strategy : stereo_strategies_) {
+    //       strategy.reset();
+    //     }
+    //     device()->vkDestroySampler(sampler);
+    // });
+
+    return true;
+}
\ No newline at end of file
diff --git a/src/strategy/depth_peeling_reprojection_stereo.hpp b/src/strategy/depth_peeling_reprojection_stereo.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..56faa93a2950c25be8ee928c7a332d2c4d63158d
--- /dev/null
+++ b/src/strategy/depth_peeling_reprojection_stereo.hpp
@@ -0,0 +1,88 @@
+#pragma once
+#include <memory>
+
+#include "stereo_strategy.hpp"
+
+namespace glsl {
+using namespace glm;
+#include "res/dpr/strategy/depth_peeling_reprojection/dpr_parameters.inc"
+}
+
+class DepthPeelingReprojectionStereo final : public StereoStrategy {
+public:
+    typedef std::shared_ptr<DepthPeelingReprojectionStereo> Ptr;
+
+public:
+    DepthPeelingReprojectionStereo();
+    void destructor();
+
+    bool create();
+    void render(VkCommandBuffer command_buffer, lava::index frame);
+    void render_companion_window(VkCommandBuffer command_buffer);
+    void update();
+    void write_buffer(lava::index frame);
+    void draw_imgui();
+
+    //---------------------------------------------------------------------------------------------------
+    // Virtual functions introduced by the new software architecture.
+    
+    bool on_create() override;
+    void on_destroy() override;
+
+    bool on_interface() override;
+    bool on_update(lava::delta delta_time) override;
+    bool on_render(VkCommandBuffer command_buffer, lava::index frame) override;
+
+    uint32_t get_max_remote_frame_ids() const override;
+    const char* get_name() const override;
+
+    //---------------------------------------------------------------------------------------------------
+    // Moved objects
+
+    VkSampler sampler = VK_NULL_HANDLE;         //Moved from vr_app to strategy
+    lava::attachment::ptr color_attachment;     //Moved from stereo_framebuffer to strategy
+
+    //---------------------------------------------------------------------------------------------------
+
+private:
+    lava::uv2 framebuffer_size_;
+    lava::pipeline_layout::ptr pipeline_layout_;
+    lava::render_pass::ptr render_passes_[2];
+    VkDescriptorSet descriptor_sets_[2];
+    lava::index current_render_pass_;
+    lava::descriptor::ptr descriptor_;
+    lava::descriptor::pool::ptr descriptor_pool_;
+
+    lava::image_array::ptr color_layers_;
+    lava::attachment::ptr color_layers_attachment_;
+
+    lava::image_array::ptr depth_stencil_layers_[2];
+    lava::attachment::ptr depth_stencil_layers_attachment_[2];
+
+    lava::image::ptr second_layer_image_;
+    lava::attachment::ptr second_layer_attachment_;
+
+    lava::render_pass::ptr create_render_pass(lava::index render_pass_index);
+
+    lava::mesh::ptr reprojection_mesh_;
+    lava::graphics_pipeline::ptr reprojection_pipeline_;
+    lava::pipeline_layout::ptr reprojection_pipeline_layout_;
+    lava::descriptor::ptr reprojection_pipeline_descriptor_;
+    std::vector<VkDescriptorSet> reprojection_pipeline_descriptor_set_[2];
+    lava::render_pass::ptr reprojection_render_pass_;
+    glsl::DprParameters params;
+    std::vector<lava::buffer::ptr> reproject_ubo_;
+    bool create_reprojection_render_pass();
+
+    lava::mesh::ptr quad_mesh_;
+    lava::graphics_pipeline::ptr companion_window_pipeline_;
+    lava::pipeline_layout::ptr companion_window_pipeline_layout_;
+    lava::descriptor::ptr companion_window_pipeline_descriptor_;
+    VkDescriptorSet companion_window_pipeline_descriptor_set_ = nullptr;
+
+    bool setup_companion_window_pipeline();
+
+    uint32_t layers_to_draw_ = 0b01 | 0b10;
+};
+
+DepthPeelingReprojectionStereo::Ptr make_depth_peeling_reprojection_stereo();
\ No newline at end of file
diff --git a/src/strategy/multi_view_stereo.cpp b/src/strategy/multi_view_stereo.cpp
index 4442b70f4eabe80766eee0d521d0ce422809b2f1..b76e3cac147880251e1dc4dbece269d0b49f6182 100644
--- a/src/strategy/multi_view_stereo.cpp
+++ b/src/strategy/multi_view_stereo.cpp
@@ -248,14 +248,14 @@ bool MultiViewStereo::create_pipeline()
 
     Scene::set_vertex_input(this->pipeline.get());
 
-    if (!this->pipeline->add_shader(lava::file_data("shaders/binary/multi_view_stereo_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!this->pipeline->add_shader(lava::file_data("dpr/binary/multi_view_stereo_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         lava::log()->error("Can't load vertex shader for multi-view stereo!");
 
         return false;
     }
 
-    if (!this->pipeline->add_shader(lava::file_data("shaders/binary/multi_view_stereo_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    if (!this->pipeline->add_shader(lava::file_data("dpr/binary/multi_view_stereo_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         lava::log()->error("Can't load fragment shader for multi-view stereo!");
 
diff --git a/src/strategy/native_stereo_deferred.cpp b/src/strategy/native_stereo_deferred.cpp
index 3cafbc2c1f66f5eb86475c5f2829959dc621db62..37be5aa60c0d1ea2c4b61a8f2722a1500250b041 100644
--- a/src/strategy/native_stereo_deferred.cpp
+++ b/src/strategy/native_stereo_deferred.cpp
@@ -229,14 +229,14 @@ bool NativeStereoDeferred::create_pipeline(Eye eye)
 
     Scene::set_vertex_input(pipeline.get());
 
-    if (!pipeline->add_shader(lava::file_data("shaders/binary/native_stereo_deferred_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!pipeline->add_shader(lava::file_data("dpr/binary/native_stereo_deferred_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         lava::log()->error("Can't load vertex shader for native stereo deferred!");
 
         return false;
     }
 
-    if (!pipeline->add_shader(lava::file_data("shaders/binary/native_stereo_deferred_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    if (!pipeline->add_shader(lava::file_data("dpr/binary/native_stereo_deferred_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         lava::log()->error("Can't load fragment shader for native stereo deferred!");
 
diff --git a/src/strategy/native_stereo_forward.cpp b/src/strategy/native_stereo_forward.cpp
index e86920c451a479d75516006f0560b5f3c3807513..bbe14e4ed302bf212671ec3bbfea836ac518e82b 100644
--- a/src/strategy/native_stereo_forward.cpp
+++ b/src/strategy/native_stereo_forward.cpp
@@ -234,14 +234,14 @@ bool NativeStereoForward::create_pipeline(Eye eye)
 
     Scene::set_vertex_input(pipeline.get());
 
-    if (!pipeline->add_shader(lava::file_data("shaders/binary/native_stereo_forward_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!pipeline->add_shader(lava::file_data("dpr/binary/native_stereo_forward_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         lava::log()->error("Can't load vertex shader for native stereo forward!");
 
         return false;
     }
 
-    if (!pipeline->add_shader(lava::file_data("shaders/binary/native_stereo_forward_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    if (!pipeline->add_shader(lava::file_data("dpr/binary/native_stereo_forward_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         lava::log()->error("Can't load fragment shader for native stereo forward!");
 
diff --git a/src/strategy/stereo_strategy.cpp b/src/strategy/stereo_strategy.cpp
index 02895ab567491ff58f1c2c5e009de173aa00ea90..eb359580ddcbc0d0938a68a82b28c4acaeabfb79 100644
--- a/src/strategy/stereo_strategy.cpp
+++ b/src/strategy/stereo_strategy.cpp
@@ -2,6 +2,7 @@
 #include "native_stereo_forward.hpp"
 #include "native_stereo_deferred.hpp"
 #include "multi_view_stereo.hpp"
+#include "depth_peeling_reprojection_stereo.hpp"
 
 #include "vr_application.hpp"
 
@@ -75,6 +76,9 @@ StereoStrategy::Ptr make_stereo_strategy(VRApplication* application, StereoStrat
     case STEREO_STRATEGY_TYPE_MULTI_VIEW:
         strategy = make_multi_view_stereo();
         break;
+    case STEREO_STRATEGY_TYPE_DEPTH_PEELING_REPROJECTION:
+        strategy = make_depth_peeling_reprojection_stereo();
+        break;
     default:
         lava::log()->error("Unkown strategy type!");
         return nullptr;
@@ -91,6 +95,7 @@ std::vector<StereoStrategy::Ptr> make_all_stereo_strategies(VRApplication* appli
     strategies.push_back(make_native_stereo_forward());
     strategies.push_back(make_native_stereo_deferred());
     strategies.push_back(make_multi_view_stereo());
+    strategies.push_back(make_depth_peeling_reprojection_stereo());
 
     for (StereoStrategy::Ptr strategy : strategies)
     {
diff --git a/src/strategy/stereo_strategy.hpp b/src/strategy/stereo_strategy.hpp
index 4b0f3bdbbc3d89437d8cc3047280612fbe73b73f..2f565c26afde0fbaceb64fd53a3c66639f6ad988 100644
--- a/src/strategy/stereo_strategy.hpp
+++ b/src/strategy/stereo_strategy.hpp
@@ -29,7 +29,8 @@ enum StereoStrategyType
 {
     STEREO_STRATEGY_TYPE_NATIVE_FORWARD,
     STEREO_STRATEGY_TYPE_NATIVE_DEFERRED,
-    STEREO_STRATEGY_TYPE_MULTI_VIEW
+    STEREO_STRATEGY_TYPE_MULTI_VIEW,
+    STEREO_STRATEGY_TYPE_DEPTH_PEELING_REPROJECTION
 };
 
 class StereoStrategy
diff --git a/src/utility/command_parser.cpp b/src/utility/command_parser.cpp
index f38b57c93d793657217b87b170e0c72f0ce42213..7face99e7d314b897cbc2f20175d51b17f0d49ba 100644
--- a/src/utility/command_parser.cpp
+++ b/src/utility/command_parser.cpp
@@ -297,7 +297,7 @@ bool CommandParser::should_write_frames() const
 void CommandParser::show_help()
 {
     std::cout << "Usage:" << std::endl;
-    std::cout << "   multi-layer-reprojection.exe [Options] [Scene File]" << std::endl;
+    std::cout << "   depth-peeling-reprojection.exe [Options] [Scene File]" << std::endl;
     std::cout << std::endl;
     std::cout << "Options:" << std::endl;
     std::cout << "   --sky-sphere={file}                  The sky sphere that should be shown. The given file has to be a .hdr file." << std::endl;
@@ -380,6 +380,11 @@ bool CommandParser::set_stero_strategy(const std::string& name)
         this->stereo_strategy = STEREO_STRATEGY_TYPE_MULTI_VIEW;
     }
 
+    else if (name == "dpr")
+    {
+        this->stereo_strategy = STEREO_STRATEGY_TYPE_DEPTH_PEELING_REPROJECTION;
+    }
+
     else
     {
         std::cout << "Invalid option set for parameter 'stereo-strategy'. Use option --help to get more information." << std::endl;
diff --git a/src/utility/geometry_buffer.cpp b/src/utility/geometry_buffer.cpp
index ddb6b61c4b585128ec65aaa21f4bd07070e630e4..27ff69206ced121be6a6f4d0eadbfdc4d893bfb7 100644
--- a/src/utility/geometry_buffer.cpp
+++ b/src/utility/geometry_buffer.cpp
@@ -510,14 +510,14 @@ bool GeometryBuffer::create_pipeline(lava::device_ptr device, lava::descriptor::
     this->pipeline->set_input_assembly_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
     this->pipeline->add_color_blend_attachment(output_blend_state);
 
-    if (!this->pipeline->add_shader(lava::file_data("shaders/binary/deferred_lighting_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!this->pipeline->add_shader(lava::file_data("dpr/binary/deferred_lighting_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         lava::log()->error("Can't load vertex shader for deferred lighting pass!");
 
         return false;
     }
 
-    std::string shader_name = "shaders/binary/deferred_lighting";
+    std::string shader_name = "dpr/binary/deferred_lighting";
 
     if (this->indirect_cache != nullptr)
     {
diff --git a/src/utility/indirect_cache.cpp b/src/utility/indirect_cache.cpp
index 04afc2f36263452cbb52b6f5be3d733e70977aa3..37205c4990c55d427faccbe18acdbc2bdbc485ca 100644
--- a/src/utility/indirect_cache.cpp
+++ b/src/utility/indirect_cache.cpp
@@ -5,7 +5,7 @@ namespace glsl
     using namespace glm;
     using uint = glm::uint32;
 
-#include "res/shaders/data/indirect_data.inc"
+#include "res/dpr/data/indirect_data.inc"
 }
 
 bool IndirectCache::create(Scene::Ptr scene, const IndirectCacheSettings& settings)
@@ -1140,17 +1140,17 @@ bool IndirectCache::create_geometry_pipeline(lava::device_ptr device)
 
     scene->set_vertex_input(this->geometry_pipeline.get());
 
-    if (!this->geometry_pipeline->add_shader(lava::file_data("shaders/binary/indirect_geometry_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!this->geometry_pipeline->add_shader(lava::file_data("dpr/binary/indirect_geometry_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         return false;
     }
 
-    if (!this->geometry_pipeline->add_shader(lava::file_data("shaders/binary/indirect_geometry_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT))
+    if (!this->geometry_pipeline->add_shader(lava::file_data("dpr/binary/indirect_geometry_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT))
     {
         return false;
     }
 
-    if (!this->geometry_pipeline->add_shader(lava::file_data("shaders/binary/indirect_geometry_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    if (!this->geometry_pipeline->add_shader(lava::file_data("dpr/binary/indirect_geometry_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         return false;
     }
@@ -1281,12 +1281,12 @@ bool IndirectCache::create_capture_pipeline(lava::device_ptr device)
 
     scene->set_vertex_input(this->capture_pipeline.get());
 
-    if (!this->capture_pipeline->add_shader(lava::file_data("shaders/binary/indirect_capture_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!this->capture_pipeline->add_shader(lava::file_data("dpr/binary/indirect_capture_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         return false;
     }
 
-    if (!this->capture_pipeline->add_shader(lava::file_data("shaders/binary/indirect_capture_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    if (!this->capture_pipeline->add_shader(lava::file_data("dpr/binary/indirect_capture_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         return false;
     }
@@ -1402,17 +1402,17 @@ bool IndirectCache::create_injection_pipeline(lava::device_ptr device)
     this->injection_pipeline->add_color_blend_attachment(blend_state);
     this->injection_pipeline->add_color_blend_attachment(blend_state);
 
-    if (!this->injection_pipeline->add_shader(lava::file_data("shaders/binary/indirect_injection_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!this->injection_pipeline->add_shader(lava::file_data("dpr/binary/indirect_injection_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         return false;
     }
 
-    if (!this->injection_pipeline->add_shader(lava::file_data("shaders/binary/indirect_injection_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT))
+    if (!this->injection_pipeline->add_shader(lava::file_data("dpr/binary/indirect_injection_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT))
     {
         return false;
     }
 
-    if (!this->injection_pipeline->add_shader(lava::file_data("shaders/binary/indirect_injection_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
+    if (!this->injection_pipeline->add_shader(lava::file_data("dpr/binary/indirect_injection_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT))
     {
         return false;
     }
@@ -1437,7 +1437,7 @@ bool IndirectCache::create_propagation_pipeline(lava::device_ptr device)
     this->propagation_pipeline = lava::make_compute_pipeline(device);
     this->propagation_pipeline->set_layout(this->propagation_layout);
     
-    if (!this->propagation_pipeline->set_shader_stage(lava::file_data("shaders/binary/indirect_propagation_compute.spirv"), VK_SHADER_STAGE_COMPUTE_BIT))
+    if (!this->propagation_pipeline->set_shader_stage(lava::file_data("dpr/binary/indirect_propagation_compute.spirv"), VK_SHADER_STAGE_COMPUTE_BIT))
     {
         return false;
     }
diff --git a/src/utility/shadow_cache.cpp b/src/utility/shadow_cache.cpp
index 240f4b628602c0fd4b710d8abe4e390ff843a1b0..e8b6df8657fa9bf4054537fe566d2b6df5ecae4a 100644
--- a/src/utility/shadow_cache.cpp
+++ b/src/utility/shadow_cache.cpp
@@ -5,7 +5,7 @@ namespace glsl
     using namespace glm;
     using uint = glm::uint32;
 
-#include "res/shaders/data/shadow_data.inc"
+#include "res/dpr/data/shadow_data.inc"
 }
 
 bool ShadowCache::create(Scene::Ptr scene, const ShadowCacheSettings& settings)
@@ -577,12 +577,12 @@ bool ShadowCache::create_pipeline(lava::device_ptr device, Scene::Ptr scene)
 
     scene->set_vertex_input_only_position(this->pipeline.get());
 
-    if (!this->pipeline->add_shader(lava::file_data("shaders/binary/shadow_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
+    if (!this->pipeline->add_shader(lava::file_data("dpr/binary/shadow_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT))
     {
         return false;
     }
 
-    if (!this->pipeline->add_shader(lava::file_data("shaders/binary/shadow_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT))
+    if (!this->pipeline->add_shader(lava::file_data("dpr/binary/shadow_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT))
     {
         return false;
     }
diff --git a/src/utility/stereo_transform.hpp b/src/utility/stereo_transform.hpp
index 6dce49c15b31317c4f8495c043a36467cf47046b..37b2d35451e78a8488fdbf0c147e137fd619a176 100644
--- a/src/utility/stereo_transform.hpp
+++ b/src/utility/stereo_transform.hpp
@@ -22,7 +22,7 @@ class VRApplication;
 namespace glsl
 {
 using namespace glm;
-#include "res/shaders/data/per_frame.inc"
+#include "res/dpr/data/per_frame.inc"
 }
 
 class StereoTransform
diff --git a/src/vr_application.cpp b/src/vr_application.cpp
index b263ea31b660e10a276dd8add448cd90c78b1fcd..e8390490848dfdca4ed66889b22dc5c530e938fc 100644
--- a/src/vr_application.cpp
+++ b/src/vr_application.cpp
@@ -323,10 +323,10 @@ bool VRApplication::on_create()
 
     if (!this->command_parser.should_benchmark())
     {
-        config.controller_left_file = std::string(RESOURCE_FOLDER) + "/controllers/ObjModelViveFocus3ControllerLeft.fbx";
+        config.controller_left_file = std::string(RESOURCE_FOLDER) + "/dpr-controller/ObjModelViveFocus3ControllerLeft.fbx";
         config.controller_left_unit = SCENE_UNIT_CENTIMETERS;
 
-        config.controller_right_file = std::string(RESOURCE_FOLDER) + "/controllers/ObjModelViveFocus3ControllerRight.fbx";
+        config.controller_right_file = std::string(RESOURCE_FOLDER) + "/dpr-controller/ObjModelViveFocus3ControllerRight.fbx";
         config.controller_right_unit = SCENE_UNIT_CENTIMETERS;
     }