diff --git a/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_base.glsl b/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_base.glsl
index a94953cb599eec74fbe33dfabebef2cb3e334cb0..a75866520fe1488b03062ed4212a276336a06ba3 100644
--- a/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_base.glsl
+++ b/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_base.glsl
@@ -61,7 +61,7 @@ void main()
 {
     if(parameters.layer == 1)
     {
-        float first_layer_depth = texelFetch(sampler_layer_depth, ivec2(gl_FragCoord.xy), 0).x;
+        float first_layer_depth = texelFetch(sampler_layer_depth, ivec2(gl_FragCoord.xy + vec2(parameters.depth_offset, 0.0)), 0).x;
         float first_layer_linear_depth = linear_depth(frame.projection, first_layer_depth);
 
         float current_depth = gl_FragCoord.z;
@@ -85,5 +85,5 @@ void main()
     vec3 lighting = apply_lighting(frame.eyePosition, inPos, normal, material);
 
     outColor = vec4(lighting, 1.0);
-    outEncodedDepth = vec4(encode_depth(gl_FragCoord.z), 0);
+    outEncodedDepth = vec4(encode_depth(gl_FragCoord.z), 1.0);
 }
diff --git a/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_parameters.inc b/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_parameters.inc
index 61f267acf6721df2a7d89513da4e96df871c8602..6e8df0a98c8838d264cc41e78e0bce7adf14faf7 100644
--- a/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_parameters.inc
+++ b/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_parameters.inc
@@ -4,6 +4,7 @@
 struct DualLayerReprojectionParameters
 {
     uint layer;
+    float depth_offset;
     float constant_threshold;
     float slope_threshold;
 };
diff --git a/src/encoder/encoder.cpp b/src/encoder/encoder.cpp
index 99f7d1aa3c0c27336a330f40247cb321a296534f..96a83dc2e1108fb83e86c9c08712052e1edea643 100644
--- a/src/encoder/encoder.cpp
+++ b/src/encoder/encoder.cpp
@@ -89,6 +89,30 @@ bool setup_device_for_encoder(EncoderType encoder_type, lava::instance& instance
     return false;
 }
 
+bool compute_encoder_resolution(EncoderType encoder_type, EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution)
+{
+    switch(encoder_type)
+    {
+    case ENCODER_TYPE_VULKAN:
+        if (!compute_vulkan_encoder_resolution(encoder_codec, image_resolution, encoder_resolution))
+        {
+            return false;
+        }
+        break;
+    case ENCODER_TYPE_NVIDIA:
+        if (!compute_nvidia_encoder_resolution(encoder_codec, image_resolution, encoder_resolution))
+        {
+            return false;
+        }
+        break;
+    default:
+        lava::log()->error("Unkown encoder type!");
+        return false;
+    }
+
+    return true;
+}
+
 bool shutdown_encoder(EncoderType encoder_type)
 {
     switch (encoder_type)
diff --git a/src/encoder/encoder.hpp b/src/encoder/encoder.hpp
index 7afa7c00bac0cde6b5c9c91f3b2431e7b1b03b6a..0da903654476969b7c7e96ac04a4c9c0d3c4578d 100644
--- a/src/encoder/encoder.hpp
+++ b/src/encoder/encoder.hpp
@@ -128,6 +128,8 @@ public:
 bool setup_instance_for_encoder(EncoderType encoder_type, lava::frame_config& config);
 bool setup_device_for_encoder(EncoderType encoder_type, lava::instance& instance, lava::device::create_param& parameters);
 
+bool compute_encoder_resolution(EncoderType encoder_type, EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution);
+
 bool shutdown_encoder(EncoderType encoder_type);
 
 Encoder::Ptr make_encoder(EncoderType encoder_type);
\ No newline at end of file
diff --git a/src/encoder/nvidia_encoder.cpp b/src/encoder/nvidia_encoder.cpp
index f75b02024c6b4ec528c8cd65522e89933fd66e86..dad440ae3efd9f78abc5c3bea86cd80662407c08 100644
--- a/src/encoder/nvidia_encoder.cpp
+++ b/src/encoder/nvidia_encoder.cpp
@@ -1518,6 +1518,29 @@ bool setup_device_for_nvidia_encoder(lava::instance& instance, lava::device::cre
     return true;
 }
 
+bool compute_nvidia_encoder_resolution(EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution)
+{
+    if (encoder_codec == ENCODER_CODEC_H264)
+    {
+        const glm::uvec2 block_size = glm::uvec2(16); //H264 macroblock size of 16x16
+        encoder_resolution = glm::uvec2(glm::ceil(glm::vec2(image_resolution) / glm::vec2(block_size))) * block_size;
+    }
+
+    else if (encoder_codec == ENCODER_CODEC_H265)
+    {
+        encoder_resolution = image_resolution;
+    }
+
+    else
+    {
+        lava::log()->error("Nvidia Encoder: Invalid codec!");
+
+        return false;
+    }
+    
+    return true;
+}
+
 void shutdown_nvidia_encoder()
 {
     unload_library();
diff --git a/src/encoder/nvidia_encoder.hpp b/src/encoder/nvidia_encoder.hpp
index ceb40737b0d68300fd794e7a923864acd3843149..44feecf9a8ee2a80b2321b5bf99187f18ef1f374 100644
--- a/src/encoder/nvidia_encoder.hpp
+++ b/src/encoder/nvidia_encoder.hpp
@@ -127,4 +127,6 @@ private:
 bool setup_instance_for_nvidia_encoder(lava::frame_config& config);
 bool setup_device_for_nvidia_encoder(lava::instance& instance, lava::device::create_param& parameters);
 
+bool compute_nvidia_encoder_resolution(EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution);
+
 void shutdown_nvidia_encoder();
\ No newline at end of file
diff --git a/src/encoder/vulkan_encoder.cpp b/src/encoder/vulkan_encoder.cpp
index 36da40d2dc9ae8556940eca328f17c1565f8d4ba..2d271a84611c29fb94b9155a27f8ad9016c94f48 100644
--- a/src/encoder/vulkan_encoder.cpp
+++ b/src/encoder/vulkan_encoder.cpp
@@ -2459,6 +2459,21 @@ bool setup_device_for_vulkan_encoder(lava::instance& instance, lava::device::cre
     return true;
 }
 
+bool compute_vulkan_encoder_resolution(EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution)
+{
+    if (encoder_codec != ENCODER_CODEC_H264)
+    {
+        lava::log()->error("Vulkan encoder only supportes h264 encoding!");
+
+        return false;
+    }
+
+    const glm::uvec2 block_size = glm::uvec2(16); //H264 macroblock size of 16x16
+    encoder_resolution = glm::uvec2(glm::ceil(glm::vec2(image_resolution) / glm::vec2(block_size))) * block_size;
+
+    return true;
+}
+
 void shutdown_vulkan_encoder()
 {
 
diff --git a/src/encoder/vulkan_encoder.hpp b/src/encoder/vulkan_encoder.hpp
index 126af55968620fb6b191a60f25c2ec5aaec5a5a7..a899b4c67ea3f02c3de9235ccefaf0dd6d8e4809 100644
--- a/src/encoder/vulkan_encoder.hpp
+++ b/src/encoder/vulkan_encoder.hpp
@@ -222,4 +222,6 @@ private:
 bool setup_instance_for_vulkan_encoder(lava::frame_config& config);
 bool setup_device_for_vulkan_encoder(lava::instance& instance, lava::device::create_param& parameters);
 
+bool compute_vulkan_encoder_resolution(EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution);
+
 void shutdown_vulkan_encoder();
\ No newline at end of file
diff --git a/src/headset/remote_headset.cpp b/src/headset/remote_headset.cpp
index 88e55660eba7d65c6aaed11da6d0a2c53cd50a97..ded41085cd663959785da9c69ceed6361fbbfcb4 100644
--- a/src/headset/remote_headset.cpp
+++ b/src/headset/remote_headset.cpp
@@ -80,8 +80,7 @@ bool RemoteHeadset::on_create()
     }
 
     this->update_values();
-    this->framebuffer_resolution = strategy->get_remote_framebuffer_resolution(this->display_resolution);
-
+    
     if (!this->create_framebuffers())
     {
         lava::log()->error("Remote Headset: Can't create framebuffers!");
@@ -381,9 +380,9 @@ bool RemoteHeadset::create_transport()
 {
     this->transport = make_transport(this->get_application()->get_command_parser().get_transport());
 
-    this->transport->set_on_setup([this](const glm::u32vec2& resolution)
+    this->transport->set_on_setup([this](const glm::u32vec2& display_resolution)
     {
-        this->on_setup(resolution);
+        this->on_setup(display_resolution);
     });
     this->transport->set_on_projection_change([this](const glm::mat4& left_eye_projection, const glm::mat4& right_eye_projection, const glm::mat4& left_head_to_eye, const glm::mat4& right_head_to_eye)
     {
@@ -461,7 +460,11 @@ void RemoteHeadset::destroy_framebuffers()
 {
     for (lava::image::ptr& framebuffer : this->framebuffers)
     {
-        framebuffer->destroy(true);
+        if (framebuffer != nullptr)
+        {
+            framebuffer->destroy(true);
+            framebuffer = nullptr;
+        }
     }
 
     this->framebuffers.clear();
@@ -672,14 +675,26 @@ void RemoteHeadset::update_overlay()
     }
 }
 
-void RemoteHeadset::on_setup(const glm::u32vec2& resolution)
+void RemoteHeadset::on_setup(const glm::u32vec2& display_resolution)
 {
-    EncoderCodec codec = this->get_application()->get_command_parser().get_codec();
+    StereoStrategy::Ptr strategy = this->get_application()->get_stereo_strategy();
+    glm::uvec2 framebuffer_resolution = strategy->get_remote_framebuffer_resolution(display_resolution);
+
+    EncoderType encoder_type = this->get_application()->get_command_parser().get_encoder();
+    EncoderCodec encoder_codec = this->get_application()->get_command_parser().get_codec();
+    glm::uvec2 encode_resolution = glm::uvec2(0);
+
+    if (!compute_encoder_resolution(encoder_type, encoder_codec, framebuffer_resolution, encode_resolution))
+    {
+        return;
+    }
 
-    this->transport->send_setup_complete(this->remote_strategy, codec, this->frame_id_count, this->near_plane, this->far_plane);
+    this->transport->send_setup_complete(this->remote_strategy, this->frame_id_count, encoder_codec, encode_resolution, framebuffer_resolution, this->near_plane, this->far_plane);
 
     std::unique_lock<std::mutex> lock(this->transport_mutex);
-    this->display_resolution = resolution;
+    this->display_resolution = display_resolution;
+    this->framebuffer_resolution = framebuffer_resolution;
+    this->encode_resolution = encode_resolution;
     lock.unlock();
 }
 
diff --git a/src/headset/remote_headset.hpp b/src/headset/remote_headset.hpp
index 4a68edf7b606c203b5177799f5baa5fbd9ba971b..165e26c60c9c07f6183ccd0b81997ecaf3a9dc3d 100644
--- a/src/headset/remote_headset.hpp
+++ b/src/headset/remote_headset.hpp
@@ -62,7 +62,7 @@ private:
     void update_stage(lava::delta delta_time);
     void update_overlay();
 
-    void on_setup(const glm::u32vec2& resolution);
+    void on_setup(const glm::u32vec2& display_resolution);
     void on_projection_change(const glm::mat4& left_eye_projection, const glm::mat4& right_eye_projection, const glm::mat4& left_head_to_eye, const glm::mat4& right_head_to_eye);
     void on_head_transform(TransformId transform_id, const glm::mat4& head_transform);
     void on_controller_transform(Controller controller, const glm::mat4& controller_transform);
@@ -109,10 +109,11 @@ private:
     uint32_t frame_id_count = 0;
     uint32_t transform_id = 0;                                                              //NOTE: Protected by transport_mutex
 
-    glm::uvec2 framebuffer_resolution;
+    glm::uvec2 framebuffer_resolution;                                                      //NOTE: Protected by transport_mutex, but accessable after setup
     lava::image::ptr framebuffer_array;
     std::vector<lava::image::ptr> framebuffers;
 
+    glm::uvec2 encode_resolution;                                                           //NOTE: Protected by transport_mutex, but accessable after setup
     std::vector<Encoder::Ptr> encoders;
     std::vector<std::fstream> encoder_files;
     uint32_t encoder_mode = ENCODER_MODE_CONSTANT_BITRATE;
diff --git a/src/strategy/dual_layer_reprojection.cpp b/src/strategy/dual_layer_reprojection.cpp
index 5ca05a10e083cb3977122d3de36a7b0e4693d8c5..c6a13f9299e852e3bcd2bf6dfabe0d7fbbcc6d0d 100644
--- a/src/strategy/dual_layer_reprojection.cpp
+++ b/src/strategy/dual_layer_reprojection.cpp
@@ -93,14 +93,20 @@ void DualLayerReprojection::on_destroy()
 
     for (uint32_t index = 0; index < this->layer_depth_buffers.size(); index++)
     {
-        this->layer_depth_buffers[index]->destroy();
-        this->layer_depth_buffers[index] = nullptr;
+        if (this->layer_depth_buffers[index] != nullptr)
+        {
+            this->layer_depth_buffers[index]->destroy();
+            this->layer_depth_buffers[index] = nullptr;
+        }
     }
 
-    if (this->encoded_depth_buffer != nullptr)
+    for (uint32_t index = 0; index < this->encoded_depth_buffers.size(); index++)
     {
-        this->encoded_depth_buffer->destroy();
-        this->encoded_depth_buffer = nullptr;
+        if (this->encoded_depth_buffers[index] != nullptr)
+        {
+            this->encoded_depth_buffers[index]->destroy();
+            this->encoded_depth_buffers[index] = nullptr;
+        }
     }
 }
 
@@ -146,71 +152,65 @@ bool DualLayerReprojection::on_render(VkCommandBuffer command_buffer, lava::inde
 
     if (this->setup_layout)
     {
-        VkImageMemoryBarrier image_barrier;
-        image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-        image_barrier.pNext = nullptr;
-        image_barrier.srcAccessMask = 0;
-        image_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
-        image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-        image_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-        image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-        image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-        image_barrier.image = this->layer_depth_buffers[1]->get();
-        image_barrier.subresourceRange = this->layer_depth_buffers[1]->get_subresource_range();
+        VkImageMemoryBarrier depth_barrier;
+        depth_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+        depth_barrier.pNext = nullptr;
+        depth_barrier.srcAccessMask = 0;
+        depth_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+        depth_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        depth_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+        depth_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        depth_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        depth_barrier.image = this->layer_depth_buffers[1]->get();
+        depth_barrier.subresourceRange = this->layer_depth_buffers[1]->get_subresource_range();
+
+        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &depth_barrier);
+
+        if (!this->get_headset()->is_remote())
+        {
+            std::array<VkImageMemoryBarrier, 2> encoded_depth_barriers;
+
+            for (uint32_t index = 0; index < encoded_depth_barriers.size(); index++)
+            {
+                VkImageMemoryBarrier& encoded_depth_barrier = encoded_depth_barriers[index];
+                encoded_depth_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+                encoded_depth_barrier.pNext = nullptr;
+                encoded_depth_barrier.srcAccessMask = 0;
+                encoded_depth_barrier.dstAccessMask = 0;
+                encoded_depth_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+                encoded_depth_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+                encoded_depth_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+                encoded_depth_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+                encoded_depth_barrier.image = this->encoded_depth_buffers[index]->get();
+                encoded_depth_barrier.subresourceRange = this->encoded_depth_buffers[index]->get_subresource_range();
+            }
+
+            vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, encoded_depth_barriers.size(), encoded_depth_barriers.data());
+        }
 
-        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_barrier);
 
         this->setup_layout = false;
     }
 
+    VkImageMemoryBarrier framebuffer_barrier;
+    framebuffer_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    framebuffer_barrier.pNext = nullptr;
+    framebuffer_barrier.srcAccessMask = 0;
+    framebuffer_barrier.dstAccessMask = 0;
+    framebuffer_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    framebuffer_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    framebuffer_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    framebuffer_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    framebuffer_barrier.image = this->get_headset()->get_framebuffer_array()->get();
+    framebuffer_barrier.subresourceRange = this->get_headset()->get_framebuffer_array()->get_subresource_range();
+
+    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &framebuffer_barrier);
+
     this->get_pass_timer()->begin_pass(command_buffer, "first_layer");
     this->layer = 0;
     this->layer_pass->process(command_buffer, 0);
     this->get_pass_timer()->end_pass(command_buffer);
 
-    if (this->get_headset()->is_remote())
-    {
-        this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_color");
-        this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_encoded_depth");
-
-        switch (this->overlay)
-        {
-        case DUAL_LAYER_REPROJECTION_OVERLAY_COLOR:
-            this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-            break;
-        case DUAL_LAYER_REPROJECTION_OVERLAY_ENCODED_DEPTH:
-            this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-            break;
-        default:
-            lava::log()->error("Dual Layer Reprojection: Invalid overlay mode!");
-            return false;
-        }
-
-        this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0);
-        this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1);
-    }
-
-    else
-    {
-        this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(EYE_LEFT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_color");
-        this->get_frame_capture()->capture_image(command_buffer, this->encoded_depth_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_encoded_depth");
-
-        switch (this->overlay)
-        {
-        case DUAL_LAYER_REPROJECTION_OVERLAY_COLOR:
-            this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->get_headset()->get_framebuffer(EYE_LEFT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-            break;
-        case DUAL_LAYER_REPROJECTION_OVERLAY_ENCODED_DEPTH:
-            this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->encoded_depth_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-            break;
-        default:
-            lava::log()->error("Dual Layer Reprojection: Invalid overlay mode!");
-            return false;
-        }
-
-        this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, EYE_LEFT);
-    }
-
     this->get_pass_timer()->begin_pass(command_buffer, "second_layer");
     this->layer = 1;
     this->layer_pass->process(command_buffer, 1);
@@ -218,44 +218,59 @@ bool DualLayerReprojection::on_render(VkCommandBuffer command_buffer, lava::inde
 
     if (this->get_headset()->is_remote())
     {
-        this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(2), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_color");
-        this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(3), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_encoded_depth");
+        glm::uvec2 display_resolution = this->get_headset()->get_display_resolution();
+        glm::uvec2 layer_offset1 = glm::uvec2(0);
+        glm::uvec2 layer_offset2 = glm::uvec2(display_resolution.x, 0);
+
+        this->get_frame_capture()->capture_image(command_buffer, layer_offset1, display_resolution, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_color");
+        this->get_frame_capture()->capture_image(command_buffer, layer_offset2, display_resolution, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_color");
+
+        this->get_frame_capture()->capture_image(command_buffer, layer_offset1, display_resolution, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_encoded_depth");
+        this->get_frame_capture()->capture_image(command_buffer, layer_offset2, display_resolution, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_encoded_depth");
 
         switch (this->overlay)
         {
         case DUAL_LAYER_REPROJECTION_OVERLAY_COLOR:
-            this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->get_headset()->get_framebuffer(2), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+            this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, layer_offset1, display_resolution, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+            this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, layer_offset2, display_resolution, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
             break;
         case DUAL_LAYER_REPROJECTION_OVERLAY_ENCODED_DEPTH:
-            this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->get_headset()->get_framebuffer(3), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+            this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, layer_offset1, display_resolution, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+            this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, layer_offset2, display_resolution, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
             break;
         default:
             lava::log()->error("Dual Layer Reprojection: Invalid overlay mode!");
             return false;
         }
 
-        this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 2);
-        this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3);
+        this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0);
+        this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1);
     }
 
     else
     {
+        this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(EYE_LEFT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_color");
         this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(EYE_RIGHT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_color");
-        this->get_frame_capture()->capture_image(command_buffer, this->encoded_depth_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_encoded_depth");
+
+        this->get_frame_capture()->capture_image(command_buffer, this->encoded_depth_buffers[0], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_encoded_depth");
+        this->get_frame_capture()->capture_image(command_buffer, this->encoded_depth_buffers[1], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_encoded_depth");
 
         switch (this->overlay)
         {
         case DUAL_LAYER_REPROJECTION_OVERLAY_COLOR:
+            this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->get_headset()->get_framebuffer(EYE_LEFT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
             this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->get_headset()->get_framebuffer(EYE_RIGHT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
             break;
         case DUAL_LAYER_REPROJECTION_OVERLAY_ENCODED_DEPTH:
-            this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->encoded_depth_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+            this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->encoded_depth_buffers[0], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+            this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->encoded_depth_buffers[1], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
             break;
         default:
             lava::log()->error("Dual Layer Reprojection: Invalid overlay mode!");
             return false;
         }
 
+        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);
     }
 
@@ -284,7 +299,7 @@ bool DualLayerReprojection::create_buffers()
         lava::image::ptr depth_buffer = lava::make_image(VK_FORMAT_D32_SFLOAT);
         depth_buffer->set_usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
 
-        if (!depth_buffer->create(this->get_device(), this->get_headset()->get_resolution()))
+        if (!depth_buffer->create(this->get_device(), this->get_headset()->get_framebuffer_resolution()))
         {
             lava::log()->error("Dual Layer Reprojection: Can't create layer depth buffer!");
 
@@ -296,14 +311,19 @@ bool DualLayerReprojection::create_buffers()
 
     if (!this->get_headset()->is_remote())
     {
-        this->encoded_depth_buffer = lava::make_image(VK_FORMAT_R8G8B8A8_UNORM);
-        this->encoded_depth_buffer->set_usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT| VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
-
-        if (!this->encoded_depth_buffer->create(this->get_device(), this->get_headset()->get_resolution()))
+        for (uint32_t index = 0; index < this->encoded_depth_buffers.size(); index++)
         {
-            lava::log()->error("Dual Layer Reprojection: Can't create encoded depth buffer!");
+            lava::image::ptr encoded_depth_buffer = lava::make_image(VK_FORMAT_R8G8B8A8_UNORM);
+            encoded_depth_buffer->set_usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
 
-            return false;
+            if (!encoded_depth_buffer->create(this->get_device(), this->get_headset()->get_framebuffer_resolution()))
+            {
+                lava::log()->error("Dual Layer Reprojection: Can't create encoded depth buffer!");
+
+                return false;
+            }
+
+            this->encoded_depth_buffers[index] = encoded_depth_buffer;
         }
     }
 
@@ -406,14 +426,21 @@ bool DualLayerReprojection::create_layer_pass()
     depth_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
 
     lava::attachment::ptr color_attachment = lava::make_attachment(this->get_headset()->get_format());
-    color_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE);
+    color_attachment->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, 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);
+    color_attachment->set_layouts(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+    VkFormat encoded_depth_format = VK_FORMAT_R8G8B8A8_UNORM;
+
+    if (this->get_headset()->is_remote())
+    {
+        encoded_depth_format = this->get_headset()->get_format();
+    }
 
-    lava::attachment::ptr encoded_depth_attachment = lava::make_attachment(VK_FORMAT_R8G8B8A8_UNORM);
-    encoded_depth_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE);
+    lava::attachment::ptr encoded_depth_attachment = lava::make_attachment(encoded_depth_format);
+    encoded_depth_attachment->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE);
     encoded_depth_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE);
-    encoded_depth_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+    encoded_depth_attachment->set_layouts(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
 
     VkAttachmentReference color_attachment_reference;
     color_attachment_reference.attachment = 1;
@@ -427,18 +454,6 @@ bool DualLayerReprojection::create_layer_pass()
     depth_clear_value.depthStencil.depth = 1.0f;
     depth_clear_value.depthStencil.stencil = 0;
 
-    VkClearValue color_clear_value;
-    color_clear_value.color.float32[0] = 0.0f;
-    color_clear_value.color.float32[1] = 0.0f;
-    color_clear_value.color.float32[2] = 0.0f;
-    color_clear_value.color.float32[3] = 1.0f;
-
-    VkClearValue encoded_depth_clear_value;
-    encoded_depth_clear_value.color.float32[0] = 0.0f;
-    encoded_depth_clear_value.color.float32[1] = 0.0f;
-    encoded_depth_clear_value.color.float32[2] = 0.0f;
-    encoded_depth_clear_value.color.float32[3] = 1.0f;
-
     lava::subpass::ptr subpass = lava::make_subpass();
     subpass->set_depth_stencil_attachment(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
     subpass->set_color_attachments(
@@ -465,15 +480,13 @@ bool DualLayerReprojection::create_layer_pass()
     this->layer_pass->set_clear_values(
     {   
         depth_clear_value,
-        color_clear_value,
-        encoded_depth_clear_value
     });    
 
     lava::VkAttachments framebuffer_views;
     lava::rect framebuffer_area =
     {
         glm::vec2(0.0f),
-        this->get_headset()->get_resolution()
+        this->get_headset()->get_framebuffer_resolution()
     };
 
     if (this->get_headset()->is_remote())
@@ -481,7 +494,7 @@ bool DualLayerReprojection::create_layer_pass()
         framebuffer_views =
         {
             { this->layer_depth_buffers[0]->get_view(), this->get_headset()->get_framebuffer(0)->get_view(), this->get_headset()->get_framebuffer(1)->get_view() },
-            { this->layer_depth_buffers[1]->get_view(), this->get_headset()->get_framebuffer(2)->get_view(), this->get_headset()->get_framebuffer(3)->get_view() }
+            { this->layer_depth_buffers[1]->get_view(), this->get_headset()->get_framebuffer(0)->get_view(), this->get_headset()->get_framebuffer(1)->get_view() },
         };
     }
 
@@ -489,8 +502,8 @@ bool DualLayerReprojection::create_layer_pass()
     {
         framebuffer_views =
         {
-            { this->layer_depth_buffers[0]->get_view(), this->get_headset()->get_framebuffer(EYE_LEFT)->get_view(), this->encoded_depth_buffer->get_view() },
-            { this->layer_depth_buffers[1]->get_view(), this->get_headset()->get_framebuffer(EYE_RIGHT)->get_view(), this->encoded_depth_buffer->get_view() }
+            { this->layer_depth_buffers[0]->get_view(), this->get_headset()->get_framebuffer(EYE_LEFT)->get_view(), this->encoded_depth_buffers[0]->get_view() },
+            { this->layer_depth_buffers[1]->get_view(), this->get_headset()->get_framebuffer(EYE_RIGHT)->get_view(), this->encoded_depth_buffers[1]->get_view() }
         };
     }
 
@@ -611,13 +624,47 @@ void DualLayerReprojection::process_layer_pass(VkCommandBuffer command_buffer)
     uint32_t frame_index = this->get_application()->get_frame_index();
     uint32_t read_index = (this->layer + 1) % 2;
 
+    if (this->layer == 0)
+    {
+        std::array<VkClearAttachment, 2> clear_attachments;
+        clear_attachments[0].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+        clear_attachments[0].colorAttachment ///TODO: .........
+
+
+        vkCmdClearAttachments(command_buffer, 2, )
+    }
+
     glsl::DualLayerReprojectionParameters parameters;
     parameters.layer = this->layer;
+    parameters.depth_offset = 0.0f;
     parameters.constant_threshold = this->layer_constant_threshold;
     parameters.slope_threshold = this->layer_slope_threshold;
 
+    if (this->get_headset()->is_remote() && this->layer == 1)
+    {
+        parameters.depth_offset = -this->get_headset()->get_display_resolution().x;    
+    }
+
     vkCmdPushConstants(command_buffer, this->layer_pipeline_layout->get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(parameters), &parameters);
 
+    if (this->get_headset()->is_remote())
+    {
+        VkViewport viewport;
+        viewport.x = 0.0f;
+        viewport.y = 0.0f;
+        viewport.width = this->get_headset()->get_display_resolution().x;
+        viewport.height = this->get_headset()->get_display_resolution().y;
+        viewport.minDepth = 0.0f;
+        viewport.maxDepth = 1.0f;
+
+        if (this->layer == 1)
+        {
+            viewport.x = this->get_headset()->get_display_resolution().x;
+        }
+
+        vkCmdSetViewport(command_buffer, 0, 1, &viewport);
+    }
+
     this->layer_pipeline_layout->bind(command_buffer, this->get_stereo_transform()->get_descriptor_set(EYE_LEFT, frame_index), 0);
     this->layer_pipeline_layout->bind(command_buffer, this->get_scene()->get_light_descriptor_set(frame_index), 3);
     this->layer_pipeline_layout->bind(command_buffer, this->layer_descriptor_sets[read_index], 4);
diff --git a/src/strategy/dual_layer_reprojection.hpp b/src/strategy/dual_layer_reprojection.hpp
index 79d71c4a350772b51f0cec63c80e6d70ac7f8e75..de959f2b97eea4c273f48db8ee78a50c38e44e03 100644
--- a/src/strategy/dual_layer_reprojection.hpp
+++ b/src/strategy/dual_layer_reprojection.hpp
@@ -53,7 +53,7 @@ private:
     float reproject_slope_threshold = 0.1f;
 
     std::array<lava::image::ptr, 2> layer_depth_buffers;
-    lava::image::ptr encoded_depth_buffer;
+    std::array<lava::image::ptr, 2> encoded_depth_buffers;
 
     lava::descriptor::pool::ptr descriptor_pool;
     lava::descriptor::ptr layer_descriptor;
diff --git a/src/transport/transport.hpp b/src/transport/transport.hpp
index cafde57896524ad5659d7031cec5e3e6e9155b56..a0ec28b17938d726f7f326494f5f5c85616443eb 100644
--- a/src/transport/transport.hpp
+++ b/src/transport/transport.hpp
@@ -53,8 +53,8 @@ public:
     typedef std::shared_ptr<Transport> Ptr;
 
     // OnSetup: Used during the initial handshake
-    //  resolution: The resolution that should be used for rendering
-    typedef std::function<void(const glm::u32vec2& resolution)> OnSetup;
+    //  display_resolution: The resolution of the headset displays
+    typedef std::function<void(const glm::u32vec2& display_resolution)> OnSetup;
 
     // OnProjectionChange: Used to change the projection matrices. Needs to be send once after the handshake.
     //   left_eye_projection: The projection matrix that should be used for the left eye
@@ -112,12 +112,14 @@ public:
 
     // send_setup_complete: Used to send a setup-complete packet
     //                      This function should be threadsafe and callable by main and worker thread
-    //  remote_strategy: The postprocessing method that should be used on the headset
-    //            codec: The codec that is used for the encoding of the images.
-    //    max_frame_ids: The number of images that define a frame and that are send in parallel (normaly 2 for left and right eye). The headset application should setup this many decoders
-    //       near_plane: The distance to the near plane that should be used for the projection matrices
-    //        far_plane: The distance to the far plane that should be used for the projection matrices
-    virtual bool send_setup_complete(RemoteStrategy remote_strategy, EncoderCodec codec, uint32_t max_frame_ids, float near_plane, float far_plane) = 0;
+    //   remote_strategy: The postprocessing method that should be used on the headset
+    //     max_frame_ids: The number of images that define a frame and that are send in parallel (normaly 2 for left and right eye). The headset application should setup this many decoders
+    //             codec: The codec that is used for the encoding of the images.
+    // encode_resolution: The resolution that is used by the encoder and decoder. The resolution could be bigger than the display resolution due to alignments
+    //  render_resoluion: The resolution used by the host during rendering
+    //        near_plane: The distance to the near plane that should be used for the projection matrices
+    //         far_plane: The distance to the far plane that should be used for the projection matrices
+    virtual bool send_setup_complete(RemoteStrategy remote_strategy, uint32_t max_frame_ids, EncoderCodec codec, const glm::uvec2& encode_resolution, const glm::uvec2& render_resolution, float near_plane, float far_plane) = 0;
 
     // send_stage_transform: Used to send the current transformation for the origin
     //                       This transformation can change for example if the user moves by pressing a controller button
diff --git a/src/transport/udp_packet.hpp b/src/transport/udp_packet.hpp
index 7b1afa2cc4fd4b421c383db8d8838895eb916ddc..9aa58ecea2192358647e913d2b5f5df8bb809c3a 100644
--- a/src/transport/udp_packet.hpp
+++ b/src/transport/udp_packet.hpp
@@ -133,7 +133,7 @@ struct UDPPacketSetup
     UDPPacketId id = UDP_PACKET_ID_SETUP;
     uint32_t size = 0;
 
-    glm::u32vec2 resolution;
+    glm::u32vec2 display_resolution;
 };
 
 struct UDPPacketSetupComplete
@@ -142,9 +142,12 @@ struct UDPPacketSetupComplete
     uint32_t size = 0;
 
     UDPStereoStrategyId strategy_id;
-    UDPCodec codec;
     uint32_t max_frame_ids;
 
+    UDPCodec codec;
+    glm::uvec2 encode_resolution;
+    glm::uvec2 render_resolution;
+
     float near_plane;
     float far_plane;
 };
diff --git a/src/transport/udp_transport.cpp b/src/transport/udp_transport.cpp
index 9ef30b3e3f8bfadc82cc325143d7636072fcb3ce..b07872b458cf12258f444a32d1794e209f3deae4 100644
--- a/src/transport/udp_transport.cpp
+++ b/src/transport/udp_transport.cpp
@@ -98,7 +98,7 @@ bool UDPTransport::wait_connect()
     return this->get_state() == TRANSPORT_STATE_CONNECTED;
 }
 
-bool UDPTransport::send_setup_complete(RemoteStrategy remote_strategy, EncoderCodec codec, uint32_t max_frame_ids, float near_plane, float far_plane)
+bool UDPTransport::send_setup_complete(RemoteStrategy remote_strategy, uint32_t max_frame_ids, EncoderCodec codec, const glm::uvec2& encode_resolution, const glm::uvec2& render_resolution, float near_plane, float far_plane)
 {
     if (this->get_state() != TRANSPORT_STATE_CONNECTED)
     {
@@ -129,8 +129,10 @@ bool UDPTransport::send_setup_complete(RemoteStrategy remote_strategy, EncoderCo
     packet->id = UDP_PACKET_ID_SETUP_COMPLETE;
     packet->size = sizeof(UDPPacketSetupComplete);
     packet->strategy_id = udp_strategy;
-    packet->codec = udp_codec;
     packet->max_frame_ids = max_frame_ids;
+    packet->codec = udp_codec;
+    packet->encode_resolution = encode_resolution;
+    packet->render_resolution = render_resolution;
     packet->near_plane = near_plane;
     packet->far_plane = far_plane;
 
@@ -814,7 +816,7 @@ void UDPTransport::parse_setup(const Datagram& datagram)
         return;
     }
 
-    this->on_setup(packet->resolution);
+    this->on_setup(packet->display_resolution);
 }
 
 void UDPTransport::parse_projection_change(const Datagram& datagram)
diff --git a/src/transport/udp_transport.hpp b/src/transport/udp_transport.hpp
index 909918cd8e8fff774e45696edbb4d7499e969c1d..173cdd6c73274dd3b09495ec238c1bd37d8f5944 100644
--- a/src/transport/udp_transport.hpp
+++ b/src/transport/udp_transport.hpp
@@ -23,7 +23,7 @@ public:
     void destroy() override;
     bool wait_connect() override;
 
-    bool send_setup_complete(RemoteStrategy remote_strategy, EncoderCodec codec, uint32_t max_frame_ids, float near_plane, float far_plane) override;
+    bool send_setup_complete(RemoteStrategy remote_strategy, uint32_t max_frame_ids, EncoderCodec codec, const glm::uvec2& encode_resolution, const glm::uvec2& render_resolution, float near_plane, float far_plane) override;
     bool send_stage_transform(const glm::mat4& stage_transform) override;
     bool send_frame_config_nal(FrameId frame_id, const std::span<const uint8_t>& content) override;
     bool send_frame_nal(FrameNumber frame_number, FrameId frame_id, TransformId transform_id, const std::span<const uint8_t>& content) override;
diff --git a/src/utility/companion_window.cpp b/src/utility/companion_window.cpp
index 078a674517246c398ed988f821d7e381927293cd..8d70778c911cac3a1335be43652459044a416087 100644
--- a/src/utility/companion_window.cpp
+++ b/src/utility/companion_window.cpp
@@ -90,6 +90,11 @@ void CompanionWindow::render(VkCommandBuffer command_buffer, lava::render_target
 }
 
 void CompanionWindow::submit_image(VkCommandBuffer command_buffer, Eye eye, lava::image::ptr image, VkImageLayout image_layout)
+{
+    this->submit_image(command_buffer, eye, glm::uvec2(0), image->get_size(), image, image_layout);
+}
+
+void CompanionWindow::submit_image(VkCommandBuffer command_buffer, Eye eye, const glm::uvec2& submit_offset, const glm::uvec2& submit_size, lava::image::ptr image, VkImageLayout image_layout)
 {
     if (!this->enabled)
     {
@@ -137,7 +142,6 @@ void CompanionWindow::submit_image(VkCommandBuffer command_buffer, Eye eye, lava
     subresource_layers.layerCount = 1;
 
     glm::uvec2 buffer_resolution = this->framebuffer->get_size();
-    glm::uvec2 image_resolution = image->get_size();
     uint32_t eye_offset = 0;
 
     if (eye == EYE_RIGHT)
@@ -147,11 +151,11 @@ void CompanionWindow::submit_image(VkCommandBuffer command_buffer, Eye eye, lava
 
     VkImageBlit image_blit;
     image_blit.srcSubresource = image->get_subresource_layers();
-    image_blit.srcOffsets[0].x = 0;
-    image_blit.srcOffsets[0].y = 0;
+    image_blit.srcOffsets[0].x = submit_offset.x;
+    image_blit.srcOffsets[0].y = submit_offset.y;
     image_blit.srcOffsets[0].z = 0;
-    image_blit.srcOffsets[1].x = image_resolution.x;
-    image_blit.srcOffsets[1].y = image_resolution.y;
+    image_blit.srcOffsets[1].x = submit_offset.x + submit_size.x;
+    image_blit.srcOffsets[1].y = submit_offset.y + submit_size.y;
     image_blit.srcOffsets[1].z = 1;
     image_blit.dstSubresource = subresource_layers;
     image_blit.dstOffsets[0].x = eye_offset;
diff --git a/src/utility/companion_window.hpp b/src/utility/companion_window.hpp
index f4b814c362a9777ae74129720c253ccd2aa55db8..4c3445dd3fc0a8705a8782b4d5e497071bfd157b 100644
--- a/src/utility/companion_window.hpp
+++ b/src/utility/companion_window.hpp
@@ -30,6 +30,7 @@ public:
     // The image format of the given image needs to be a four channel color type where each channel has a bit-depth of one byte.
     // After the image is copied to the companion window, its image layout is restored.
     void submit_image(VkCommandBuffer command_buffer, Eye eye, lava::image::ptr image, VkImageLayout image_layout);
+    void submit_image(VkCommandBuffer command_buffer, Eye eye, const glm::uvec2& submit_offset, const glm::uvec2& submit_size, lava::image::ptr image, VkImageLayout image_layout);
 
     void set_enabled(bool enabled);
     bool is_enabled() const;
diff --git a/src/utility/frame_capture.cpp b/src/utility/frame_capture.cpp
index 5c8680b53d5229de33baf8bb6c51bb8c69468748..4ff9bc5a87d7a87829b4342b7dd2a796392c0e51 100644
--- a/src/utility/frame_capture.cpp
+++ b/src/utility/frame_capture.cpp
@@ -35,6 +35,11 @@ void FrameCapture::next_frame(lava::index frame)
 }
 
 void FrameCapture::capture_image(VkCommandBuffer command_buffer, lava::image::ptr image, VkImageLayout image_layout, const std::string& image_name)
+{
+    this->capture_image(command_buffer, glm::uvec2(0), image->get_size(), image, image_layout, image_name);
+}
+
+void FrameCapture::capture_image(VkCommandBuffer command_buffer, const glm::uvec2& capture_offset, const glm::uvec2& capture_size, lava::image::ptr image, VkImageLayout image_layout, const std::string& image_name)
 {
     if (!this->enabled)
     {
@@ -42,22 +47,21 @@ void FrameCapture::capture_image(VkCommandBuffer command_buffer, lava::image::pt
     }
 
     lava::device_ptr device = image->get_device();
-    lava::uv2 image_size = image->get_size();
     VkFormat image_format = image->get_format();
 
-    uint32_t staging_buffer_size = image_size.x * image_size.y * this->get_component_count(image_format) * this->get_component_size(image_format);
+    uint32_t staging_buffer_size = capture_size.x * capture_size.y * this->get_component_count(image_format) * this->get_component_size(image_format);
 
     lava::buffer::ptr staging_buffer = lava::make_buffer();
     staging_buffer->create(device, nullptr, staging_buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, false, VmaMemoryUsage::VMA_MEMORY_USAGE_GPU_TO_CPU);
 
     VkOffset3D image_offset;
-    image_offset.x = 0;
-    image_offset.y = 0;
+    image_offset.x = capture_offset.x;
+    image_offset.y = capture_offset.y;
     image_offset.z = 0;
 
     VkExtent3D image_extend;
-    image_extend.width = image_size.x;
-    image_extend.height = image_size.y;
+    image_extend.width = capture_size.x;
+    image_extend.height = capture_size.y;
     image_extend.depth = 1;
 
     VkImageMemoryBarrier begin_barrier;
@@ -129,7 +133,7 @@ void FrameCapture::capture_image(VkCommandBuffer command_buffer, lava::image::pt
     ImageCapture capture;
     capture.frame_index = this->current_frame;
     capture.name = image_name;
-    capture.size = image_size;
+    capture.size = capture_size;
     capture.format = image_format;
     capture.store_directory = directory.name;
     capture.store_index = directory.index;
diff --git a/src/utility/frame_capture.hpp b/src/utility/frame_capture.hpp
index 4a4a86b61997fd2424d33c7695c2ad252bee49fe..781291a41085d4f9132aecd18f5b34d46ce4def6 100644
--- a/src/utility/frame_capture.hpp
+++ b/src/utility/frame_capture.hpp
@@ -53,6 +53,7 @@ public:
 
     void next_frame(lava::index frame);
     void capture_image(VkCommandBuffer command_buffer, lava::image::ptr image, VkImageLayout image_layout, const std::string& image_name);
+    void capture_image(VkCommandBuffer command_buffer, const glm::uvec2& capture_offset, const glm::uvec2& capture_size, lava::image::ptr image, VkImageLayout image_layout, const std::string& image_name);
 
     void set_enabled(bool enabled);
     bool is_enabled() const;