From 54739aff8dc39ef513352cc8aeffde791ab28a0b Mon Sep 17 00:00:00 2001
From: Jakob Bornecrantz <jakob@collabora.com>
Date: Mon, 5 Oct 2020 23:30:31 +0100
Subject: [PATCH] c/render: Refactor out distortion rendering

---
 src/xrt/compositor/CMakeLists.txt          |   6 +-
 src/xrt/compositor/main/comp_compositor.c  |   6 +
 src/xrt/compositor/main/comp_compositor.h  |   4 +
 src/xrt/compositor/main/comp_distortion.c  | 726 ------------------
 src/xrt/compositor/main/comp_distortion.h  | 136 ----
 src/xrt/compositor/main/comp_renderer.c    | 495 +++---------
 src/xrt/compositor/meson.build             |   6 +-
 src/xrt/compositor/render/comp_buffer.c    | 222 ++++++
 src/xrt/compositor/render/comp_render.h    | 355 +++++++++
 src/xrt/compositor/render/comp_rendering.c | 847 +++++++++++++++++++++
 src/xrt/compositor/render/comp_resources.c | 333 ++++++++
 11 files changed, 1882 insertions(+), 1254 deletions(-)
 delete mode 100644 src/xrt/compositor/main/comp_distortion.c
 delete mode 100644 src/xrt/compositor/main/comp_distortion.h
 create mode 100644 src/xrt/compositor/render/comp_buffer.c
 create mode 100644 src/xrt/compositor/render/comp_render.h
 create mode 100644 src/xrt/compositor/render/comp_rendering.c
 create mode 100644 src/xrt/compositor/render/comp_resources.c

diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt
index ade5b7b26..7ad36844b 100644
--- a/src/xrt/compositor/CMakeLists.txt
+++ b/src/xrt/compositor/CMakeLists.txt
@@ -13,8 +13,6 @@ set(CLIENT_SOURCE_FILES)
 set(MAIN_SOURCE_FILES
 	main/comp_compositor.c
 	main/comp_compositor.h
-	main/comp_distortion.c
-	main/comp_distortion.h
 	main/comp_documentation.h
 	main/comp_renderer.c
 	main/comp_renderer.h
@@ -29,6 +27,10 @@ set(MAIN_SOURCE_FILES
 	main/comp_layer.c
 	main/comp_layer_renderer.h
 	main/comp_layer_renderer.c
+	render/comp_buffer.c
+	render/comp_render.h
+	render/comp_rendering.c
+	render/comp_resources.c
 	)
 
 ###
diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c
index 25b7134d0..e251bbad4 100644
--- a/src/xrt/compositor/main/comp_compositor.c
+++ b/src/xrt/compositor/main/comp_compositor.c
@@ -81,6 +81,8 @@ compositor_destroy(struct xrt_compositor *xc)
 		c->r = NULL;
 	}
 
+	comp_resources_close(c, &c->nr);
+
 	// As long as vk_bundle is valid it's safe to call this function.
 	comp_shaders_close(&c->vk, &c->shaders);
 
@@ -1146,6 +1148,10 @@ compositor_init_shaders(struct comp_compositor *c)
 static bool
 compositor_init_renderer(struct comp_compositor *c)
 {
+	if (!comp_resources_init(c, &c->nr)) {
+		return false;
+	}
+
 	c->r = comp_renderer_create(c);
 	return c->r != NULL;
 }
diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h
index 9bd00e48c..4af484315 100644
--- a/src/xrt/compositor/main/comp_compositor.h
+++ b/src/xrt/compositor/main/comp_compositor.h
@@ -21,6 +21,7 @@
 #include "main/comp_settings.h"
 #include "main/comp_window.h"
 #include "main/comp_renderer.h"
+#include "render/comp_render.h"
 
 
 #ifdef __cplusplus
@@ -237,6 +238,9 @@ struct comp_compositor
 		//! Thread object for safely destroying swapchain.
 		struct u_threading_stack destroy_swapchains;
 	} threading;
+
+
+	struct comp_resources nr;
 };
 
 
diff --git a/src/xrt/compositor/main/comp_distortion.c b/src/xrt/compositor/main/comp_distortion.c
deleted file mode 100644
index ea74f05e4..000000000
--- a/src/xrt/compositor/main/comp_distortion.c
+++ /dev/null
@@ -1,726 +0,0 @@
-// Copyright 2019, Collabora, Ltd.
-// SPDX-License-Identifier: BSL-1.0
-/*!
- * @file
- * @brief  Distortion shader code.
- * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
- * @author Jakob Bornecrantz <jakob@collabora.com>
- * @ingroup comp_main
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "main/comp_settings.h"
-#include "main/comp_compositor.h"
-
-#include "comp_distortion.h"
-
-
-/*
- *
- * Pre declare functions.
- *
- */
-
-static void
-comp_distortion_update_uniform_buffer_warp(struct comp_distortion *d,
-                                           struct comp_compositor *c);
-
-static void
-comp_distortion_init_buffers(struct comp_distortion *d,
-                             struct comp_compositor *c);
-
-XRT_MAYBE_UNUSED static void
-comp_distortion_update_descriptor_sets(struct comp_distortion *d,
-                                       VkSampler samplers[2],
-                                       VkImageView views[2],
-                                       bool flip_y);
-
-static void
-comp_distortion_init_descriptor_set_layout(struct comp_distortion *d);
-
-static void
-comp_distortion_init_pipeline_layout(struct comp_distortion *d);
-
-static void
-comp_distortion_init_pipeline(struct comp_distortion *d,
-                              struct comp_shaders *s,
-                              VkRenderPass render_pass,
-                              VkPipelineCache pipeline_cache);
-
-static VkWriteDescriptorSet
-comp_distortion_get_uniform_write_descriptor_set(
-    struct comp_distortion *d,
-    uint32_t binding,
-    VkDescriptorSet descriptor_set,
-    struct comp_uniform_buffer *ubo_handle);
-
-static VkWriteDescriptorSet
-comp_distortion_get_image_write_descriptor_set(
-    VkDescriptorSet descriptor_set,
-    VkDescriptorImageInfo *descriptor_position,
-    uint32_t binding);
-
-static void
-comp_distortion_init_descriptor_sets(struct comp_distortion *d,
-                                     VkDescriptorPool descriptor_pool);
-
-
-/*
- *
- * Buffer functions.
- *
- */
-
-static void
-_buffer_destroy(struct vk_bundle *vk, struct comp_uniform_buffer *buffer)
-{
-	if (buffer->buffer != VK_NULL_HANDLE) {
-		vk->vkDestroyBuffer(buffer->device, buffer->buffer, NULL);
-	}
-	if (buffer->memory != VK_NULL_HANDLE) {
-		vk->vkFreeMemory(buffer->device, buffer->memory, NULL);
-	}
-}
-
-static VkResult
-_buffer_map(struct vk_bundle *vk,
-            struct comp_uniform_buffer *buffer,
-            VkDeviceSize size,
-            VkDeviceSize offset)
-{
-	return vk->vkMapMemory(vk->device, buffer->memory, offset, size, 0,
-	                       &buffer->mapped);
-}
-
-static void
-_buffer_unmap(struct vk_bundle *vk, struct comp_uniform_buffer *buffer)
-{
-	if (buffer->mapped) {
-		vk->vkUnmapMemory(vk->device, buffer->memory);
-		buffer->mapped = NULL;
-	}
-}
-
-static void
-_buffer_setup_descriptor(struct vk_bundle *vk,
-                         struct comp_uniform_buffer *buffer,
-                         VkDeviceSize size,
-                         VkDeviceSize offset)
-{
-	buffer->descriptor.offset = offset;
-	buffer->descriptor.buffer = buffer->buffer;
-	buffer->descriptor.range = size;
-}
-
-
-/*
- *
- * Functions.
- *
- */
-
-void
-comp_distortion_init(struct comp_distortion *d,
-                     struct comp_compositor *c,
-                     VkRenderPass render_pass,
-                     VkPipelineCache pipeline_cache,
-                     struct xrt_hmd_parts *parts,
-                     VkDescriptorPool descriptor_pool)
-{
-	d->vk = &c->vk;
-
-	//! Add support for 1 channels as well.
-	assert(parts->distortion.mesh.vertices == NULL ||
-	       parts->distortion.mesh.num_uv_channels == 3);
-	assert(parts->distortion.mesh.indices == NULL ||
-	       parts->distortion.mesh.total_num_indices != 0);
-	assert(parts->distortion.mesh.indices == NULL ||
-	       parts->distortion.mesh.num_indices[0] != 0);
-	assert(parts->distortion.mesh.indices == NULL ||
-	       parts->distortion.mesh.num_indices[1] != 0);
-
-	d->mesh.vertices = parts->distortion.mesh.vertices;
-	d->mesh.stride = parts->distortion.mesh.stride;
-	d->mesh.num_vertices = parts->distortion.mesh.num_vertices;
-	d->mesh.indices = parts->distortion.mesh.indices;
-	d->mesh.total_num_indices = parts->distortion.mesh.total_num_indices;
-	d->mesh.num_indices[0] = parts->distortion.mesh.num_indices[0];
-	d->mesh.num_indices[1] = parts->distortion.mesh.num_indices[1];
-	d->mesh.offset_indices[0] = parts->distortion.mesh.offset_indices[0];
-	d->mesh.offset_indices[1] = parts->distortion.mesh.offset_indices[1];
-
-	d->ubo_vp_data[0].flip_y = false;
-	d->ubo_vp_data[1].flip_y = false;
-	d->quirk_draw_lines = c->settings.debug.wireframe;
-
-	// binding indices used in mesh.vert & mesh.frag shaders.
-	d->render_texture_target_binding = 0;
-	d->ubo_viewport_binding = 1;
-
-	comp_distortion_init_buffers(d, c);
-	comp_distortion_update_uniform_buffer_warp(d, c);
-	comp_distortion_init_descriptor_set_layout(d);
-	comp_distortion_init_pipeline_layout(d);
-	comp_distortion_init_pipeline(d, &c->shaders, render_pass,
-	                              pipeline_cache);
-	comp_distortion_init_descriptor_sets(d, descriptor_pool);
-}
-
-void
-comp_distortion_destroy(struct comp_distortion *d)
-{
-	struct vk_bundle *vk = d->vk;
-
-	/*
-	 * This makes sure that any pending command buffer has completed and all
-	 * resources referred by it can now be manipulated. This make sure that
-	 * validation doesn't complain. This is done during destroy so isn't
-	 * time critical.
-	 */
-	vk->vkDeviceWaitIdle(vk->device);
-
-	vk->vkDestroyDescriptorSetLayout(vk->device, d->descriptor_set_layout,
-	                                 NULL);
-
-	_buffer_destroy(vk, &d->vbo_handle);
-	_buffer_destroy(vk, &d->index_handle);
-	_buffer_destroy(vk, &d->ubo_viewport_handles[0]);
-	_buffer_destroy(vk, &d->ubo_viewport_handles[1]);
-
-	vk->vkDestroyPipeline(vk->device, d->pipeline, NULL);
-	vk->vkDestroyPipelineLayout(vk->device, d->pipeline_layout, NULL);
-
-	free(d);
-}
-
-static void
-comp_distortion_init_pipeline(struct comp_distortion *d,
-                              struct comp_shaders *s,
-                              VkRenderPass render_pass,
-                              VkPipelineCache pipeline_cache)
-{
-	struct vk_bundle *vk = d->vk;
-	VkResult ret;
-
-	VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL;
-	if (d->quirk_draw_lines) {
-		polygonMode = VK_POLYGON_MODE_LINE;
-	}
-
-	VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
-	if (d->mesh.total_num_indices > 0) {
-		topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
-	}
-
-	VkPipelineInputAssemblyStateCreateInfo input_assembly_state = {
-	    .sType =
-	        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
-	    .topology = topology,
-	    .primitiveRestartEnable = VK_FALSE,
-	};
-
-	VkPipelineRasterizationStateCreateInfo rasterization_state = {
-	    .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
-	    .depthClampEnable = VK_FALSE,
-	    .rasterizerDiscardEnable = VK_FALSE,
-	    .polygonMode = polygonMode,
-	    .cullMode = VK_CULL_MODE_BACK_BIT,
-	    .frontFace = VK_FRONT_FACE_CLOCKWISE,
-	    .lineWidth = 1.0f,
-	};
-
-	VkPipelineColorBlendAttachmentState blend_attachment_state = {
-	    .blendEnable = VK_FALSE,
-	    .colorWriteMask = 0xf,
-	};
-
-	VkPipelineColorBlendStateCreateInfo color_blend_state = {
-	    .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
-	    .attachmentCount = 1,
-	    .pAttachments = &blend_attachment_state,
-	};
-
-	VkPipelineDepthStencilStateCreateInfo depth_stencil_state = {
-	    .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
-	    .depthTestEnable = VK_TRUE,
-	    .depthWriteEnable = VK_TRUE,
-	    .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL,
-	    .front =
-	        {
-	            .compareOp = VK_COMPARE_OP_ALWAYS,
-	        },
-	    .back =
-	        {
-	            .compareOp = VK_COMPARE_OP_ALWAYS,
-	        },
-	};
-
-	VkPipelineViewportStateCreateInfo viewport_state = {
-	    .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
-	    .viewportCount = 1,
-	    .scissorCount = 1,
-	};
-
-	VkPipelineMultisampleStateCreateInfo multisample_state = {
-	    .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
-	    .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT};
-
-	VkDynamicState dynamic_states[] = {
-	    VK_DYNAMIC_STATE_VIEWPORT,
-	    VK_DYNAMIC_STATE_SCISSOR,
-	};
-
-	VkPipelineDynamicStateCreateInfo dynamic_state = {
-	    .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
-	    .dynamicStateCount = 2,
-	    .pDynamicStates = dynamic_states,
-	};
-
-
-	VkVertexInputBindingDescription vertex_input_binding_description;
-	VkVertexInputAttributeDescription
-	    vertex_input_attribute_descriptions[2];
-
-
-
-	/*
-	 * By default, we will generate positions and UVs for the full screen
-	 * quad from the gl_VertexIndex
-	 */
-	VkPipelineVertexInputStateCreateInfo vertex_input_state = {
-	    .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-	};
-	// clang-format off
-	vertex_input_attribute_descriptions[0].binding = d->render_texture_target_binding;
-	vertex_input_attribute_descriptions[0].location = 0;
-	vertex_input_attribute_descriptions[0].format = VK_FORMAT_R32G32B32A32_SFLOAT;
-	vertex_input_attribute_descriptions[0].offset = 0;
-
-	vertex_input_attribute_descriptions[1].binding = d->render_texture_target_binding;
-	vertex_input_attribute_descriptions[1].location = 1;
-	vertex_input_attribute_descriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
-	vertex_input_attribute_descriptions[1].offset = 16;
-
-	vertex_input_binding_description.binding = d->render_texture_target_binding;
-	vertex_input_binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
-	vertex_input_binding_description.stride = d->mesh.stride;
-
-	vertex_input_state.vertexAttributeDescriptionCount = 2;
-	vertex_input_state.pVertexAttributeDescriptions = vertex_input_attribute_descriptions;
-	vertex_input_state.vertexBindingDescriptionCount = 1;
-	vertex_input_state.pVertexBindingDescriptions = &vertex_input_binding_description;
-	// clang-format on
-
-	VkPipelineShaderStageCreateInfo shader_stages[2] = {
-	    {
-	        .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
-	        .stage = VK_SHADER_STAGE_VERTEX_BIT,
-	        .module = s->mesh_vert,
-	        .pName = "main",
-	    },
-	    {
-	        .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
-	        .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
-	        .module = s->mesh_frag,
-	        .pName = "main",
-	    },
-	};
-
-	VkGraphicsPipelineCreateInfo pipeline_info = {
-	    .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
-	    .stageCount = ARRAY_SIZE(shader_stages),
-	    .pStages = shader_stages,
-	    .pVertexInputState = &vertex_input_state,
-	    .pInputAssemblyState = &input_assembly_state,
-	    .pViewportState = &viewport_state,
-	    .pRasterizationState = &rasterization_state,
-	    .pMultisampleState = &multisample_state,
-	    .pDepthStencilState = &depth_stencil_state,
-	    .pColorBlendState = &color_blend_state,
-	    .pDynamicState = &dynamic_state,
-	    .layout = d->pipeline_layout,
-	    .renderPass = render_pass,
-	    .basePipelineHandle = VK_NULL_HANDLE,
-	    .basePipelineIndex = -1,
-	};
-
-	ret = vk->vkCreateGraphicsPipelines(vk->device, pipeline_cache, 1,
-	                                    &pipeline_info, NULL, &d->pipeline);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(d->vk, "vkCreateGraphicsPipelines failed %u!", ret);
-	}
-}
-
-static VkWriteDescriptorSet
-comp_distortion_get_uniform_write_descriptor_set(
-    struct comp_distortion *d,
-    uint32_t binding,
-    VkDescriptorSet descriptor_set,
-    struct comp_uniform_buffer *ubo_handle)
-{
-	return (VkWriteDescriptorSet){
-	    .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
-	    .dstSet = descriptor_set,
-	    .dstBinding = binding,
-	    .descriptorCount = 1,
-	    .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
-	    .pBufferInfo = &ubo_handle->descriptor,
-	};
-}
-
-
-static VkWriteDescriptorSet
-comp_distortion_get_image_write_descriptor_set(
-    VkDescriptorSet descriptor_set,
-    VkDescriptorImageInfo *descriptor_position,
-    uint32_t binding)
-{
-	return (VkWriteDescriptorSet){
-	    .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
-	    .dstSet = descriptor_set,
-	    .dstBinding = binding,
-	    .descriptorCount = 1,
-	    .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-	    .pImageInfo = descriptor_position,
-	};
-}
-
-static void
-comp_distortion_init_descriptor_sets(struct comp_distortion *d,
-                                     VkDescriptorPool descriptor_pool)
-{
-	struct vk_bundle *vk = d->vk;
-	VkResult ret;
-
-	VkDescriptorSetAllocateInfo alloc_info = {
-	    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
-	    .descriptorPool = descriptor_pool,
-	    .descriptorSetCount = 1,
-	    .pSetLayouts = &d->descriptor_set_layout,
-	};
-
-	for (uint32_t i = 0; i < 2; i++) {
-		ret = vk->vkAllocateDescriptorSets(d->vk->device, &alloc_info,
-		                                   &d->descriptor_sets[i]);
-		if (ret != VK_SUCCESS) {
-			VK_DEBUG(d->vk, "vkAllocateDescriptorSets failed %u",
-			         ret);
-		}
-	}
-}
-
-void
-comp_distortion_update_descriptor_set(struct comp_distortion *d,
-                                      VkSampler sampler,
-                                      VkImageView view,
-                                      uint32_t eye,
-                                      bool flip_y)
-{
-	struct vk_bundle *vk = d->vk;
-
-	VkDescriptorImageInfo image_info = {
-	    .sampler = sampler,
-	    .imageView = view,
-	    .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
-	};
-
-	VkWriteDescriptorSet write_descriptor_sets[] = {
-	    // Binding 0 : Render texture target
-	    comp_distortion_get_image_write_descriptor_set(
-	        d->descriptor_sets[eye], &image_info,
-	        d->render_texture_target_binding),
-	    comp_distortion_get_uniform_write_descriptor_set(
-	        d, d->ubo_viewport_binding, d->descriptor_sets[eye],
-	        &d->ubo_viewport_handles[eye]),
-	};
-
-	vk->vkUpdateDescriptorSets(vk->device,
-	                           ARRAY_SIZE(write_descriptor_sets),
-	                           write_descriptor_sets, 0, NULL);
-
-	d->ubo_vp_data[eye].flip_y = flip_y;
-	memcpy(d->ubo_viewport_handles[eye].mapped, &d->ubo_vp_data[eye],
-	       sizeof(d->ubo_vp_data[eye]));
-}
-
-static void
-comp_distortion_update_descriptor_sets(struct comp_distortion *d,
-                                       VkSampler samplers[2],
-                                       VkImageView views[2],
-                                       bool flip_y)
-{
-	for (uint32_t i = 0; i < 2; i++) {
-		comp_distortion_update_descriptor_set(d, samplers[i], views[i],
-		                                      i, flip_y);
-	}
-}
-
-static void
-comp_distortion_init_descriptor_set_layout(struct comp_distortion *d)
-{
-	struct vk_bundle *vk = d->vk;
-	VkResult ret;
-
-	VkDescriptorSetLayoutBinding set_layout_bindings[2] = {
-	    {
-	        .binding = d->render_texture_target_binding,
-	        .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-	        .descriptorCount = 1,
-	        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
-	    },
-	    {
-	        .binding = d->ubo_viewport_binding,
-	        .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
-	        .descriptorCount = 1,
-	        .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
-	    },
-	};
-
-	VkDescriptorSetLayoutCreateInfo set_layout_info = {
-	    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
-	    .bindingCount = ARRAY_SIZE(set_layout_bindings),
-	    .pBindings = set_layout_bindings,
-	};
-
-	ret = vk->vkCreateDescriptorSetLayout(d->vk->device, &set_layout_info,
-	                                      NULL, &d->descriptor_set_layout);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(d->vk, "vkCreateDescriptorSetLayout failed %u", ret);
-	}
-}
-
-static void
-comp_distortion_init_pipeline_layout(struct comp_distortion *d)
-{
-	struct vk_bundle *vk = d->vk;
-	VkResult ret;
-
-	VkPipelineLayoutCreateInfo pipeline_layout_info = {
-	    .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
-	    .setLayoutCount = 1,
-	    .pSetLayouts = &d->descriptor_set_layout,
-	};
-
-	ret = vk->vkCreatePipelineLayout(d->vk->device, &pipeline_layout_info,
-	                                 NULL, &d->pipeline_layout);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(d->vk, "Failed to create pipeline layout!");
-	}
-}
-
-void
-comp_distortion_draw_mesh(struct comp_distortion *d,
-                          VkCommandBuffer command_buffer,
-                          int eye)
-{
-	struct vk_bundle *vk = d->vk;
-
-
-	vk->vkCmdBindDescriptorSets(
-	    command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, d->pipeline_layout,
-	    0, 1, &d->descriptor_sets[eye], 0, NULL);
-	vk->vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
-	                      d->pipeline);
-
-	VkDeviceSize offsets[] = {0};
-	vk->vkCmdBindVertexBuffers(command_buffer, 0, 1,
-	                           &(d->vbo_handle.buffer), offsets);
-
-	if (d->mesh.total_num_indices > 0) {
-		vk->vkCmdBindIndexBuffer(command_buffer, d->index_handle.buffer,
-		                         0, VK_INDEX_TYPE_UINT32);
-
-		vk->vkCmdDrawIndexed(command_buffer, d->mesh.num_indices[eye],
-		                     1, d->mesh.offset_indices[eye], 0, 0);
-
-	} else {
-		vk->vkCmdDraw(command_buffer, d->mesh.num_vertices, 1, 0, 0);
-	}
-}
-
-// Update fragment shader hmd warp uniform block
-static void
-comp_distortion_update_uniform_buffer_warp(struct comp_distortion *d,
-                                           struct comp_compositor *c)
-{
-	/*
-	 * Common vertex shader stuff.
-	 */
-
-	// clang-format off
-	d->ubo_vp_data[0].rot = c->xdev->hmd->views[0].rot;
-	d->ubo_vp_data[1].rot = c->xdev->hmd->views[1].rot;
-
-	memcpy(d->ubo_viewport_handles[0].mapped, &d->ubo_vp_data[0], sizeof(d->ubo_vp_data[0]));
-	memcpy(d->ubo_viewport_handles[1].mapped, &d->ubo_vp_data[1], sizeof(d->ubo_vp_data[1]));
-	// clang-format on
-}
-
-static VkResult
-_create_buffer(struct vk_bundle *vk,
-               VkBufferUsageFlags usage_flags,
-               VkMemoryPropertyFlags memory_property_flags,
-               struct comp_uniform_buffer *buffer,
-               VkDeviceSize size,
-               void *data)
-{
-	buffer->device = vk->device;
-	VkResult ret;
-
-	// Create the buffer handle.
-	VkBufferCreateInfo buffer_info = {
-	    .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
-	    .size = size,
-	    .usage = usage_flags,
-	};
-	ret =
-	    vk->vkCreateBuffer(vk->device, &buffer_info, NULL, &buffer->buffer);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to create buffer!");
-		return ret;
-	}
-
-	// Create the memory backing up the buffer handle.
-	VkMemoryRequirements mem_reqs;
-	vk->vkGetBufferMemoryRequirements(vk->device, buffer->buffer,
-	                                  &mem_reqs);
-
-	// Find a memory type index that fits the properties of the buffer.
-	uint32_t memory_type_index = 0;
-	vk_get_memory_type(vk, mem_reqs.memoryTypeBits, memory_property_flags,
-	                   &memory_type_index);
-
-	VkMemoryAllocateInfo mem_alloc = {
-	    .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
-	    .allocationSize = mem_reqs.size,
-	    .memoryTypeIndex = memory_type_index,
-	};
-
-	ret =
-	    vk->vkAllocateMemory(vk->device, &mem_alloc, NULL, &buffer->memory);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to allocate memory!");
-		goto err_buffer;
-	}
-
-	buffer->alignment = mem_reqs.alignment;
-	buffer->size = mem_alloc.allocationSize;
-	buffer->usageFlags = usage_flags;
-	buffer->memoryPropertyFlags = memory_property_flags;
-
-	// If a pointer to the buffer data has been passed, map the
-	// buffer and copy over the data
-	if (data != NULL) {
-		ret = _buffer_map(vk, buffer, VK_WHOLE_SIZE, 0);
-		if (ret != VK_SUCCESS) {
-			VK_DEBUG(vk, "Failed to map buffer!");
-			goto err_memory;
-		}
-
-		memcpy(buffer->mapped, data, size);
-		_buffer_unmap(vk, buffer);
-	}
-
-	// Initialize a default descriptor that covers the whole buffer size
-	_buffer_setup_descriptor(vk, buffer, VK_WHOLE_SIZE, 0);
-
-	// Attach the memory to the buffer object
-	ret = vk->vkBindBufferMemory(vk->device, buffer->buffer, buffer->memory,
-	                             0);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to bind buffer to memory!");
-		goto err_memory;
-	}
-
-	return VK_SUCCESS;
-
-
-err_memory:
-	vk->vkFreeMemory(vk->device, buffer->memory, NULL);
-
-err_buffer:
-	vk->vkDestroyBuffer(vk->device, buffer->buffer, NULL);
-
-	return ret;
-}
-
-static void
-comp_distortion_init_buffers(struct comp_distortion *d,
-                             struct comp_compositor *c)
-{
-	struct vk_bundle *vk = &c->vk;
-	VkMemoryPropertyFlags memory_property_flags = 0;
-	VkBufferUsageFlags ubo_usage_flags = 0;
-	VkBufferUsageFlags vbo_usage_flags = 0;
-	VkBufferUsageFlags index_usage_flags = 0;
-
-	VkResult ret;
-
-	// Using the same flags for all ubos and vbos uniform buffers.
-	ubo_usage_flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
-	vbo_usage_flags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
-	index_usage_flags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
-	memory_property_flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
-	memory_property_flags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
-
-	// Distortion ubo and vbo sizes.
-	VkDeviceSize vbo_size = d->mesh.stride * d->mesh.num_vertices;
-	VkDeviceSize index_size = sizeof(int) * d->mesh.total_num_indices;
-
-	// vp ubo[0]
-	ret = _create_buffer(vk, ubo_usage_flags, memory_property_flags,
-	                     &d->ubo_viewport_handles[0],
-	                     sizeof(d->ubo_vp_data[0]), NULL);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to create vp ubo buffer[0]!");
-	}
-	ret = _buffer_map(vk, &d->ubo_viewport_handles[0], VK_WHOLE_SIZE, 0);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to map vp ubo buffer[0]!");
-	}
-
-	// vp ubo[1]
-	ret = _create_buffer(vk, ubo_usage_flags, memory_property_flags,
-	                     &d->ubo_viewport_handles[1],
-	                     sizeof(d->ubo_vp_data[1]), NULL);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to create vp ubo buffer[1]!");
-	}
-	ret = _buffer_map(vk, &d->ubo_viewport_handles[1], VK_WHOLE_SIZE, 0);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to map vp ubo buffer[1]!");
-	}
-
-	// Don't create vbo if size is zero.
-	if (vbo_size == 0) {
-		return;
-	}
-
-	ret = _create_buffer(vk, vbo_usage_flags, memory_property_flags,
-	                     &d->vbo_handle, vbo_size, d->mesh.vertices);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to create mesh vbo buffer!");
-	}
-	ret = _buffer_map(vk, &d->vbo_handle, vbo_size, 0);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to map mesh vbo buffer!");
-	}
-
-	if (index_size == 0) {
-		return;
-	}
-
-	ret = _create_buffer(vk, index_usage_flags, memory_property_flags,
-	                     &d->index_handle, index_size, d->mesh.indices);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to create mesh index buffer!");
-	}
-	ret = _buffer_map(vk, &d->index_handle, index_size, 0);
-	if (ret != VK_SUCCESS) {
-		VK_DEBUG(vk, "Failed to map mesh vbo buffer!");
-	}
-}
diff --git a/src/xrt/compositor/main/comp_distortion.h b/src/xrt/compositor/main/comp_distortion.h
deleted file mode 100644
index 644cbbc21..000000000
--- a/src/xrt/compositor/main/comp_distortion.h
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2019, Collabora, Ltd.
-// SPDX-License-Identifier: BSL-1.0
-/*!
- * @file
- * @brief  Distortion shader code header.
- * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
- * @author Jakob Bornecrantz <jakob@collabora.com>
- * @ingroup comp_main
- */
-
-#pragma once
-
-#include "main/comp_settings.h"
-#include "main/comp_compositor.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
- *
- * Structs
- *
- */
-
-
-/*!
- * Helper buffer for a single uniform buffer.
- *
- * @ingroup comp_main
- */
-struct comp_uniform_buffer
-{
-	VkDevice device;
-	VkBuffer buffer;
-	VkDeviceMemory memory;
-	VkDescriptorBufferInfo descriptor;
-	VkDeviceSize size;
-	VkDeviceSize alignment;
-	void *mapped;
-	VkBufferUsageFlags usageFlags;
-	VkMemoryPropertyFlags memoryPropertyFlags;
-};
-
-/*!
- * Helper struct that encapsulate a distortion rendering code.
- *
- * @ingroup comp_main
- */
-struct comp_distortion
-{
-	// Holds all of the needed common Vulkan things.
-	struct vk_bundle *vk;
-
-	struct comp_uniform_buffer vbo_handle;
-	struct comp_uniform_buffer index_handle;
-	struct comp_uniform_buffer ubo_viewport_handles[2];
-	uint32_t ubo_viewport_binding;
-
-	struct
-	{
-		float *vertices;
-		int *indices;
-		size_t stride;
-		size_t num_vertices;
-		size_t num_indices[2];
-		size_t offset_indices[2];
-		size_t total_num_indices;
-	} mesh;
-
-	struct
-	{
-		struct xrt_matrix_2x2 rot;
-		bool flip_y;
-	} ubo_vp_data[2];
-
-	VkPipelineLayout pipeline_layout;
-	VkPipeline pipeline;
-
-	VkDescriptorSetLayout descriptor_set_layout;
-	VkDescriptorSet descriptor_sets[2];
-	uint32_t render_texture_target_binding;
-
-	bool quirk_draw_lines;
-};
-
-
-/*
- *
- * Functions.
- *
- */
-
-/*!
- * Init a distortion, pass in the distortion so it can be embedded in a struct.
- *
- * @ingroup comp_main
- */
-void
-comp_distortion_init(struct comp_distortion *d,
-                     struct comp_compositor *c,
-                     VkRenderPass render_pass,
-                     VkPipelineCache pipeline_cache,
-                     struct xrt_hmd_parts *parts,
-                     VkDescriptorPool descriptor_pool);
-
-/*!
- * Free and destroy all fields, does not free the destortion itself.
- *
- * @ingroup comp_main
- */
-void
-comp_distortion_destroy(struct comp_distortion *d);
-
-/*!
- * Update the descriptor set to a new image.
- *
- * @ingroup comp_main
- */
-void
-comp_distortion_update_descriptor_set(struct comp_distortion *d,
-                                      VkSampler sampler,
-                                      VkImageView view,
-                                      uint32_t eye,
-                                      bool flip_y);
-
-void
-comp_distortion_draw_mesh(struct comp_distortion *d,
-                          VkCommandBuffer command_buffer,
-                          int eye);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c
index cb656ba62..81b31316e 100644
--- a/src/xrt/compositor/main/comp_renderer.c
+++ b/src/xrt/compositor/main/comp_renderer.c
@@ -15,7 +15,6 @@
 #include "util/u_misc.h"
 #include "util/u_distortion_mesh.h"
 
-#include "main/comp_distortion.h"
 #include "main/comp_layer_renderer.h"
 #include "math/m_api.h"
 
@@ -42,9 +41,6 @@ struct comp_renderer
 	uint32_t current_buffer;
 
 	VkQueue queue;
-	VkRenderPass render_pass;
-	VkDescriptorPool descriptor_pool;
-	VkPipelineCache pipeline_cache;
 
 	struct
 	{
@@ -52,14 +48,12 @@ struct comp_renderer
 		VkSemaphore render_complete;
 	} semaphores;
 
-	VkCommandBuffer *cmd_buffers;
-	VkFramebuffer *frame_buffers;
+	struct comp_rendering *rrs;
 	VkFence *fences;
 	uint32_t num_buffers;
 
 	struct comp_compositor *c;
 	struct comp_settings *settings;
-	struct comp_distortion *distortion;
 
 	struct comp_layer_renderer *lr;
 };
@@ -81,30 +75,13 @@ static void
 renderer_submit_queue(struct comp_renderer *r);
 
 static void
-renderer_build_command_buffers(struct comp_renderer *r);
+renderer_build_renderings(struct comp_renderer *r);
 
 static void
-renderer_build_command_buffer(struct comp_renderer *r,
-                              VkCommandBuffer command_buffer,
-                              VkFramebuffer framebuffer);
+renderer_allocate_renderings(struct comp_renderer *r);
 
 static void
-renderer_init_descriptor_pool(struct comp_renderer *r);
-
-static void
-renderer_create_frame_buffer(struct comp_renderer *r,
-                             VkFramebuffer *frame_buffer,
-                             uint32_t num_attachements,
-                             VkImageView *attachments);
-
-static void
-renderer_allocate_command_buffers(struct comp_renderer *r);
-
-static void
-renderer_destroy_command_buffers(struct comp_renderer *r);
-
-static void
-renderer_create_pipeline_cache(struct comp_renderer *r);
+renderer_close_renderings(struct comp_renderer *r);
 
 static void
 renderer_init_semaphores(struct comp_renderer *r);
@@ -112,12 +89,6 @@ renderer_init_semaphores(struct comp_renderer *r);
 static void
 renderer_resize(struct comp_renderer *r);
 
-static void
-renderer_create_frame_buffers(struct comp_renderer *r);
-
-static void
-renderer_create_render_pass(struct comp_renderer *r);
-
 static void
 renderer_acquire_swapchain_image(struct comp_renderer *r);
 
@@ -166,15 +137,10 @@ renderer_create(struct comp_renderer *r, struct comp_compositor *c)
 
 	r->current_buffer = 0;
 	r->queue = VK_NULL_HANDLE;
-	r->render_pass = VK_NULL_HANDLE;
-	r->descriptor_pool = VK_NULL_HANDLE;
-	r->pipeline_cache = VK_NULL_HANDLE;
 	r->semaphores.present_complete = VK_NULL_HANDLE;
 	r->semaphores.render_complete = VK_NULL_HANDLE;
 
-	r->distortion = NULL;
-	r->cmd_buffers = NULL;
-	r->frame_buffers = NULL;
+	r->rrs = NULL;
 }
 
 static void
@@ -202,7 +168,7 @@ renderer_submit_queue(struct comp_renderer *r)
 	    .pWaitSemaphores = &r->semaphores.present_complete,
 	    .pWaitDstStageMask = stage_flags,
 	    .commandBufferCount = 1,
-	    .pCommandBuffers = &r->cmd_buffers[r->current_buffer],
+	    .pCommandBuffers = &r->rrs[r->current_buffer].cmd,
 	    .signalSemaphoreCount = 1,
 	    .pSignalSemaphores = &r->semaphores.render_complete,
 	};
@@ -215,151 +181,106 @@ renderer_submit_queue(struct comp_renderer *r)
 }
 
 static void
-renderer_build_command_buffers(struct comp_renderer *r)
+renderer_build_rendering(struct comp_renderer *r,
+                         struct comp_rendering *rr,
+                         uint32_t index)
 {
-	for (uint32_t i = 0; i < r->num_buffers; ++i)
-		renderer_build_command_buffer(r, r->cmd_buffers[i],
-		                              r->frame_buffers[i]);
-}
-
-static void
-renderer_set_viewport_scissor(float scale_x,
-                              float scale_y,
-                              VkViewport *v,
-                              VkRect2D *s,
-                              struct xrt_view *view)
-{
-	s->offset.x = (int32_t)(view->viewport.x_pixels * scale_x);
-	s->offset.y = (int32_t)(view->viewport.y_pixels * scale_y);
-	s->extent.width = (uint32_t)(view->viewport.w_pixels * scale_x);
-	s->extent.height = (uint32_t)(view->viewport.h_pixels * scale_y);
-
-	v->x = s->offset.x;
-	v->y = s->offset.y;
-	v->width = s->extent.width;
-	v->height = s->extent.height;
-}
-
-static void
-renderer_build_command_buffer(struct comp_renderer *r,
-                              VkCommandBuffer command_buffer,
-                              VkFramebuffer framebuffer)
-{
-	struct vk_bundle *vk = &r->c->vk;
-	VkResult ret;
-
-	VkClearValue clear_color = {
-	    .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}}};
-
-	VkCommandBufferBeginInfo command_buffer_info = {
-	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
-	};
-
-	ret = vk->vkBeginCommandBuffer(command_buffer, &command_buffer_info);
-	if (ret != VK_SUCCESS) {
-		COMP_ERROR(r->c, "vkBeginCommandBuffer: %s",
-		           vk_result_string(ret));
-		return;
-	}
-
-	VkRenderPassBeginInfo render_pass_begin_info = {
-	    .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-	    .renderPass = r->render_pass,
-	    .framebuffer = framebuffer,
-	    .renderArea =
-	        {
-	            .offset =
-	                {
-	                    .x = 0,
-	                    .y = 0,
-	                },
-	            .extent =
-	                {
-	                    .width = r->c->current.width,
-	                    .height = r->c->current.height,
-	                },
-	        },
-	    .clearValueCount = 1,
-	    .pClearValues = &clear_color,
-	};
-	vk->vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info,
-	                         VK_SUBPASS_CONTENTS_INLINE);
+	struct comp_compositor *c = r->c;
 
+	struct comp_target_data data;
+	data.format = r->c->window->swapchain.surface_format.format;
+	data.is_external = true;
+	data.width = r->c->current.width;
+	data.height = r->c->current.height;
 
 	// clang-format off
-	float scale_x = (float)r->c->current.width /
-	                (float)r->c->xdev->hmd->screens[0].w_pixels;
-	float scale_y = (float)r->c->current.height /
-	                (float)r->c->xdev->hmd->screens[0].h_pixels;
+	float scale_x = (float)r->c->current.width / (float)r->c->xdev->hmd->screens[0].w_pixels;
+	float scale_y = (float)r->c->current.height / (float)r->c->xdev->hmd->screens[0].h_pixels;
 	// clang-format on
 
-	VkViewport viewport = {
-	    .x = 0,
-	    .y = 0,
-	    .width = 0,
-	    .height = 0,
-	    .minDepth = 0.0f,
-	    .maxDepth = 1.0f,
+	struct xrt_view *l_v = &r->c->xdev->hmd->views[0];
+	struct comp_viewport_data l_viewport_data = {
+	    .x = (uint32_t)(l_v->viewport.x_pixels * scale_x),
+	    .y = (uint32_t)(l_v->viewport.y_pixels * scale_y),
+	    .w = (uint32_t)(l_v->viewport.w_pixels * scale_x),
+	    .h = (uint32_t)(l_v->viewport.h_pixels * scale_y),
+	};
+	struct comp_mesh_ubo_data l_data = {
+	    .rot = l_v->rot,
+	    .flip_y = false,
 	};
 
-	VkRect2D scissor = {
-	    .offset = {.x = 0, .y = 0},
-	    .extent = {.width = 0, .height = 0},
+	struct xrt_view *r_v = &r->c->xdev->hmd->views[1];
+	struct comp_viewport_data r_viewport_data = {
+	    .x = (uint32_t)(r_v->viewport.x_pixels * scale_x),
+	    .y = (uint32_t)(r_v->viewport.y_pixels * scale_y),
+	    .w = (uint32_t)(r_v->viewport.w_pixels * scale_x),
+	    .h = (uint32_t)(r_v->viewport.h_pixels * scale_y),
+	};
+	struct comp_mesh_ubo_data r_data = {
+	    .rot = r_v->rot,
+	    .flip_y = false,
 	};
 
-	renderer_set_viewport_scissor(scale_x, scale_y, &viewport, &scissor,
-	                              &r->c->xdev->hmd->views[0]);
-	vk->vkCmdSetViewport(command_buffer, 0, 1, &viewport);
-	vk->vkCmdSetScissor(command_buffer, 0, 1, &scissor);
+
+	/*
+	 * Init
+	 */
+
+	comp_rendering_init(c, &c->nr, rr);
+
+	comp_draw_begin_target_single(
+	    rr,                                          //
+	    r->c->window->swapchain.buffers[index].view, //
+	    &data);                                      //
 
 
-	// Mesh distortion
-	comp_distortion_draw_mesh(r->distortion, command_buffer, 0);
-	renderer_set_viewport_scissor(scale_x, scale_y, &viewport, &scissor,
-	                              &r->c->xdev->hmd->views[1]);
-	vk->vkCmdSetViewport(command_buffer, 0, 1, &viewport);
-	vk->vkCmdSetScissor(command_buffer, 0, 1, &scissor);
-	comp_distortion_draw_mesh(r->distortion, command_buffer, 1);
+	/*
+	 * Viewport one
+	 */
 
-	vk->vkCmdEndRenderPass(command_buffer);
+	comp_draw_begin_view(rr,                //
+	                     0,                 // target_index
+	                     0,                 // view_index
+	                     &l_viewport_data); // viewport_data
 
-	ret = vk->vkEndCommandBuffer(command_buffer);
-	if (ret != VK_SUCCESS) {
-		COMP_ERROR(r->c, "vkEndCommandBuffer: %s",
-		           vk_result_string(ret));
-		return;
-	}
+	comp_draw_distortion(rr,                             //
+	                     r->lr->framebuffers[0].sampler, //
+	                     r->lr->framebuffers[0].view,    //
+	                     &l_data);                       //
+
+	comp_draw_end_view(rr);
+
+
+	/*
+	 * Viewport two
+	 */
+
+	comp_draw_begin_view(rr,                //
+	                     0,                 // target_index
+	                     1,                 // view_index
+	                     &r_viewport_data); // viewport_data
+
+	comp_draw_distortion(rr,                             //
+	                     r->lr->framebuffers[1].sampler, //
+	                     r->lr->framebuffers[1].view,    //
+	                     &r_data);                       //
+
+	comp_draw_end_view(rr);
+
+
+	/*
+	 * End
+	 */
+
+	comp_draw_end_target(rr);
 }
 
 static void
-renderer_init_descriptor_pool(struct comp_renderer *r)
+renderer_build_renderings(struct comp_renderer *r)
 {
-	struct vk_bundle *vk = &r->c->vk;
-	VkResult ret;
-
-	VkDescriptorPoolSize pool_sizes[2] = {
-	    {
-	        .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
-	        .descriptorCount = 4,
-	    },
-	    {
-	        .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-	        .descriptorCount = 2,
-	    },
-	};
-
-	VkDescriptorPoolCreateInfo descriptor_pool_info = {
-	    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
-	    .maxSets = 2,
-	    .poolSizeCount = ARRAY_SIZE(pool_sizes),
-	    .pPoolSizes = pool_sizes,
-	};
-
-	ret = vk->vkCreateDescriptorPool(vk->device, &descriptor_pool_info,
-	                                 NULL, &r->descriptor_pool);
-	if (ret != VK_SUCCESS) {
-		COMP_ERROR(r->c, "vkCreateDescriptorPool: %s",
-		           vk_result_string(ret));
+	for (uint32_t i = 0; i < r->num_buffers; ++i) {
+		renderer_build_rendering(r, &r->rrs[i], i);
 	}
 }
 
@@ -431,28 +352,11 @@ renderer_init(struct comp_renderer *r)
 	vk->vkGetDeviceQueue(vk->device, r->c->vk.queue_family_index, 0,
 	                     &r->queue);
 	renderer_init_semaphores(r);
-	renderer_create_pipeline_cache(r);
-	renderer_create_render_pass(r);
-
 	assert(r->c->window->swapchain.image_count > 0);
 
 	r->num_buffers = r->c->window->swapchain.image_count;
 
 	renderer_create_fences(r);
-	renderer_create_frame_buffers(r);
-	renderer_allocate_command_buffers(r);
-
-	renderer_init_descriptor_pool(r);
-
-	r->distortion = U_TYPED_CALLOC(struct comp_distortion);
-
-	bool has_meshuv = (r->c->xdev->hmd->distortion.models &
-	                   XRT_DISTORTION_MODEL_MESHUV) != 0;
-	assert(has_meshuv);
-
-	comp_distortion_init(r->distortion, r->c, r->render_pass,
-	                     r->pipeline_cache, r->c->xdev->hmd,
-	                     r->descriptor_pool);
 
 	VkExtent2D extent = {
 	    .width = r->c->xdev->hmd->screens[0].w_pixels,
@@ -462,13 +366,8 @@ renderer_init(struct comp_renderer *r)
 	r->lr = comp_layer_renderer_create(vk, &r->c->shaders, extent,
 	                                   VK_FORMAT_B8G8R8A8_SRGB);
 
-	for (uint32_t i = 0; i < 2; i++) {
-		comp_distortion_update_descriptor_set(
-		    r->distortion, r->lr->framebuffers[i].sampler,
-		    r->lr->framebuffers[i].view, i, false);
-	}
-
-	renderer_build_command_buffers(r);
+	renderer_allocate_renderings(r);
+	renderer_build_renderings(r);
 }
 
 VkImageView
@@ -624,38 +523,8 @@ comp_renderer_draw(struct comp_renderer *r)
 }
 
 static void
-renderer_create_frame_buffer(struct comp_renderer *r,
-                             VkFramebuffer *frame_buffer,
-                             uint32_t num_attachements,
-                             VkImageView *attachments)
+renderer_allocate_renderings(struct comp_renderer *r)
 {
-	struct vk_bundle *vk = &r->c->vk;
-	VkResult ret;
-
-	VkFramebufferCreateInfo frame_buffer_info = {
-	    .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
-	    .renderPass = r->render_pass,
-	    .attachmentCount = num_attachements,
-	    .pAttachments = attachments,
-	    .width = r->c->current.width,
-	    .height = r->c->current.height,
-	    .layers = 1,
-	};
-
-	ret = vk->vkCreateFramebuffer(vk->device, &frame_buffer_info, NULL,
-	                              frame_buffer);
-	if (ret != VK_SUCCESS) {
-		COMP_ERROR(r->c, "vkCreateFramebuffer: %s",
-		           vk_result_string(ret));
-	}
-}
-
-static void
-renderer_allocate_command_buffers(struct comp_renderer *r)
-{
-	struct vk_bundle *vk = &r->c->vk;
-	VkResult ret;
-
 	if (r->num_buffers == 0) {
 		COMP_ERROR(r->c, "Requested 0 command buffers.");
 		return;
@@ -663,50 +532,22 @@ renderer_allocate_command_buffers(struct comp_renderer *r)
 
 	COMP_DEBUG(r->c, "Allocating %d Command Buffers.", r->num_buffers);
 
-	if (r->cmd_buffers != NULL)
-		free(r->cmd_buffers);
-
-	r->cmd_buffers = U_TYPED_ARRAY_CALLOC(VkCommandBuffer, r->num_buffers);
-
-	VkCommandBufferAllocateInfo cmd_buffer_info = {
-	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
-	    .commandPool = vk->cmd_pool,
-	    .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
-	    .commandBufferCount = r->num_buffers,
-	};
-
-	ret = vk->vkAllocateCommandBuffers(vk->device, &cmd_buffer_info,
-	                                   r->cmd_buffers);
-	if (ret != VK_SUCCESS) {
-		COMP_ERROR(r->c, "vkCreateFramebuffer: %s",
-		           vk_result_string(ret));
+	if (r->rrs != NULL) {
+		free(r->rrs);
 	}
+
+	r->rrs = U_TYPED_ARRAY_CALLOC(struct comp_rendering, r->num_buffers);
 }
 
 static void
-renderer_destroy_command_buffers(struct comp_renderer *r)
+renderer_close_renderings(struct comp_renderer *r)
 {
-	struct vk_bundle *vk = &r->c->vk;
-
-	vk->vkFreeCommandBuffers(vk->device, vk->cmd_pool, r->num_buffers,
-	                         r->cmd_buffers);
-}
-
-static void
-renderer_create_pipeline_cache(struct comp_renderer *r)
-{
-	struct vk_bundle *vk = &r->c->vk;
-	VkResult ret;
-
-	VkPipelineCacheCreateInfo pipeline_cache_info = {
-	    .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
-	};
-	ret = vk->vkCreatePipelineCache(vk->device, &pipeline_cache_info, NULL,
-	                                &r->pipeline_cache);
-	if (ret != VK_SUCCESS) {
-		COMP_ERROR(r->c, "vkCreatePipelineCache: %s",
-		           vk_result_string(ret));
+	for (uint32_t i = 0; i < r->num_buffers; i++) {
+		comp_rendering_close(&r->rrs[i]);
 	}
+
+	free(r->rrs);
+	r->rrs = NULL;
 }
 
 static void
@@ -752,99 +593,12 @@ renderer_resize(struct comp_renderer *r)
 	                    r->settings->color_space,
 	                    r->settings->present_mode);
 
-	for (uint32_t i = 0; i < r->num_buffers; i++)
-		vk->vkDestroyFramebuffer(vk->device, r->frame_buffers[i], NULL);
-	renderer_destroy_command_buffers(r);
+	renderer_close_renderings(r);
 
 	r->num_buffers = r->c->window->swapchain.image_count;
 
-	renderer_create_frame_buffers(r);
-	renderer_allocate_command_buffers(r);
-	renderer_build_command_buffers(r);
-}
-
-static void
-renderer_create_frame_buffers(struct comp_renderer *r)
-{
-	if (r->frame_buffers != NULL)
-		free(r->frame_buffers);
-
-	r->frame_buffers = U_TYPED_ARRAY_CALLOC(VkFramebuffer, r->num_buffers);
-
-	for (uint32_t i = 0; i < r->num_buffers; i++) {
-		VkImageView attachments[1] = {
-		    r->c->window->swapchain.buffers[i].view,
-		};
-		renderer_create_frame_buffer(r, &r->frame_buffers[i],
-		                             ARRAY_SIZE(attachments),
-		                             attachments);
-	}
-}
-
-static void
-renderer_create_render_pass(struct comp_renderer *r)
-{
-	struct vk_bundle *vk = &r->c->vk;
-	VkResult ret;
-
-	VkAttachmentDescription attachments[1] = {
-	    (VkAttachmentDescription){
-	        .format = r->c->window->swapchain.surface_format.format,
-	        .samples = VK_SAMPLE_COUNT_1_BIT,
-	        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
-	        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
-	        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
-	        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
-	        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
-	        .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
-	    },
-	};
-
-	VkAttachmentReference color_reference = {
-	    .attachment = 0,
-	    .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
-	};
-
-	VkSubpassDescription subpass_description = {
-	    .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
-	    .inputAttachmentCount = 0,
-	    .pInputAttachments = NULL,
-	    .colorAttachmentCount = 1,
-	    .pColorAttachments = &color_reference,
-	    .pResolveAttachments = NULL,
-	    .pDepthStencilAttachment = NULL,
-	    .preserveAttachmentCount = 0,
-	    .pPreserveAttachments = NULL,
-	};
-
-	VkSubpassDependency dependencies[1] = {
-	    (VkSubpassDependency){
-	        .srcSubpass = VK_SUBPASS_EXTERNAL,
-	        .dstSubpass = 0,
-	        .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
-	        .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
-	        .srcAccessMask = 0,
-	        .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
-	                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
-	    },
-	};
-
-	VkRenderPassCreateInfo render_pass_info = {
-	    .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
-	    .attachmentCount = ARRAY_SIZE(attachments),
-	    .pAttachments = attachments,
-	    .subpassCount = 1,
-	    .pSubpasses = &subpass_description,
-	    .dependencyCount = ARRAY_SIZE(dependencies),
-	    .pDependencies = dependencies,
-	};
-
-	ret = vk->vkCreateRenderPass(vk->device, &render_pass_info, NULL,
-	                             &r->render_pass);
-	if (ret != VK_SUCCESS) {
-		COMP_ERROR(r->c, "vkCreateRenderPass: %s",
-		           vk_result_string(ret));
-	}
+	renderer_allocate_renderings(r);
+	renderer_build_renderings(r);
 }
 
 static void
@@ -896,54 +650,19 @@ renderer_destroy(struct comp_renderer *r)
 {
 	struct vk_bundle *vk = &r->c->vk;
 
-	// Distortion
-	if (r->distortion != NULL) {
-		comp_distortion_destroy(r->distortion);
-		r->distortion = NULL;
-	}
-
-	// Discriptor pool
-	if (r->descriptor_pool != VK_NULL_HANDLE) {
-		vk->vkDestroyDescriptorPool(vk->device, r->descriptor_pool,
-		                            NULL);
-		r->descriptor_pool = VK_NULL_HANDLE;
-	}
-
 	// Fences
 	for (uint32_t i = 0; i < r->num_buffers; i++)
 		vk->vkDestroyFence(vk->device, r->fences[i], NULL);
 	free(r->fences);
 
 	// Command buffers
-	renderer_destroy_command_buffers(r);
-	if (r->cmd_buffers != NULL)
-		free(r->cmd_buffers);
-
-	// Render pass
-	if (r->render_pass != VK_NULL_HANDLE) {
-		vk->vkDestroyRenderPass(vk->device, r->render_pass, NULL);
-		r->render_pass = VK_NULL_HANDLE;
+	renderer_close_renderings(r);
+	if (r->rrs != NULL) {
+		free(r->rrs);
 	}
 
-	// Frame buffers
-	for (uint32_t i = 0; i < r->num_buffers; i++) {
-		if (r->frame_buffers[i] != VK_NULL_HANDLE) {
-			vk->vkDestroyFramebuffer(vk->device,
-			                         r->frame_buffers[i], NULL);
-			r->frame_buffers[i] = VK_NULL_HANDLE;
-		}
-	}
-	if (r->frame_buffers != NULL)
-		free(r->frame_buffers);
-	r->frame_buffers = NULL;
 	r->num_buffers = 0;
 
-	// Pipeline cache
-	if (r->pipeline_cache != VK_NULL_HANDLE) {
-		vk->vkDestroyPipelineCache(vk->device, r->pipeline_cache, NULL);
-		r->pipeline_cache = VK_NULL_HANDLE;
-	}
-
 	// Semaphores
 	if (r->semaphores.present_complete != VK_NULL_HANDLE) {
 		vk->vkDestroySemaphore(vk->device,
diff --git a/src/xrt/compositor/meson.build b/src/xrt/compositor/meson.build
index 5efcd278e..5535c778c 100644
--- a/src/xrt/compositor/meson.build
+++ b/src/xrt/compositor/meson.build
@@ -15,8 +15,6 @@ compositor_srcs = [
 	'client/comp_vk_glue.c',
 	'main/comp_compositor.c',
 	'main/comp_compositor.h',
-	'main/comp_distortion.c',
-	'main/comp_distortion.h',
 	'main/comp_documentation.h',
 	'main/comp_renderer.c',
 	'main/comp_renderer.h',
@@ -29,6 +27,10 @@ compositor_srcs = [
 	'main/comp_window.h',
 	'main/comp_layer_renderer.c',
 	'main/comp_layer.c',
+	'render/comp_buffer.c',
+	'render/comp_render.h',
+	'render/comp_rendering.c',
+	'render/comp_resources.c',
 ]
 
 compile_args = []
diff --git a/src/xrt/compositor/render/comp_buffer.c b/src/xrt/compositor/render/comp_buffer.c
new file mode 100644
index 000000000..f40c112eb
--- /dev/null
+++ b/src/xrt/compositor/render/comp_buffer.c
@@ -0,0 +1,222 @@
+// Copyright 2019-2020, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Buffer functions.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_main
+ */
+
+#include "main/comp_compositor.h"
+
+#include "render/comp_render.h"
+
+#include <stdio.h>
+
+
+/*
+ *
+ * Common helpers.
+ *
+ */
+
+static VkResult
+create_buffer(struct vk_bundle *vk,
+              VkBufferUsageFlags usage_flags,
+              VkMemoryPropertyFlags memory_property_flags,
+              VkDeviceSize size,
+              VkBuffer *out_buffer,
+              VkDeviceMemory *out_memory,
+              VkDeviceSize *out_alignment,
+              VkDeviceSize *out_allocation_size)
+{
+	VkResult ret;
+
+	// Create the buffer handle.
+	VkBufferCreateInfo buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+	    .size = size,
+	    .usage = usage_flags,
+	};
+
+	VkBuffer buffer = VK_NULL_HANDLE;
+	ret = vk->vkCreateBuffer(vk->device,   //
+	                         &buffer_info, //
+	                         NULL,         //
+	                         &buffer);     //
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateBuffer failed: '%s'",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	// Create the memory backing up the buffer handle.
+	VkMemoryRequirements mem_reqs;
+	vk->vkGetBufferMemoryRequirements(vk->device, //
+	                                  buffer,     //
+	                                  &mem_reqs); //
+
+	// Find a memory type index that fits the properties of the buffer.
+	uint32_t memory_type_index = 0;
+	vk_get_memory_type(vk,                      //
+	                   mem_reqs.memoryTypeBits, //
+	                   memory_property_flags,   //
+	                   &memory_type_index);     //
+
+	VkMemoryAllocateInfo mem_alloc = {
+	    .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+	    .allocationSize = mem_reqs.size,
+	    .memoryTypeIndex = memory_type_index,
+	};
+
+	VkDeviceMemory memory = VK_NULL_HANDLE;
+	ret = vk->vkAllocateMemory(vk->device, //
+	                           &mem_alloc, //
+	                           NULL,       //
+	                           &memory);   //
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkAllocateMemory failed: '%s'",
+		         vk_result_string(ret));
+		goto err_buffer;
+	}
+
+
+	// Attach the memory to the buffer object
+	ret = vk->vkBindBufferMemory(vk->device, //
+	                             buffer,     // buffer
+	                             memory,     // memory
+	                             0);         // memoryOffset
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkBindBufferMemory failed: '%s'",
+		         vk_result_string(ret));
+		goto err_memory;
+	}
+
+	*out_memory = memory;
+	*out_buffer = buffer;
+	*out_alignment = mem_reqs.alignment;
+	*out_allocation_size = mem_alloc.allocationSize;
+
+	return VK_SUCCESS;
+
+
+err_memory:
+	vk->vkFreeMemory(vk->device, memory, NULL);
+
+err_buffer:
+	vk->vkDestroyBuffer(vk->device, buffer, NULL);
+
+	return ret;
+}
+
+
+/*
+ *
+ * 'Exported' functions.
+ *
+ */
+
+VkResult
+comp_buffer_init(struct vk_bundle *vk,
+                 struct comp_buffer *buffer,
+                 VkBufferUsageFlags usage_flags,
+                 VkMemoryPropertyFlags memory_property_flags,
+                 VkDeviceSize size)
+{
+	return create_buffer(vk,                        //
+	                     usage_flags,               // usage_flags
+	                     memory_property_flags,     // memory_property_flags
+	                     size,                      // size
+	                     &buffer->buffer,           // out_buffer
+	                     &buffer->memory,           // out_memory
+	                     &buffer->alignment,        // out_alignment
+	                     &buffer->allocation_size); // out_allocation_size
+}
+
+void
+comp_buffer_close(struct vk_bundle *vk, struct comp_buffer *buffer)
+{
+	if (buffer->buffer != VK_NULL_HANDLE) {
+		vk->vkDestroyBuffer(vk->device, buffer->buffer, NULL);
+	}
+	if (buffer->memory != VK_NULL_HANDLE) {
+		vk->vkFreeMemory(vk->device, buffer->memory, NULL);
+	}
+
+	U_ZERO(buffer);
+}
+
+VkResult
+comp_buffer_map(struct vk_bundle *vk, struct comp_buffer *buffer)
+{
+	return vk->vkMapMemory(vk->device,       //
+	                       buffer->memory,   // memory
+	                       0,                // offset
+	                       VK_WHOLE_SIZE,    // size
+	                       0,                // flags
+	                       &buffer->mapped); // ppData
+}
+
+void
+comp_buffer_unmap(struct vk_bundle *vk, struct comp_buffer *buffer)
+{
+	if (buffer->mapped != NULL) {
+		vk->vkUnmapMemory(vk->device, buffer->memory);
+		buffer->mapped = NULL;
+	}
+}
+
+VkResult
+comp_buffer_map_and_write(struct vk_bundle *vk,
+                          struct comp_buffer *buffer,
+                          void *data,
+                          VkDeviceSize size)
+{
+	VkResult ret;
+
+	if (size > buffer->allocation_size) {
+		VK_ERROR(vk, "Trying to write more the buffer size!");
+		return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+	}
+
+	if (buffer->mapped == NULL) {
+		ret = comp_buffer_map(vk, buffer);
+		if (ret != VK_SUCCESS) {
+			return ret;
+		}
+	}
+
+	memcpy(buffer->mapped, data, size);
+
+	return VK_SUCCESS;
+}
+
+VkResult
+comp_buffer_write(struct vk_bundle *vk,
+                  struct comp_buffer *buffer,
+                  void *data,
+                  VkDeviceSize size)
+{
+	if (size > buffer->allocation_size) {
+		VK_ERROR(vk, "Trying to write more the buffer size!");
+		return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+	}
+
+	bool mapped = buffer->mapped != NULL;
+	if (!mapped) {
+		VkResult ret = comp_buffer_map(vk, buffer);
+		if (ret != VK_SUCCESS) {
+			return ret;
+		}
+	}
+
+	memcpy(buffer->mapped, data, size);
+
+	// Only unmap if we did the mapping.
+	if (!mapped) {
+		comp_buffer_unmap(vk, buffer);
+	}
+
+	return VK_SUCCESS;
+}
diff --git a/src/xrt/compositor/render/comp_render.h b/src/xrt/compositor/render/comp_render.h
new file mode 100644
index 000000000..b8df3d1d7
--- /dev/null
+++ b/src/xrt/compositor/render/comp_render.h
@@ -0,0 +1,355 @@
+// Copyright 2019-2020, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  The NEW compositor rendering code header.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_main
+ */
+
+#pragma once
+
+#include "xrt/xrt_compiler.h"
+#include "xrt/xrt_defines.h"
+
+#include "vk/vk_helpers.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct comp_compositor;
+struct comp_swapchain_image;
+
+/*!
+ * @ingroup comp_main
+ * @{
+ */
+
+/*
+ *
+ * Buffer
+ *
+ */
+
+/*!
+ * Helper struct holding a buffer and it's memory.
+ */
+struct comp_buffer
+{
+	//! Backing memory.
+	VkDeviceMemory memory;
+
+	//! Buffer.
+	VkBuffer buffer;
+
+	//! Size of the buffer.
+	VkDeviceSize size;
+
+	//! Size of the memory allocation.
+	VkDeviceSize allocation_size;
+
+	//! Alignment of the buffer.
+	VkDeviceSize alignment;
+
+	void *mapped;
+};
+
+/*!
+ * Initialize a buffer.
+ */
+VkResult
+comp_buffer_init(struct vk_bundle *vk,
+                 struct comp_buffer *buffer,
+                 VkBufferUsageFlags usage_flags,
+                 VkMemoryPropertyFlags memory_property_flags,
+                 VkDeviceSize size);
+
+/*!
+ * Frees all resources that this buffer has, doesn't not free the buffer itself.
+ */
+void
+comp_buffer_close(struct vk_bundle *vk, struct comp_buffer *buffer);
+
+/*!
+ * Maps the memory, sets comp_buffer::mapped to the memory.
+ */
+VkResult
+comp_buffer_map(struct vk_bundle *vk, struct comp_buffer *buffer);
+
+/*!
+ * Unmaps the memory.
+ */
+void
+comp_buffer_unmap(struct vk_bundle *vk, struct comp_buffer *buffer);
+
+/*!
+ * Maps the buffer, and copies the given data to the buffer.
+ */
+VkResult
+comp_buffer_map_and_write(struct vk_bundle *vk,
+                          struct comp_buffer *buffer,
+                          void *data,
+                          VkDeviceSize size);
+
+/*!
+ * Writes the given data to the buffer, will map it temporarily if not mapped.
+ */
+VkResult
+comp_buffer_write(struct vk_bundle *vk,
+                  struct comp_buffer *buffer,
+                  void *data,
+                  VkDeviceSize size);
+
+
+/*
+ *
+ * Resources
+ *
+ */
+
+/*!
+ * Holds all pools and static resources for rendering.
+ */
+struct comp_resources
+{
+	/*
+	 * Shared pools and caches.
+	 */
+
+	//! Shared for all rendering.
+	VkPipelineCache pipeline_cache;
+
+	//! Descriptor pool for mesh rendering.
+	VkDescriptorPool mesh_descriptor_pool;
+
+
+	/*
+	 * Static
+	 */
+
+	struct
+	{
+		//! The binding index for the source texture.
+		uint32_t src_binding;
+
+		//! The binding index for the UBO.
+		uint32_t ubo_binding;
+
+		//! Descriptor set layout for mesh distortion.
+		VkDescriptorSetLayout descriptor_set_layout;
+
+		//! Pipeline layout used for mesh.
+		VkPipelineLayout pipeline_layout;
+
+		struct comp_buffer vbo;
+		struct comp_buffer ibo;
+
+		uint32_t num_vertices;
+		uint32_t num_indices[2];
+		uint32_t stride;
+		uint32_t offset_indices[2];
+		uint32_t total_num_indices;
+	} mesh;
+};
+
+/*!
+ * Allocate pools and static resources.
+ *
+ * @ingroup comp_main
+ */
+bool
+comp_resources_init(struct comp_compositor *c, struct comp_resources *r);
+
+/*!
+ * Free all pools and static resources, does not free the struct itself.
+ */
+void
+comp_resources_close(struct comp_compositor *c, struct comp_resources *r);
+
+
+/*
+ *
+ * Rendering
+ *
+ */
+
+/*!
+ * Each rendering (@ref comp_rendering) render to one or more targets, each
+ * target can have one or more views (@ref comp_rendering_view), this struct
+ * holds all the data that is specific to the target.
+ */
+struct comp_target_data
+{
+	// The format that should be used to read from the target.
+	VkFormat format;
+
+	// Is this target a external target.
+	bool is_external;
+
+	//! Total height and width of the target.
+	uint32_t width, height;
+};
+
+/*!
+ * Each rendering (@ref comp_rendering) render to one or more targets, each
+ * target can have one or more views (@ref comp_rendering_view), this struct
+ * holds all the data that is specific to the target.
+ */
+struct comp_rendering_view
+{
+	struct
+	{
+		struct comp_buffer ubo;
+
+		VkDescriptorSet descriptor_set;
+	} mesh;
+};
+
+/*!
+ * A rendering is used to create command buffers needed to do one frame of
+ * compositor rendering, it holds onto resources used by the command buffer.
+ */
+struct comp_rendering
+{
+	struct comp_compositor *c;
+	struct comp_resources *r;
+
+	//! Command buffer where all commands are recorded.
+	VkCommandBuffer cmd;
+
+	//! Render pass used for rendering.
+	VkRenderPass render_pass;
+
+	struct
+	{
+		//! The data for this target.
+		struct comp_target_data data;
+
+		//! Framebuffer for this target.
+		VkFramebuffer framebuffer;
+	} targets[2];
+
+	//! Number of different targets, number of views are always two.
+	uint32_t num_targets;
+
+	struct
+	{
+		//! Pipeline layout used for mesh.
+		VkPipeline pipeline;
+	} mesh;
+
+	//! Holds per view data.
+	struct comp_rendering_view views[2];
+
+	//! The current view we are rendering to.
+	uint32_t current_view;
+};
+
+/*!
+ * Init struct and create resources needed for rendering.
+ */
+bool
+comp_rendering_init(struct comp_compositor *c,
+                    struct comp_resources *r,
+                    struct comp_rendering *rr);
+
+/*!
+ * Frees all resources held by the rendering, does not free the struct itself.
+ */
+void
+comp_rendering_close(struct comp_rendering *rr);
+
+
+/*
+ *
+ * Drawing
+ *
+ */
+
+/*!
+ *  The pure data information about a view that the renderer is rendering to.
+ */
+struct comp_viewport_data
+{
+	uint32_t x, y;
+	uint32_t w, h;
+};
+
+/*!
+ * UBO data that is sent to the mesh shaders.
+ */
+struct comp_mesh_ubo_data
+{
+	struct xrt_matrix_2x2 rot;
+	int flip_y;
+};
+
+/*!
+ * This function allocates everything to start a single rendering. This is the
+ * first function you call when you start rendering, you follow up with a call
+ * to comp_draw_begin_view.
+ */
+bool
+comp_draw_begin_target_single(struct comp_rendering *rr,
+                              VkImageView target,
+                              struct comp_target_data *data);
+
+void
+comp_draw_end_target(struct comp_rendering *rr);
+
+void
+comp_draw_begin_view(struct comp_rendering *rr,
+                     uint32_t target,
+                     uint32_t view,
+                     struct comp_viewport_data *viewport_data);
+
+void
+comp_draw_end_view(struct comp_rendering *rr);
+
+/*!
+ * Does any needed teardown of state after all of the drawing commands have been
+ * submitted.
+ */
+void
+comp_draw_end_drawing(struct comp_resources *r);
+
+void
+comp_draw_projection_layer(struct comp_rendering *rr,
+                           uint32_t layer,
+                           VkSampler sampler,
+                           VkImageView l_image_view,
+                           VkImageView r_image_view,
+                           struct xrt_layer_data *data);
+
+void
+comp_draw_quad_layer(struct comp_rendering *rr,
+                     uint32_t layer,
+                     VkSampler sampler,
+                     VkImageView image_view,
+                     struct xrt_layer_data *data);
+
+void
+comp_draw_cylinder_layer(struct comp_rendering *rr,
+                         uint32_t layer,
+                         VkSampler sampler,
+                         VkImageView image_view,
+                         struct xrt_layer_data *data);
+
+void
+comp_draw_distortion(struct comp_rendering *rr,
+                     VkSampler sampler,
+                     VkImageView image_view,
+                     struct comp_mesh_ubo_data *data);
+
+/*!
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/render/comp_rendering.c b/src/xrt/compositor/render/comp_rendering.c
new file mode 100644
index 000000000..7947c30d3
--- /dev/null
+++ b/src/xrt/compositor/render/comp_rendering.c
@@ -0,0 +1,847 @@
+// Copyright 2019-2020, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  The NEW compositor rendering code header.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_main
+ */
+
+#include "main/comp_compositor.h"
+#include "render/comp_render.h"
+
+#include <stdio.h>
+
+
+/*
+ *
+ * Common helpers
+ *
+ */
+
+#define C(c)                                                                   \
+	do {                                                                   \
+		VkResult ret = c;                                              \
+		if (ret != VK_SUCCESS) {                                       \
+			return false;                                          \
+		}                                                              \
+	} while (false)
+
+#define D(TYPE, thing)                                                         \
+	if (thing != VK_NULL_HANDLE) {                                         \
+		vk->vkDestroy##TYPE(vk->device, thing, NULL);                  \
+		thing = VK_NULL_HANDLE;                                        \
+	}
+
+#define DD(pool, thing)                                                        \
+	if (thing != VK_NULL_HANDLE) {                                         \
+		free_descriptor_set(vk, pool, thing);                          \
+		thing = VK_NULL_HANDLE;                                        \
+	}
+
+static VkResult
+create_external_render_pass(struct vk_bundle *vk,
+                            VkFormat format,
+                            VkRenderPass *out_render_pass)
+{
+	VkResult ret;
+
+	VkAttachmentDescription attachments[1] = {
+	    {
+	        .format = format,
+	        .samples = VK_SAMPLE_COUNT_1_BIT,
+	        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+	        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+	        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+	        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
+	        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+	        .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+	    },
+	};
+
+	VkAttachmentReference color_reference = {
+	    .attachment = 0,
+	    .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+	};
+
+	VkSubpassDescription subpasses[1] = {
+	    {
+	        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+	        .inputAttachmentCount = 0,
+	        .pInputAttachments = NULL,
+	        .colorAttachmentCount = 1,
+	        .pColorAttachments = &color_reference,
+	        .pResolveAttachments = NULL,
+	        .pDepthStencilAttachment = NULL,
+	        .preserveAttachmentCount = 0,
+	        .pPreserveAttachments = NULL,
+	    },
+	};
+
+	VkSubpassDependency dependencies[1] = {
+	    {
+	        .srcSubpass = VK_SUBPASS_EXTERNAL,
+	        .dstSubpass = 0,
+	        .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+	        .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+	        .srcAccessMask = 0,
+	        .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+	                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+	    },
+	};
+
+	VkRenderPassCreateInfo render_pass_info = {
+	    .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+	    .attachmentCount = ARRAY_SIZE(attachments),
+	    .pAttachments = attachments,
+	    .subpassCount = ARRAY_SIZE(subpasses),
+	    .pSubpasses = subpasses,
+	    .dependencyCount = ARRAY_SIZE(dependencies),
+	    .pDependencies = dependencies,
+	};
+
+	VkRenderPass render_pass = VK_NULL_HANDLE;
+	ret = vk->vkCreateRenderPass(vk->device,        //
+	                             &render_pass_info, //
+	                             NULL,              //
+	                             &render_pass);     //
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateRenderPass failed: %s",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	*out_render_pass = render_pass;
+
+	return VK_SUCCESS;
+}
+
+static VkResult
+create_descriptor_set(struct vk_bundle *vk,
+                      VkDescriptorPool descriptor_pool,
+                      VkDescriptorSetLayout descriptor_layout,
+                      VkDescriptorSet *out_descriptor_set)
+{
+	VkResult ret;
+
+	VkDescriptorSetAllocateInfo alloc_info = {
+	    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+	    .descriptorPool = descriptor_pool,
+	    .descriptorSetCount = 1,
+	    .pSetLayouts = &descriptor_layout,
+	};
+
+	VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
+	ret = vk->vkAllocateDescriptorSets(vk->device,       //
+	                                   &alloc_info,      //
+	                                   &descriptor_set); //
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "vkAllocateDescriptorSets failed: %s",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	*out_descriptor_set = descriptor_set;
+
+	return VK_SUCCESS;
+}
+
+static void
+free_descriptor_set(struct vk_bundle *vk,
+                    VkDescriptorPool descriptor_pool,
+                    VkDescriptorSet descriptor_set)
+{
+	VkResult ret;
+
+
+	ret = vk->vkFreeDescriptorSets(vk->device,       //
+	                               descriptor_pool,  // descriptorPool
+	                               1,                // descriptorSetCount
+	                               &descriptor_set); // pDescriptorSets
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "vkFreeDescriptorSets failed: %s",
+		         vk_result_string(ret));
+	}
+}
+
+static VkResult
+create_framebuffer(struct vk_bundle *vk,
+                   VkImageView image_view,
+                   VkRenderPass render_pass,
+                   uint32_t width,
+                   uint32_t height,
+                   VkFramebuffer *out_external_framebuffer)
+{
+	VkResult ret;
+
+	VkImageView attachments[1] = {image_view};
+
+	VkFramebufferCreateInfo frame_buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+	    .renderPass = render_pass,
+	    .attachmentCount = ARRAY_SIZE(attachments),
+	    .pAttachments = attachments,
+	    .width = width,
+	    .height = height,
+	    .layers = 1,
+	};
+
+	VkFramebuffer framebuffer = VK_NULL_HANDLE;
+	ret = vk->vkCreateFramebuffer(vk->device,         //
+	                              &frame_buffer_info, //
+	                              NULL,               //
+	                              &framebuffer);      //
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateFramebuffer failed: %s",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	*out_external_framebuffer = framebuffer;
+
+	return VK_SUCCESS;
+}
+
+static VkResult
+create_command_buffer(struct vk_bundle *vk, VkCommandBuffer *out_cmd)
+{
+	VkResult ret;
+
+	VkCommandBufferAllocateInfo cmd_buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+	    .commandPool = vk->cmd_pool,
+	    .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+	    .commandBufferCount = 1,
+	};
+
+	VkCommandBuffer cmd = VK_NULL_HANDLE;
+	ret = vk->vkAllocateCommandBuffers(vk->device,       //
+	                                   &cmd_buffer_info, //
+	                                   &cmd);            //
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(r->c, "vkCreateFramebuffer failed: %s",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	*out_cmd = cmd;
+
+	return VK_SUCCESS;
+}
+
+static VkResult
+begin_command_buffer(struct vk_bundle *vk, VkCommandBuffer command_buffer)
+{
+	VkResult ret;
+
+	VkCommandBufferBeginInfo command_buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+	};
+
+	ret = vk->vkBeginCommandBuffer(command_buffer, &command_buffer_info);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkBeginCommandBuffer failed: %s",
+		           vk_result_string(ret));
+		return ret;
+	}
+
+	return VK_SUCCESS;
+}
+
+static void
+begin_render_pass(struct vk_bundle *vk,
+                  VkCommandBuffer command_buffer,
+                  VkRenderPass render_pass,
+                  VkFramebuffer framebuffer,
+                  uint32_t width,
+                  uint32_t height)
+{
+	VkClearValue clear_color[1] = {{
+	    .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}},
+	}};
+
+	VkRenderPassBeginInfo render_pass_begin_info = {
+	    .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+	    .renderPass = render_pass,
+	    .framebuffer = framebuffer,
+	    .renderArea =
+	        {
+	            .offset =
+	                {
+	                    .x = 0,
+	                    .y = 0,
+	                },
+	            .extent =
+	                {
+	                    .width = width,
+	                    .height = height,
+	                },
+	        },
+	    .clearValueCount = ARRAY_SIZE(clear_color),
+	    .pClearValues = clear_color,
+	};
+
+	vk->vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info,
+	                         VK_SUBPASS_CONTENTS_INLINE);
+}
+
+
+/*
+ *
+ * Mesh
+ *
+ */
+
+static VkResult
+create_mesh_pipeline(struct vk_bundle *vk,
+                     VkRenderPass render_pass,
+                     VkPipelineLayout pipeline_layout,
+                     VkPipelineCache pipeline_cache,
+                     uint32_t src_binding,
+                     uint32_t mesh_total_num_indices,
+                     uint32_t mesh_stride,
+                     VkShaderModule mesh_vert,
+                     VkShaderModule mesh_frag,
+                     VkPipeline *out_mesh_pipeline)
+{
+	VkResult ret;
+
+	// Might be changed to line for debugging.
+	VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL;
+
+	// Do we use triangle strips or triangles with indices.
+	VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+	if (mesh_total_num_indices > 0) {
+		topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+	}
+
+	VkPipelineInputAssemblyStateCreateInfo input_assembly_state = {
+	    .sType =
+	        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+	    .topology = topology,
+	    .primitiveRestartEnable = VK_FALSE,
+	};
+
+	VkPipelineRasterizationStateCreateInfo rasterization_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+	    .depthClampEnable = VK_FALSE,
+	    .rasterizerDiscardEnable = VK_FALSE,
+	    .polygonMode = polygonMode,
+	    .cullMode = VK_CULL_MODE_BACK_BIT,
+	    .frontFace = VK_FRONT_FACE_CLOCKWISE,
+	    .lineWidth = 1.0f,
+	};
+
+	VkPipelineColorBlendAttachmentState blend_attachment_state = {
+	    .blendEnable = VK_FALSE,
+	    .colorWriteMask = 0xf,
+	};
+
+	VkPipelineColorBlendStateCreateInfo color_blend_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+	    .attachmentCount = 1,
+	    .pAttachments = &blend_attachment_state,
+	};
+
+	VkPipelineDepthStencilStateCreateInfo depth_stencil_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+	    .depthTestEnable = VK_TRUE,
+	    .depthWriteEnable = VK_TRUE,
+	    .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL,
+	    .front =
+	        {
+	            .compareOp = VK_COMPARE_OP_ALWAYS,
+	        },
+	    .back =
+	        {
+	            .compareOp = VK_COMPARE_OP_ALWAYS,
+	        },
+	};
+
+	VkPipelineViewportStateCreateInfo viewport_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+	    .viewportCount = 1,
+	    .scissorCount = 1,
+	};
+
+	VkPipelineMultisampleStateCreateInfo multisample_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+	    .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
+	};
+
+	VkDynamicState dynamic_states[] = {
+	    VK_DYNAMIC_STATE_VIEWPORT,
+	    VK_DYNAMIC_STATE_SCISSOR,
+	};
+
+	VkPipelineDynamicStateCreateInfo dynamic_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+	    .dynamicStateCount = ARRAY_SIZE(dynamic_states),
+	    .pDynamicStates = dynamic_states,
+	};
+
+	// clang-format off
+	VkVertexInputAttributeDescription vertex_input_attribute_descriptions[2] = {
+	    {
+	        .binding = src_binding,
+	        .location = 0,
+	        .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+	        .offset = 0,
+	    },
+	    {
+	        .binding = src_binding,
+	        .location = 1,
+	        .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+	        .offset = 16,
+	    },
+	};
+
+	VkVertexInputBindingDescription vertex_input_binding_description[1] = {
+	    {
+	        .binding = src_binding,
+	        .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
+	        .stride = mesh_stride,
+	    },
+	};
+
+	VkPipelineVertexInputStateCreateInfo vertex_input_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+	    .vertexAttributeDescriptionCount = ARRAY_SIZE(vertex_input_attribute_descriptions),
+	    .pVertexAttributeDescriptions = vertex_input_attribute_descriptions,
+	    .vertexBindingDescriptionCount = ARRAY_SIZE(vertex_input_binding_description),
+	    .pVertexBindingDescriptions = vertex_input_binding_description,
+	};
+	// clang-format on
+
+	VkPipelineShaderStageCreateInfo shader_stages[2] = {
+	    {
+	        .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+	        .stage = VK_SHADER_STAGE_VERTEX_BIT,
+	        .module = mesh_vert,
+	        .pName = "main",
+	    },
+	    {
+	        .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+	        .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
+	        .module = mesh_frag,
+	        .pName = "main",
+	    },
+	};
+
+	VkGraphicsPipelineCreateInfo pipeline_info = {
+	    .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+	    .stageCount = ARRAY_SIZE(shader_stages),
+	    .pStages = shader_stages,
+	    .pVertexInputState = &vertex_input_state,
+	    .pInputAssemblyState = &input_assembly_state,
+	    .pViewportState = &viewport_state,
+	    .pRasterizationState = &rasterization_state,
+	    .pMultisampleState = &multisample_state,
+	    .pDepthStencilState = &depth_stencil_state,
+	    .pColorBlendState = &color_blend_state,
+	    .pDynamicState = &dynamic_state,
+	    .layout = pipeline_layout,
+	    .renderPass = render_pass,
+	    .basePipelineHandle = VK_NULL_HANDLE,
+	    .basePipelineIndex = -1,
+	};
+
+	VkPipeline pipeline = VK_NULL_HANDLE;
+	ret = vk->vkCreateGraphicsPipelines(vk->device,     //
+	                                    pipeline_cache, //
+	                                    1,              //
+	                                    &pipeline_info, //
+	                                    NULL,           //
+	                                    &pipeline);     //
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "vkCreateGraphicsPipelines failed: %s",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	*out_mesh_pipeline = pipeline;
+
+	return VK_SUCCESS;
+}
+
+static bool
+init_mesh_ubo_buffers(struct vk_bundle *vk,
+                      struct comp_buffer *l_ubo,
+                      struct comp_buffer *r_ubo)
+{
+	// Using the same flags for all ubos.
+	VkBufferUsageFlags ubo_usage_flags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+	VkMemoryPropertyFlags memory_property_flags =
+	    VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
+	    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+
+	// Distortion ubo size.
+	VkDeviceSize ubo_size = sizeof(struct comp_mesh_ubo_data);
+
+	C(comp_buffer_init(vk,                    //
+	                   l_ubo,                 //
+	                   ubo_usage_flags,       //
+	                   memory_property_flags, //
+	                   ubo_size));            // size
+	C(comp_buffer_map(vk, l_ubo));
+
+	C(comp_buffer_init(vk,                    //
+	                   r_ubo,                 //
+	                   ubo_usage_flags,       //
+	                   memory_property_flags, //
+	                   ubo_size));            // size
+	C(comp_buffer_map(vk, r_ubo));
+
+
+	return true;
+}
+
+static void
+update_mesh_discriptor_set(struct vk_bundle *vk,
+                           uint32_t src_binding,
+                           VkSampler sampler,
+                           VkImageView image_view,
+                           uint32_t ubo_binding,
+                           VkBuffer buffer,
+                           VkDeviceSize size,
+                           VkDescriptorSet descriptor_set)
+{
+	VkDescriptorImageInfo image_info = {
+	    .sampler = sampler,
+	    .imageView = image_view,
+	    .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+	};
+
+	VkDescriptorBufferInfo buffer_info = {
+	    .buffer = buffer,
+	    .offset = 0,
+	    .range = size,
+	};
+
+	VkWriteDescriptorSet write_descriptor_sets[2] = {
+	    {
+	        .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+	        .dstSet = descriptor_set,
+	        .dstBinding = src_binding,
+	        .descriptorCount = 1,
+	        .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+	        .pImageInfo = &image_info,
+	    },
+	    {
+	        .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+	        .dstSet = descriptor_set,
+	        .dstBinding = ubo_binding,
+	        .descriptorCount = 1,
+	        .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+	        .pBufferInfo = &buffer_info,
+	    },
+	};
+
+	vk->vkUpdateDescriptorSets(
+	    vk->device,                        //
+	    ARRAY_SIZE(write_descriptor_sets), // descriptorWriteCount
+	    write_descriptor_sets,             // pDescriptorWrites
+	    0,                                 // descriptorCopyCount
+	    NULL);                             // pDescriptorCopies
+}
+
+
+/*
+ *
+ * 'Exported' rendering functions.
+ *
+ */
+
+bool
+comp_rendering_init(struct comp_compositor *c,
+                    struct comp_resources *r,
+                    struct comp_rendering *rr)
+{
+	struct vk_bundle *vk = &c->vk;
+	rr->c = c;
+	rr->r = r;
+
+
+	/*
+	 * Per rendering.
+	 */
+
+	C(create_command_buffer(vk, &rr->cmd));
+
+
+	/*
+	 * Mesh per view
+	 */
+
+	C(create_descriptor_set(
+	    vk,                                  // vk_bundle
+	    r->mesh_descriptor_pool,             // descriptor_pool
+	    r->mesh.descriptor_set_layout,       // descriptor_set_layout
+	    &rr->views[0].mesh.descriptor_set)); // descriptor_set
+
+	C(create_descriptor_set(
+	    vk,                                  // vk_bundle
+	    r->mesh_descriptor_pool,             // descriptor_pool
+	    r->mesh.descriptor_set_layout,       // descriptor_set_layout
+	    &rr->views[1].mesh.descriptor_set)); // descriptor_set
+
+	if (!init_mesh_ubo_buffers(vk,                     //
+	                           &rr->views[0].mesh.ubo, //
+	                           &rr->views[1].mesh.ubo)) {
+		return false;
+	}
+
+	return true;
+}
+
+void
+comp_rendering_close(struct comp_rendering *rr)
+{
+	struct vk_bundle *vk = &rr->c->vk;
+	struct comp_resources *r = rr->r;
+
+	D(RenderPass, rr->render_pass);
+	D(Pipeline, rr->mesh.pipeline);
+	D(Framebuffer, rr->targets[0].framebuffer);
+	D(Framebuffer, rr->targets[1].framebuffer);
+	comp_buffer_close(vk, &rr->views[0].mesh.ubo);
+	comp_buffer_close(vk, &rr->views[1].mesh.ubo);
+	DD(r->mesh_descriptor_pool, rr->views[0].mesh.descriptor_set);
+	DD(r->mesh_descriptor_pool, rr->views[1].mesh.descriptor_set);
+
+	U_ZERO(rr);
+}
+
+
+/*
+ *
+ * 'Exported' draw functions.
+ *
+ */
+
+bool
+comp_draw_begin_target_single(struct comp_rendering *rr,
+                              VkImageView target,
+                              struct comp_target_data *data)
+{
+	struct vk_bundle *vk = &rr->c->vk;
+	struct comp_resources *r = rr->r;
+
+	rr->targets[0].data = *data;
+	rr->num_targets = 1;
+
+	assert(data->is_external);
+
+	C(create_external_render_pass( //
+	    vk,                        // vk_bundle
+	    data->format,              // target_format
+	    &rr->render_pass));        // out_render_pass
+
+	C(create_mesh_pipeline(
+	    vk,                        // vk_bundle
+	    rr->render_pass,           // render_pass
+	    r->mesh.pipeline_layout,   // pipeline_layout
+	    r->pipeline_cache,         // pipeline_cache
+	    r->mesh.src_binding,       // src_binding
+	    r->mesh.total_num_indices, // mesh_total_num_indices
+	    r->mesh.stride,            // mesh_stride
+	    rr->c->shaders.mesh_vert,  // mesh_vert
+	    rr->c->shaders.mesh_frag,  // mesh_frag
+	    &rr->mesh.pipeline));      // out_mesh_pipeline
+
+	C(create_framebuffer(
+	    vk,                            // vk_bundle,
+	    target,                        // image_view,
+	    rr->render_pass,               // render_pass,
+	    data->width,                   // width,
+	    data->height,                  // height,
+	    &rr->targets[0].framebuffer)); // out_external_framebuffer
+
+	C(begin_command_buffer(vk, rr->cmd));
+
+	// This is shared across both views.
+	begin_render_pass(vk,                          //
+	                  rr->cmd,                     //
+	                  rr->render_pass,             //
+	                  rr->targets[0].framebuffer,  //
+	                  rr->targets[0].data.width,   //
+	                  rr->targets[0].data.height); //
+
+	return true;
+}
+
+void
+comp_draw_end_target(struct comp_rendering *rr)
+{
+	struct vk_bundle *vk = &rr->c->vk;
+	VkResult ret;
+
+	//! We currently only support single target mode.
+	assert(rr->num_targets == 1);
+
+	// Stop the shared render pass.
+	vk->vkCmdEndRenderPass(rr->cmd);
+
+	// End the command buffer.
+	ret = vk->vkEndCommandBuffer(rr->cmd);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkEndCommandBuffer failed: %s",
+		         vk_result_string(ret));
+		return;
+	}
+}
+
+void
+comp_draw_begin_view(struct comp_rendering *rr,
+                     uint32_t target,
+                     uint32_t view,
+                     struct comp_viewport_data *viewport_data)
+{
+	struct vk_bundle *vk = &rr->c->vk;
+
+	rr->current_view = view;
+
+	//! We currently only support single target mode.
+	assert(rr->num_targets == 1);
+	assert(target == 0);
+	assert(view == 0 || view == 1);
+
+
+	/*
+	 * Viewport
+	 */
+
+	VkViewport viewport = {
+	    .x = viewport_data->x,
+	    .y = viewport_data->y,
+	    .width = viewport_data->w,
+	    .height = viewport_data->h,
+	    .minDepth = 0.0f,
+	    .maxDepth = 1.0f,
+	};
+
+	vk->vkCmdSetViewport(rr->cmd,    // commandBuffer
+	                     0,          // firstViewport
+	                     1,          // viewportCount
+	                     &viewport); // pViewports
+
+	/*
+	 * Scissor
+	 */
+
+	VkRect2D scissor = {
+	    .offset =
+	        {
+	            .x = viewport_data->x,
+	            .y = viewport_data->y,
+	        },
+	    .extent =
+	        {
+	            .width = viewport_data->w,
+	            .height = viewport_data->h,
+	        },
+	};
+
+	vk->vkCmdSetScissor(rr->cmd,   // commandBuffer
+	                    0,         // firstScissor
+	                    1,         // scissorCount
+	                    &scissor); // pScissors
+}
+
+void
+comp_draw_end_view(struct comp_rendering *rr)
+{
+	//! We currently only support single target mode.
+	assert(rr->num_targets == 1);
+}
+
+void
+comp_draw_distortion(struct comp_rendering *rr,
+                     VkSampler sampler,
+                     VkImageView image_view,
+                     struct comp_mesh_ubo_data *data)
+{
+	struct vk_bundle *vk = &rr->c->vk;
+	struct comp_resources *r = rr->r;
+
+	uint32_t view = rr->current_view;
+	struct comp_rendering_view *v = &rr->views[view];
+
+	/*
+	 * Descriptors and pipeline.
+	 */
+
+	comp_buffer_write(vk, &v->mesh.ubo, data,
+	                  sizeof(struct comp_mesh_ubo_data));
+
+	update_mesh_discriptor_set(  //
+	    vk,                      // vk_bundle
+	    r->mesh.src_binding,     // src_binding
+	    sampler,                 // sampler
+	    image_view,              // image_view
+	    r->mesh.ubo_binding,     // ubo_binding
+	    v->mesh.ubo.buffer,      // buffer
+	    VK_WHOLE_SIZE,           // size
+	    v->mesh.descriptor_set); // descriptor_set
+
+	VkDescriptorSet descriptor_sets[1] = {v->mesh.descriptor_set};
+	vk->vkCmdBindDescriptorSets(         //
+	    rr->cmd,                         // commandBuffer
+	    VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
+	    r->mesh.pipeline_layout,         // layout
+	    0,                               // firstSet
+	    ARRAY_SIZE(descriptor_sets),     // descriptorSetCount
+	    descriptor_sets,                 // pDescriptorSets
+	    0,                               // dynamicOffsetCount
+	    NULL);                           // pDynamicOffsets
+
+	vk->vkCmdBindPipeline(               //
+	    rr->cmd,                         // commandBuffer
+	    VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
+	    rr->mesh.pipeline);              // pipeline
+
+
+	/*
+	 * Vertex buffer.
+	 */
+
+	VkBuffer buffers[1] = {r->mesh.vbo.buffer};
+	VkDeviceSize offsets[1] = {0};
+	assert(ARRAY_SIZE(buffers) == ARRAY_SIZE(offsets));
+
+	vk->vkCmdBindVertexBuffers( //
+	    rr->cmd,                // commandBuffer
+	    0,                      // firstBinding
+	    ARRAY_SIZE(buffers),    // bindingCount
+	    buffers,                // pBuffers
+	    offsets);               // pOffsets
+
+
+	/*
+	 * Draw with indices or not?
+	 */
+
+	if (r->mesh.total_num_indices > 0) {
+		vk->vkCmdBindIndexBuffer(  //
+		    rr->cmd,               // commandBuffer
+		    r->mesh.ibo.buffer,    // buffer
+		    0,                     // offset
+		    VK_INDEX_TYPE_UINT32); // indexType
+
+		vk->vkCmdDrawIndexed(             //
+		    rr->cmd,                      // commandBuffer
+		    r->mesh.num_indices[view],    // indexCount
+		    1,                            // instanceCount
+		    r->mesh.offset_indices[view], // firstIndex
+		    0,                            // vertexOffset
+		    0);                           // firstInstance
+	} else {
+		vk->vkCmdDraw(            //
+		    rr->cmd,              // commandBuffer
+		    r->mesh.num_vertices, // vertexCount
+		    1,                    // instanceCount
+		    0,                    // firstVertex
+		    0);                   // firstInstance
+	}
+}
diff --git a/src/xrt/compositor/render/comp_resources.c b/src/xrt/compositor/render/comp_resources.c
new file mode 100644
index 000000000..1c5471723
--- /dev/null
+++ b/src/xrt/compositor/render/comp_resources.c
@@ -0,0 +1,333 @@
+// Copyright 2019-2020, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Shared resources for rendering.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_main
+ */
+
+
+#include "main/comp_compositor.h"
+#include "render/comp_render.h"
+
+#include <stdio.h>
+
+
+#define C(c)                                                                   \
+	do {                                                                   \
+		VkResult ret = c;                                              \
+		if (ret != VK_SUCCESS) {                                       \
+			return false;                                          \
+		}                                                              \
+	} while (false)
+
+#define D(TYPE, thing)                                                         \
+	if (thing != VK_NULL_HANDLE) {                                         \
+		vk->vkDestroy##TYPE(vk->device, thing, NULL);                  \
+		thing = VK_NULL_HANDLE;                                        \
+	}
+
+static VkResult
+create_pipeline_cache(struct vk_bundle *vk, VkPipelineCache *out_pipeline_cache)
+{
+	VkResult ret;
+
+	VkPipelineCacheCreateInfo pipeline_cache_info = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
+	};
+
+	VkPipelineCache pipeline_cache;
+	ret = vk->vkCreatePipelineCache(vk->device,           //
+	                                &pipeline_cache_info, //
+	                                NULL,                 //
+	                                &pipeline_cache);     //
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(vk, "vkCreatePipelineCache failed: %s",
+		           vk_result_string(ret));
+		return ret;
+	}
+
+	*out_pipeline_cache = pipeline_cache;
+
+	return VK_SUCCESS;
+}
+
+static VkResult
+create_pipeline_layout(struct vk_bundle *vk,
+                       VkDescriptorSetLayout descriptor_set_layout,
+                       VkPipelineLayout *out_pipeline_layout)
+{
+	VkResult ret;
+
+	VkPipelineLayoutCreateInfo pipeline_layout_info = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+	    .setLayoutCount = 1,
+	    .pSetLayouts = &descriptor_set_layout,
+	};
+
+	VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
+	ret = vk->vkCreatePipelineLayout(vk->device,            //
+	                                 &pipeline_layout_info, //
+	                                 NULL,                  //
+	                                 &pipeline_layout);     //
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreatePipelineLayout failed: %s",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	*out_pipeline_layout = pipeline_layout;
+
+	return VK_SUCCESS;
+}
+
+static VkResult
+create_descriptor_pool(struct vk_bundle *vk,
+                       uint32_t num_uniform_per_desc,
+                       uint32_t num_sampler_per_desc,
+                       uint32_t num_descs,
+                       VkDescriptorPool *out_descriptor_pool)
+{
+	VkResult ret;
+
+
+	VkDescriptorPoolSize pool_sizes[2] = {
+	    {
+	        .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+	        .descriptorCount = num_uniform_per_desc * num_descs,
+	    },
+	    {
+	        .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+	        .descriptorCount = num_sampler_per_desc * num_descs,
+	    },
+	};
+
+	VkDescriptorPoolCreateInfo descriptor_pool_info = {
+	    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+	    .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
+	    .maxSets = num_descs,
+	    .poolSizeCount = ARRAY_SIZE(pool_sizes),
+	    .pPoolSizes = pool_sizes,
+	};
+
+	VkDescriptorPool descriptor_pool = VK_NULL_HANDLE;
+	ret = vk->vkCreateDescriptorPool(vk->device,            //
+	                                 &descriptor_pool_info, //
+	                                 NULL,                  //
+	                                 &descriptor_pool);     //
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateRenderPass failed: %s",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	*out_descriptor_pool = descriptor_pool;
+
+	return VK_SUCCESS;
+}
+
+
+/*
+ *
+ * Mesh
+ *
+ */
+
+static VkResult
+create_mesh_descriptor_set_layout(
+    struct vk_bundle *vk,
+    uint32_t src_binding,
+    uint32_t ubo_binding,
+    VkDescriptorSetLayout *out_descriptor_set_layout)
+{
+	VkResult ret;
+
+	VkDescriptorSetLayoutBinding set_layout_bindings[2] = {
+	    {
+	        .binding = src_binding,
+	        .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+	        .descriptorCount = 1,
+	        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+	    },
+	    {
+	        .binding = ubo_binding,
+	        .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+	        .descriptorCount = 1,
+	        .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
+	    },
+	};
+
+	VkDescriptorSetLayoutCreateInfo set_layout_info = {
+	    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+	    .bindingCount = ARRAY_SIZE(set_layout_bindings),
+	    .pBindings = set_layout_bindings,
+	};
+
+	VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE;
+	ret = vk->vkCreateDescriptorSetLayout(vk->device,              //
+	                                      &set_layout_info,        //
+	                                      NULL,                    //
+	                                      &descriptor_set_layout); //
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateDescriptorSetLayout failed: %s",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	*out_descriptor_set_layout = descriptor_set_layout;
+
+	return VK_SUCCESS;
+}
+
+
+static bool
+init_mesh_vertex_buffers(struct vk_bundle *vk,
+                         struct comp_buffer *vbo,
+                         struct comp_buffer *ibo,
+                         uint32_t num_vertices,
+                         uint32_t stride,
+                         void *vertices,
+                         uint32_t num_indices,
+                         void *indices)
+{
+	// Using the same flags for all vbos.
+	VkBufferUsageFlags vbo_usage_flags = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+	VkBufferUsageFlags ibo_usage_flags = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+	VkMemoryPropertyFlags memory_property_flags =
+	    VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
+	    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+
+	// Distortion vbo and ibo sizes.
+	VkDeviceSize vbo_size = stride * num_vertices;
+	VkDeviceSize ibo_size = sizeof(int) * num_indices;
+
+
+	// Don't create vbo if size is zero.
+	if (vbo_size == 0) {
+		return true;
+	}
+
+	C(comp_buffer_init(vk,                    // vk_bundle
+	                   vbo,                   // buffer
+	                   vbo_usage_flags,       // usage_flags
+	                   memory_property_flags, // memory_property_flags
+	                   vbo_size));            // size
+
+	C(comp_buffer_write(vk,         // vk_bundle
+	                    vbo,        // buffer
+	                    vertices,   // data
+	                    vbo_size)); // size
+
+
+	// Don't create index buffer if size is zero.
+	if (ibo_size == 0) {
+		return true;
+	}
+
+	C(comp_buffer_init(vk,                    // vk_bundle
+	                   ibo,                   // buffer
+	                   ibo_usage_flags,       // usage_flags
+	                   memory_property_flags, // memory_property_flags
+	                   ibo_size));            // size
+
+	C(comp_buffer_write(vk,         // vk_bundle
+	                    ibo,        // buffer
+	                    indices,    // data
+	                    ibo_size)); // size
+
+	return true;
+}
+
+
+/*
+ *
+ * 'Exported' renderer functions.
+ *
+ */
+
+bool
+comp_resources_init(struct comp_compositor *c, struct comp_resources *r)
+{
+	struct vk_bundle *vk = &c->vk;
+	struct xrt_device *xdev = c->xdev;
+
+	/*
+	 * Constants
+	 */
+
+	r->mesh.src_binding = 0;
+	r->mesh.ubo_binding = 1;
+	struct xrt_hmd_parts *parts = xdev->hmd;
+	r->mesh.num_vertices = parts->distortion.mesh.num_vertices;
+	r->mesh.stride = parts->distortion.mesh.stride;
+	r->mesh.num_indices[0] = parts->distortion.mesh.num_indices[0];
+	r->mesh.num_indices[1] = parts->distortion.mesh.num_indices[1];
+	r->mesh.total_num_indices = parts->distortion.mesh.total_num_indices;
+	r->mesh.offset_indices[0] = parts->distortion.mesh.offset_indices[0];
+	r->mesh.offset_indices[1] = parts->distortion.mesh.offset_indices[1];
+
+
+	/*
+	 * Shared
+	 */
+
+	C(create_pipeline_cache(vk, &r->pipeline_cache));
+
+
+	/*
+	 * Mesh static.
+	 */
+
+	C(create_descriptor_pool(
+	    vk,                         // vk_bundle
+	    1,                          // num_uniform_per_desc
+	    1,                          // num_sampler_per_desc
+	    16 * 2,                     // num_descs
+	    &r->mesh_descriptor_pool)); // out_descriptor_pool
+
+	C(create_mesh_descriptor_set_layout(
+	    vk,                               // vk_bundle
+	    r->mesh.src_binding,              // src_binding
+	    r->mesh.ubo_binding,              // ubo_binding
+	    &r->mesh.descriptor_set_layout)); // out_mesh_descriptor_set_layout
+
+	C(create_pipeline_layout(
+	    vk,                            // vk_bundle
+	    r->mesh.descriptor_set_layout, // descriptor_set_layout
+	    &r->mesh.pipeline_layout));    // out_pipeline_layout
+
+	if (!init_mesh_vertex_buffers(vk,                                //
+	                              &r->mesh.vbo,                      //
+	                              &r->mesh.ibo,                      //
+	                              r->mesh.num_vertices,              //
+	                              r->mesh.stride,                    //
+	                              parts->distortion.mesh.vertices,   //
+	                              r->mesh.total_num_indices,         //
+	                              parts->distortion.mesh.indices)) { //
+		return false;
+	}
+
+
+	/*
+	 * Done
+	 */
+
+	U_LOG_I("New renderer initialized!");
+
+	return true;
+}
+
+void
+comp_resources_close(struct comp_compositor *c, struct comp_resources *r)
+{
+	struct vk_bundle *vk = &c->vk;
+
+	D(DescriptorSetLayout, r->mesh.descriptor_set_layout);
+	D(PipelineLayout, r->mesh.pipeline_layout);
+	D(PipelineCache, r->pipeline_cache);
+	D(DescriptorPool, r->mesh_descriptor_pool);
+	comp_buffer_close(vk, &r->mesh.vbo);
+	comp_buffer_close(vk, &r->mesh.ibo);
+}