diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c
index 7f9d1fcdf..71b0c7446 100644
--- a/src/xrt/compositor/main/comp_compositor.c
+++ b/src/xrt/compositor/main/comp_compositor.c
@@ -6,6 +6,7 @@
  * @author Jakob Bornecrantz <jakob@collabora.com>
  * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
  * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ * @author Moses Turner <moses@collabora.com>
  * @ingroup comp_main
  *
  *
@@ -363,7 +364,7 @@ compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_graphic
 	 * We have a fast path for single projection layer that goes directly
 	 * to the distortion shader, so no need to use the layer renderer.
 	 */
-	bool fast_path = can_do_one_projection_layer_fast_path(c);
+	bool fast_path = can_do_one_projection_layer_fast_path(c) && !c->mirroring_to_debug_gui;
 	c->base.slot.one_projection_layer_fast_path = fast_path;
 
 
@@ -1171,6 +1172,25 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos
 
 	c->last_frame_time_ns = os_monotonic_get_ns();
 
+	float scale = c->settings.viewport_scale;
+
+	if (scale > 2.0) {
+		scale = 2.0;
+		COMP_DEBUG(c, "Clamped scale to 200%%\n");
+	}
+
+	uint32_t w0 = (uint32_t)(xdev->hmd->views[0].display.w_pixels * scale);
+	uint32_t h0 = (uint32_t)(xdev->hmd->views[0].display.h_pixels * scale);
+	uint32_t w1 = (uint32_t)(xdev->hmd->views[1].display.w_pixels * scale);
+	uint32_t h1 = (uint32_t)(xdev->hmd->views[1].display.h_pixels * scale);
+
+	uint32_t w0_2 = xdev->hmd->views[0].display.w_pixels * 2;
+	uint32_t h0_2 = xdev->hmd->views[0].display.h_pixels * 2;
+	uint32_t w1_2 = xdev->hmd->views[1].display.w_pixels * 2;
+	uint32_t h1_2 = xdev->hmd->views[1].display.h_pixels * 2;
+
+	c->view_extents.width = w0;
+	c->view_extents.height = h0;
 
 	// Need to select window backend before creating Vulkan, then
 	// swapchain will initialize the window fully and the swapchain,
@@ -1256,22 +1276,7 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos
 	memcpy(sys_info->compositor_vk_deviceUUID, c->settings.selected_gpu_deviceUUID, XRT_GPU_UUID_SIZE);
 	memcpy(sys_info->client_vk_deviceUUID, c->settings.client_gpu_deviceUUID, XRT_GPU_UUID_SIZE);
 
-	float scale = c->settings.viewport_scale;
 
-	if (scale > 2.0) {
-		scale = 2.0;
-		COMP_DEBUG(c, "Clamped scale to 200%%\n");
-	}
-
-	uint32_t w0 = (uint32_t)(xdev->hmd->views[0].display.w_pixels * scale);
-	uint32_t h0 = (uint32_t)(xdev->hmd->views[0].display.h_pixels * scale);
-	uint32_t w1 = (uint32_t)(xdev->hmd->views[1].display.w_pixels * scale);
-	uint32_t h1 = (uint32_t)(xdev->hmd->views[1].display.h_pixels * scale);
-
-	uint32_t w0_2 = xdev->hmd->views[0].display.w_pixels * 2;
-	uint32_t h0_2 = xdev->hmd->views[0].display.h_pixels * 2;
-	uint32_t w1_2 = xdev->hmd->views[1].display.w_pixels * 2;
-	uint32_t h1_2 = xdev->hmd->views[1].display.h_pixels * 2;
 
 	// clang-format off
 	sys_info->views[0].recommended.width_pixels  = w0;
@@ -1328,6 +1333,8 @@ xrt_gfx_provider_create_system(struct xrt_device *xdev, struct xrt_system_compos
 
 	u_var_add_f32_timing(c, ft, "Frame Times (Compositor)");
 
+	comp_renderer_add_debug_vars(c->r);
+
 	c->compositor_frame_times.debug_var = ft;
 
 	c->state = COMP_STATE_READY;
diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h
index da9952e85..0e02d26fb 100644
--- a/src/xrt/compositor/main/comp_compositor.h
+++ b/src/xrt/compositor/main/comp_compositor.h
@@ -99,6 +99,12 @@ struct comp_compositor
 	//! State for generating the correct set of events.
 	enum comp_state state;
 
+	// Extents of one view, in pixels.
+	VkExtent2D view_extents;
+
+	//! Are we mirroring any of the views to the debug gui? If so, turn off the fast path.
+	bool mirroring_to_debug_gui;
+
 	/*!
 	 * @brief Data exclusive to the begin_frame/end_frame for computing an
 	 * estimate of the app's needs.
diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c
index 49d45be81..8a46cc049 100644
--- a/src/xrt/compositor/main/comp_renderer.c
+++ b/src/xrt/compositor/main/comp_renderer.c
@@ -1,4 +1,4 @@
-// Copyright 2019-2021, Collabora, Ltd.
+// Copyright 2019-2022, Collabora, Ltd.
 // SPDX-License-Identifier: BSL-1.0
 /*!
  * @file
@@ -6,23 +6,33 @@
  * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
  * @author Jakob Bornecrantz <jakob@collabora.com>
  * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ * @author Moses Turner <moses@collabora.com>
  * @ingroup comp_main
  */
 
+#include "xrt/xrt_defines.h"
+#include "xrt/xrt_frame.h"
 #include "xrt/xrt_compositor.h"
 
 #include "os/os_time.h"
 
+#include "math/m_api.h"
+#include "math/m_vec3.h"
+#include "math/m_matrix_4x4_f64.h"
 #include "math/m_space.h"
 
 #include "util/u_misc.h"
 #include "util/u_trace_marker.h"
 #include "util/u_distortion_mesh.h"
+#include "util/u_sink.h"
+#include "util/u_var.h"
+#include "util/u_frame.h"
 
 #include "main/comp_layer_renderer.h"
-#include "math/m_api.h"
-#include "math/m_vec3.h"
-#include "math/m_matrix_4x4_f64.h"
+
+
+#include "vk/vk_helpers.h"
+#include "vk/vk_image_readback_to_xf_pool.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -52,6 +62,19 @@ struct comp_renderer
 	struct comp_compositor *c;
 	struct comp_settings *settings;
 
+	struct
+	{
+		// Hint: enable/disable is in c->mirroring_to_debug_gui. It's there because comp_renderer is just a
+		// forward decl to comp_compositor.c
+		struct u_sink_debug debug_sink;
+		VkExtent2D image_extent;
+		uint64_t sequence;
+
+		struct vk_image_readback_to_xf_pool *pool;
+
+	} mirror_to_debug_gui;
+
+
 	struct
 	{
 		VkSemaphore present_complete;
@@ -433,19 +456,11 @@ renderer_create_layer_renderer(struct comp_renderer *r)
 	}
 
 	VkExtent2D extent;
-	if (r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
-	    r->c->target->surface_transform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
-		// Swapping width and height, since we are pre rotating
-		extent = (VkExtent2D){
-		    .width = r->c->xdev->hmd->screens[0].h_pixels,
-		    .height = r->c->xdev->hmd->screens[0].w_pixels,
-		};
-	} else {
-		extent = (VkExtent2D){
-		    .width = r->c->xdev->hmd->screens[0].w_pixels,
-		    .height = r->c->xdev->hmd->screens[0].h_pixels,
-		};
-	}
+
+	extent = (VkExtent2D){
+	    .width = r->c->view_extents.width,
+	    .height = r->c->view_extents.height,
+	};
 
 	r->lr = comp_layer_renderer_create(vk, &r->c->shaders, extent, VK_FORMAT_B8G8R8A8_SRGB);
 	if (layer_count != 0) {
@@ -541,6 +556,17 @@ renderer_create(struct comp_renderer *r, struct comp_compositor *c)
 
 	// Try to early-allocate these, in case we can.
 	renderer_ensure_images_and_renderings(r, false);
+
+	double orig_width = r->lr->extent.width;
+	double orig_height = r->lr->extent.height;
+
+	double mul = 1080.0 / orig_height;
+
+	r->mirror_to_debug_gui.image_extent.width = orig_width * mul;
+	r->mirror_to_debug_gui.image_extent.height = orig_height * mul;
+
+	vk_image_readback_to_xf_pool_create(vk, r->mirror_to_debug_gui.image_extent, &r->mirror_to_debug_gui.pool,
+	                                    XRT_FORMAT_R8G8B8X8);
 }
 
 static void
@@ -732,6 +758,9 @@ renderer_destroy(struct comp_renderer *r)
 {
 	struct vk_bundle *vk = &r->c->base.vk;
 
+	// Left eye readback
+	vk_image_readback_to_xf_pool_destroy(vk, &r->mirror_to_debug_gui.pool);
+
 	// Command buffers
 	renderer_close_renderings_and_fences(r);
 
@@ -1235,6 +1264,154 @@ comp_renderer_set_equirect2_layer(struct comp_renderer *r,
 }
 #endif
 
+static bool
+can_mirror_to_debug_gui(struct comp_renderer *r)
+{
+	return r->c->mirroring_to_debug_gui && u_sink_debug_is_active(&r->mirror_to_debug_gui.debug_sink);
+}
+
+static void
+mirror_to_debug_gui_do_blit(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->base.vk;
+
+	struct vk_image_readback_to_xf *wrap = NULL;
+
+	if (!vk_image_readback_to_xf_pool_get_unused_frame(vk, r->mirror_to_debug_gui.pool, &wrap)) {
+		return;
+	}
+
+	VkCommandBuffer cmd;
+	vk_init_cmd_buffer(vk, &cmd);
+
+	VkImage copy_from = r->lr->framebuffers[0].image;
+
+#if 0
+	bool fast = r->c->base.slot.one_projection_layer_fast_path;
+
+
+	if (fast) {
+		switch (layer->data.type) {
+		case XRT_LAYER_STEREO_PROJECTION: {
+			copy_from = layer->sc_array[0]->vkic.images[layer->data.stereo.l.sub.image_index].handle;
+		} break;
+		case XRT_LAYER_STEREO_PROJECTION_DEPTH: {
+			copy_from = layer->sc_array[0]->vkic.images[layer->data.stereo_depth.l.sub.image_index].handle;
+		} break;
+		default: assert(false);
+		}
+	} else {
+		
+		
+	}
+#endif
+
+
+
+	VkImageSubresourceRange first_color_level_subresource_range = {
+	    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+	    .baseMipLevel = 0,
+	    .levelCount = 1,
+	    .baseArrayLayer = 0,
+	    .layerCount = 1,
+	};
+
+	// Barrier to make destination a destination
+	vk_insert_image_memory_barrier(           //
+	    vk,                                   // vk_bundle
+	    cmd,                                  // cmdbuffer
+	    wrap->image,                          // image
+	    VK_ACCESS_HOST_READ_BIT,              // srcAccessMask
+	    VK_ACCESS_TRANSFER_WRITE_BIT,         // dstAccessMask
+	    wrap->layout,                         // oldImageLayout
+	    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // newImageLayout
+	    VK_PIPELINE_STAGE_HOST_BIT,           // srcStageMask
+	    VK_PIPELINE_STAGE_TRANSFER_BIT,       // dstStageMask
+	    first_color_level_subresource_range); // subresourceRange
+
+	// Barrier to make source a source
+	vk_insert_image_memory_barrier(               //
+	    vk,                                       // vk_bundle
+	    cmd,                                      // cmdbuffer
+	    copy_from,                                // image
+	    VK_ACCESS_SHADER_WRITE_BIT,               // srcAccessMask
+	    VK_ACCESS_TRANSFER_READ_BIT,              // dstAccessMask
+	    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // oldImageLayout
+	    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,     // newImageLayout
+	    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,     // srcStageMask
+	    VK_PIPELINE_STAGE_TRANSFER_BIT,           // dstStageMask
+	    first_color_level_subresource_range);     // subresourceRange
+
+
+	VkImageBlit blit = {0};
+	blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	blit.srcSubresource.layerCount = 1;
+
+	blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	blit.dstSubresource.layerCount = 1;
+
+	blit.srcOffsets[1].x = r->lr->extent.width;
+	blit.srcOffsets[1].y = r->lr->extent.height;
+	blit.srcOffsets[1].z = 1;
+
+
+	blit.dstOffsets[1].x = r->mirror_to_debug_gui.image_extent.width;
+	blit.dstOffsets[1].y = r->mirror_to_debug_gui.image_extent.height;
+	blit.dstOffsets[1].z = 1;
+
+	vk->vkCmdBlitImage(                       //
+	    cmd,                                  // commandBuffer
+	    copy_from,                            // srcImage
+	    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // srcImageLayout
+	    wrap->image,                          // dstImage
+	    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // dstImageLayout
+	    1,                                    // regionCount
+	    &blit,                                // pRegions
+	    VK_FILTER_LINEAR                      // filter
+	);
+
+	wrap->layout = VK_IMAGE_LAYOUT_GENERAL;
+
+	// Reset destination
+	vk_insert_image_memory_barrier(           //
+	    vk,                                   // vk_bundle
+	    cmd,                                  // cmdbuffer
+	    wrap->image,                          // image
+	    VK_ACCESS_TRANSFER_WRITE_BIT,         // srcAccessMask
+	    VK_ACCESS_HOST_READ_BIT,              // dstAccessMask
+	    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // oldImageLayout
+	    wrap->layout,                         // newImageLayout
+	    VK_PIPELINE_STAGE_TRANSFER_BIT,       // srcStageMask
+	    VK_PIPELINE_STAGE_HOST_BIT,           // dstStageMask
+	    first_color_level_subresource_range); // subresourceRange
+
+	// Reset src
+	vk_insert_image_memory_barrier(               //
+	    vk,                                       // vk_bundle
+	    cmd,                                      // cmdbuffer
+	    copy_from,                                // image
+	    VK_ACCESS_TRANSFER_READ_BIT,              // srcAccessMask
+	    VK_ACCESS_SHADER_WRITE_BIT,               // dstAccessMask
+	    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,     // oldImageLayout
+	    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // newImageLayout
+	    VK_PIPELINE_STAGE_TRANSFER_BIT,           // srcStageMask
+	    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,     // dstStageMask
+	    first_color_level_subresource_range);     // subresourceRange
+
+	// Waits for command to finish.
+	vk_submit_cmd_buffer(vk, cmd);
+
+	wrap->base_frame.source_timestamp = wrap->base_frame.timestamp =
+	    r->c->frame.rendering.predicted_display_time_ns;
+	wrap->base_frame.source_id = r->mirror_to_debug_gui.sequence++;
+
+
+	struct xrt_frame *frame = &wrap->base_frame;
+	wrap = NULL;
+	u_sink_debug_push_frame(&r->mirror_to_debug_gui.debug_sink, frame);
+	xrt_frame_reference(&frame, NULL);
+}
+
 void
 comp_renderer_draw(struct comp_renderer *r)
 {
@@ -1282,9 +1459,14 @@ comp_renderer_draw(struct comp_renderer *r)
 	renderer_present_swapchain_image(r, c->frame.rendering.desired_present_time_ns,
 	                                 c->frame.rendering.present_slop_ns);
 
+
 	// Clear the frame.
 	c->frame.rendering.id = -1;
 
+	if (can_mirror_to_debug_gui(r)) {
+		mirror_to_debug_gui_do_blit(r);
+	}
+
 	/*
 	 * This fixes a lot of validation issues as it makes sure that the
 	 * command buffer has completed and all resources referred by it can
@@ -1294,6 +1476,8 @@ comp_renderer_draw(struct comp_renderer *r)
 	 */
 	renderer_wait_gpu_idle(r);
 
+
+
 	if (use_compute) {
 		comp_rendering_compute_close(&crc);
 	} else {
@@ -1352,3 +1536,11 @@ comp_renderer_destroy(struct comp_renderer **ptr_r)
 	free(r);
 	*ptr_r = NULL;
 }
+
+void
+comp_renderer_add_debug_vars(struct comp_renderer *r)
+{
+	// 1.2 % 2.3;
+	u_var_add_bool(r->c, &r->c->mirroring_to_debug_gui, "Display left eye to GUI (slow)");
+	u_var_add_sink_debug(r->c, &r->mirror_to_debug_gui.debug_sink, "Left view!");
+}
diff --git a/src/xrt/compositor/main/comp_renderer.h b/src/xrt/compositor/main/comp_renderer.h
index a5be40502..27d9ff7a5 100644
--- a/src/xrt/compositor/main/comp_renderer.h
+++ b/src/xrt/compositor/main/comp_renderer.h
@@ -128,6 +128,9 @@ comp_renderer_allocate_layers(struct comp_renderer *self, uint32_t layer_count);
 void
 comp_renderer_destroy_layers(struct comp_renderer *self);
 
+void
+comp_renderer_add_debug_vars(struct comp_renderer *self);
+
 #ifdef __cplusplus
 }
 #endif