diff --git a/doc/changes/xrt/mr.407.md b/doc/changes/xrt/mr.407.md
new file mode 100644
index 000000000..cae6bd02e
--- /dev/null
+++ b/doc/changes/xrt/mr.407.md
@@ -0,0 +1,3 @@
+compositor: Introduce `xrt_swapchain_create_info` simplifying the argument
+passing between various layers of the compositor stack and also simplify future
+refactoring projects.
diff --git a/src/xrt/compositor/client/comp_gl_client.c b/src/xrt/compositor/client/comp_gl_client.c
index 296809044..098640251 100644
--- a/src/xrt/compositor/client/comp_gl_client.c
+++ b/src/xrt/compositor/client/comp_gl_client.c
@@ -241,19 +241,11 @@ vk_format_to_gl(int64_t format)
 
 static struct xrt_swapchain *
 client_gl_swapchain_create(struct xrt_compositor *xc,
-                           enum xrt_swapchain_create_flags create,
-                           enum xrt_swapchain_usage_bits bits,
-                           int64_t format,
-                           uint32_t sample_count,
-                           uint32_t width,
-                           uint32_t height,
-                           uint32_t face_count,
-                           uint32_t array_size,
-                           uint32_t mip_count)
+                           struct xrt_swapchain_create_info *info)
 {
 	struct client_gl_compositor *c = client_gl_compositor(xc);
 
-	if (array_size > 1) {
+	if (info->array_size > 1) {
 		const char *version_str = (const char *)glGetString(GL_VERSION);
 		if (strstr(version_str, "OpenGL ES 2.") == version_str) {
 			fprintf(stderr,
@@ -264,15 +256,16 @@ client_gl_swapchain_create(struct xrt_compositor *xc,
 		}
 	}
 
-	int64_t vk_format = gl_format_to_vk(format);
+	int64_t vk_format = gl_format_to_vk(info->format);
 	if (vk_format == 0) {
 		fprintf(stderr, "%s - Invalid format!\n", __func__);
 		return NULL;
 	}
 
-	struct xrt_swapchain_fd *xscfd = xrt_comp_fd_create_swapchain(
-	    c->xcfd, create, bits, vk_format, sample_count, width, height,
-	    face_count, array_size, mip_count);
+	struct xrt_swapchain_create_info vk_info = *info;
+	vk_info.format = vk_format;
+	struct xrt_swapchain_fd *xscfd =
+	    xrt_comp_fd_create_swapchain(c->xcfd, &vk_info);
 
 
 	if (xscfd == NULL) {
@@ -291,14 +284,14 @@ client_gl_swapchain_create(struct xrt_compositor *xc,
 	sc->xscfd = xscfd;
 
 	GLuint prev_texture = 0;
-	glGetIntegerv(array_size == 1 ? GL_TEXTURE_BINDING_2D
-	                              : GL_TEXTURE_BINDING_2D_ARRAY,
+	glGetIntegerv(info->array_size == 1 ? GL_TEXTURE_BINDING_2D
+	                                    : GL_TEXTURE_BINDING_2D_ARRAY,
 	              (GLint *)&prev_texture);
 
 	glGenTextures(xsc->num_images, sc->base.images);
 	for (uint32_t i = 0; i < xsc->num_images; i++) {
-		glBindTexture(array_size == 1 ? GL_TEXTURE_2D
-		                              : GL_TEXTURE_2D_ARRAY,
+		glBindTexture(info->array_size == 1 ? GL_TEXTURE_2D
+		                                    : GL_TEXTURE_2D_ARRAY,
 		              sc->base.images[i]);
 	}
 	glCreateMemoryObjectsEXT(xsc->num_images, &sc->base.memory[0]);
@@ -314,18 +307,21 @@ client_gl_swapchain_create(struct xrt_compositor *xc,
 		// We have consumed this fd now, make sure it's not freed again.
 		xscfd->images[i].fd = -1;
 
-		if (array_size == 1) {
-			glTextureStorageMem2DEXT(sc->base.images[i], mip_count,
-			                         (GLuint)format, width, height,
-			                         sc->base.memory[i], 0);
+		if (info->array_size == 1) {
+			glTextureStorageMem2DEXT(
+			    sc->base.images[i], info->mip_count,
+			    (GLuint)info->format, info->width, info->height,
+			    sc->base.memory[i], 0);
 		} else {
 			glTextureStorageMem3DEXT(
-			    sc->base.images[i], mip_count, (GLuint)format,
-			    width, height, array_size, sc->base.memory[i], 0);
+			    sc->base.images[i], info->mip_count,
+			    (GLuint)info->format, info->width, info->height,
+			    info->array_size, sc->base.memory[i], 0);
 		}
 	}
 
-	glBindTexture(array_size == 1 ? GL_TEXTURE_2D : GL_TEXTURE_2D_ARRAY,
+	glBindTexture(info->array_size == 1 ? GL_TEXTURE_2D
+	                                    : GL_TEXTURE_2D_ARRAY,
 	              prev_texture);
 
 	return &sc->base.base;
diff --git a/src/xrt/compositor/client/comp_vk_client.c b/src/xrt/compositor/client/comp_vk_client.c
index d098b0908..62da4e20c 100644
--- a/src/xrt/compositor/client/comp_vk_client.c
+++ b/src/xrt/compositor/client/comp_vk_client.c
@@ -287,23 +287,14 @@ client_vk_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id)
 
 static struct xrt_swapchain *
 client_vk_swapchain_create(struct xrt_compositor *xc,
-                           enum xrt_swapchain_create_flags create,
-                           enum xrt_swapchain_usage_bits bits,
-                           int64_t format,
-                           uint32_t sample_count,
-                           uint32_t width,
-                           uint32_t height,
-                           uint32_t face_count,
-                           uint32_t array_size,
-                           uint32_t mip_count)
+                           struct xrt_swapchain_create_info *info)
 {
 	struct client_vk_compositor *c = client_vk_compositor(xc);
 	VkCommandBuffer cmd_buffer;
 	VkResult ret;
 
-	struct xrt_swapchain_fd *xscfd = xrt_comp_fd_create_swapchain(
-	    c->xcfd, create, bits, format, sample_count, width, height,
-	    face_count, array_size, mip_count);
+	struct xrt_swapchain_fd *xscfd =
+	    xrt_comp_fd_create_swapchain(c->xcfd, info);
 
 	if (xscfd == NULL) {
 		return NULL;
@@ -336,8 +327,9 @@ client_vk_swapchain_create(struct xrt_compositor *xc,
 
 	for (uint32_t i = 0; i < xsc->num_images; i++) {
 		ret = vk_create_image_from_fd(
-		    &c->vk, bits, format, width, height, array_size, mip_count,
-		    &xscfd->images[i], &sc->base.images[i], &sc->base.mems[i]);
+		    &c->vk, info->bits, info->format, info->width, info->height,
+		    info->array_size, info->mip_count, &xscfd->images[i],
+		    &sc->base.images[i], &sc->base.mems[i]);
 
 		// We have consumed this fd now, make sure it's not freed again.
 		xscfd->images[i].fd = -1;
@@ -402,7 +394,7 @@ client_vk_swapchain_create(struct xrt_compositor *xc,
 		VkImageMemoryBarrier acquire = {
 		    .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
 		    .srcAccessMask = 0,
-		    .dstAccessMask = vk_swapchain_access_flags(bits),
+		    .dstAccessMask = vk_swapchain_access_flags(info->bits),
 		    .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
 		    .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
 		    .srcQueueFamilyIndex = c->vk.queue_family_index,
@@ -413,7 +405,7 @@ client_vk_swapchain_create(struct xrt_compositor *xc,
 
 		VkImageMemoryBarrier release = {
 		    .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
-		    .srcAccessMask = vk_swapchain_access_flags(bits),
+		    .srcAccessMask = vk_swapchain_access_flags(info->bits),
 		    .dstAccessMask = 0,
 		    .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
 		    .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h
index 3d8aa43a6..ca790ae18 100644
--- a/src/xrt/compositor/main/comp_compositor.h
+++ b/src/xrt/compositor/main/comp_compositor.h
@@ -273,15 +273,7 @@ comp_compositor_garbage_collect(struct comp_compositor *c);
  */
 struct xrt_swapchain *
 comp_swapchain_create(struct xrt_compositor *xc,
-                      enum xrt_swapchain_create_flags create,
-                      enum xrt_swapchain_usage_bits bits,
-                      int64_t format,
-                      uint32_t sample_count,
-                      uint32_t width,
-                      uint32_t height,
-                      uint32_t face_count,
-                      uint32_t array_size,
-                      uint32_t mip_count);
+                      struct xrt_swapchain_create_info *info);
 
 /*!
  * Swapchain destruct is delayed until it is safe to destroy them, this function
diff --git a/src/xrt/compositor/main/comp_swapchain.c b/src/xrt/compositor/main/comp_swapchain.c
index cd69e99ea..aae03e126 100644
--- a/src/xrt/compositor/main/comp_swapchain.c
+++ b/src/xrt/compositor/main/comp_swapchain.c
@@ -223,15 +223,7 @@ err_image:
 
 struct xrt_swapchain *
 comp_swapchain_create(struct xrt_compositor *xc,
-                      enum xrt_swapchain_create_flags create,
-                      enum xrt_swapchain_usage_bits bits,
-                      int64_t format,
-                      uint32_t sample_count,
-                      uint32_t width,
-                      uint32_t height,
-                      uint32_t face_count,
-                      uint32_t array_size,
-                      uint32_t mip_count)
+                      struct xrt_swapchain_create_info *info)
 {
 	struct comp_compositor *c = comp_compositor(xc);
 	VkCommandBuffer cmd_buffer;
@@ -239,7 +231,7 @@ comp_swapchain_create(struct xrt_compositor *xc,
 	VkResult ret;
 
 
-	if ((create & XRT_SWAPCHAIN_CREATE_STATIC_IMAGE) != 0) {
+	if ((info->create & XRT_SWAPCHAIN_CREATE_STATIC_IMAGE) != 0) {
 		num_images = 1;
 	}
 
@@ -251,7 +243,7 @@ comp_swapchain_create(struct xrt_compositor *xc,
 	sc->base.base.num_images = num_images;
 	sc->c = c;
 
-	COMP_DEBUG(c, "CREATE %p %dx%d", (void *)sc, width, height);
+	COMP_DEBUG(c, "CREATE %p %dx%d", (void *)sc, info->width, info->height);
 
 	// Make sure the fds are invalid.
 	for (uint32_t i = 0; i < ARRAY_SIZE(sc->base.images); i++) {
@@ -259,10 +251,10 @@ comp_swapchain_create(struct xrt_compositor *xc,
 	}
 
 	for (uint32_t i = 0; i < num_images; i++) {
-		ret =
-		    create_image_fd(c, bits, format, width, height, array_size,
-		                    mip_count, &sc->images[i].image,
-		                    &sc->images[i].memory, &sc->base.images[i]);
+		ret = create_image_fd(
+		    c, info->bits, info->format, info->width, info->height,
+		    info->array_size, info->mip_count, &sc->images[i].image,
+		    &sc->images[i].memory, &sc->base.images[i]);
 		if (ret != VK_SUCCESS) {
 			//! @todo memory leak of image fds and swapchain
 			// see
@@ -282,12 +274,12 @@ comp_swapchain_create(struct xrt_compositor *xc,
 
 	for (uint32_t i = 0; i < num_images; i++) {
 		sc->images[i].views.alpha =
-		    U_TYPED_ARRAY_CALLOC(VkImageView, array_size);
+		    U_TYPED_ARRAY_CALLOC(VkImageView, info->array_size);
 		sc->images[i].views.no_alpha =
-		    U_TYPED_ARRAY_CALLOC(VkImageView, array_size);
-		sc->images[i].array_size = array_size;
+		    U_TYPED_ARRAY_CALLOC(VkImageView, info->array_size);
+		sc->images[i].array_size = info->array_size;
 
-		for (uint32_t layer = 0; layer < array_size; ++layer) {
+		for (uint32_t layer = 0; layer < info->array_size; ++layer) {
 			VkImageSubresourceRange subresource_range = {
 			    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
 			    .baseMipLevel = 0,
@@ -298,10 +290,11 @@ comp_swapchain_create(struct xrt_compositor *xc,
 
 
 			vk_create_view(&c->vk, sc->images[i].image,
-			               (VkFormat)format, subresource_range,
+			               (VkFormat)info->format,
+			               subresource_range,
 			               &sc->images[i].views.alpha[layer]);
 			vk_create_view_swizzle(
-			    &c->vk, sc->images[i].image, (VkFormat)format,
+			    &c->vk, sc->images[i].image, (VkFormat)info->format,
 			    subresource_range, components,
 			    &sc->images[i].views.no_alpha[layer]);
 		}
@@ -326,7 +319,7 @@ comp_swapchain_create(struct xrt_compositor *xc,
 	    .baseMipLevel = 0,
 	    .levelCount = 1,
 	    .baseArrayLayer = 0,
-	    .layerCount = array_size,
+	    .layerCount = info->array_size,
 	};
 
 	for (uint32_t i = 0; i < num_images; i++) {
diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h
index 6c3daa34e..d6f5d4b5f 100644
--- a/src/xrt/include/xrt/xrt_compositor.h
+++ b/src/xrt/include/xrt/xrt_compositor.h
@@ -378,6 +378,22 @@ union xrt_compositor_event {
 	struct xrt_compositor_event_state_change overlay;
 };
 
+/*!
+ * Swapchain creation info.
+ */
+struct xrt_swapchain_create_info
+{
+	enum xrt_swapchain_create_flags create;
+	enum xrt_swapchain_usage_bits bits;
+	int64_t format;
+	uint32_t sample_count;
+	uint32_t width;
+	uint32_t height;
+	uint32_t face_count;
+	uint32_t array_size;
+	uint32_t mip_count;
+};
+
 /*!
  * Session prepare information, mostly overlay extension data.
  */
@@ -409,16 +425,7 @@ struct xrt_compositor
 	 * Create a swapchain with a set of images.
 	 */
 	struct xrt_swapchain *(*create_swapchain)(
-	    struct xrt_compositor *xc,
-	    enum xrt_swapchain_create_flags create,
-	    enum xrt_swapchain_usage_bits bits,
-	    int64_t format,
-	    uint32_t sample_count,
-	    uint32_t width,
-	    uint32_t height,
-	    uint32_t face_count,
-	    uint32_t array_size,
-	    uint32_t mip_count);
+	    struct xrt_compositor *xc, struct xrt_swapchain_create_info *info);
 
 	/*!
 	 * Poll events from this compositor.
@@ -542,19 +549,9 @@ struct xrt_compositor
  */
 static inline struct xrt_swapchain *
 xrt_comp_create_swapchain(struct xrt_compositor *xc,
-                          enum xrt_swapchain_create_flags create,
-                          enum xrt_swapchain_usage_bits bits,
-                          int64_t format,
-                          uint32_t sample_count,
-                          uint32_t width,
-                          uint32_t height,
-                          uint32_t face_count,
-                          uint32_t array_size,
-                          uint32_t mip_count)
+                          struct xrt_swapchain_create_info *info)
 {
-	return xc->create_swapchain(xc, create, bits, format, sample_count,
-	                            width, height, face_count, array_size,
-	                            mip_count);
+	return xc->create_swapchain(xc, info);
 }
 
 /*!
@@ -922,19 +919,10 @@ struct xrt_compositor_fd
  */
 static inline struct xrt_swapchain_fd *
 xrt_comp_fd_create_swapchain(struct xrt_compositor_fd *xcfd,
-                             enum xrt_swapchain_create_flags create,
-                             enum xrt_swapchain_usage_bits bits,
-                             int64_t format,
-                             uint32_t sample_count,
-                             uint32_t width,
-                             uint32_t height,
-                             uint32_t face_count,
-                             uint32_t array_size,
-                             uint32_t mip_count)
+                             struct xrt_swapchain_create_info *info)
 {
-	struct xrt_swapchain *xsc = xrt_comp_create_swapchain(
-	    &xcfd->base, create, bits, format, sample_count, width, height,
-	    face_count, array_size, mip_count);
+	struct xrt_swapchain *xsc =
+	    xrt_comp_create_swapchain(&xcfd->base, info);
 	return (struct xrt_swapchain_fd *)xsc;
 }
 
diff --git a/src/xrt/ipc/ipc_client_compositor.c b/src/xrt/ipc/ipc_client_compositor.c
index 3668e457c..3e8dd230b 100644
--- a/src/xrt/ipc/ipc_client_compositor.c
+++ b/src/xrt/ipc/ipc_client_compositor.c
@@ -171,15 +171,7 @@ ipc_compositor_swapchain_release_image(struct xrt_swapchain *xsc,
 
 static struct xrt_swapchain *
 ipc_compositor_swapchain_create(struct xrt_compositor *xc,
-                                enum xrt_swapchain_create_flags create,
-                                enum xrt_swapchain_usage_bits bits,
-                                int64_t format,
-                                uint32_t sample_count,
-                                uint32_t width,
-                                uint32_t height,
-                                uint32_t face_count,
-                                uint32_t array_size,
-                                uint32_t mip_count)
+                                struct xrt_swapchain_create_info *info)
 {
 	struct ipc_client_compositor *icc = ipc_client_compositor(xc);
 
@@ -190,15 +182,7 @@ ipc_compositor_swapchain_create(struct xrt_compositor *xc,
 	uint64_t size;
 
 	r = ipc_call_swapchain_create(icc->ipc_c,             // connection
-	                              create,                 // in
-	                              bits,                   // in
-	                              format,                 // in
-	                              sample_count,           // in
-	                              width,                  // in
-	                              height,                 // in
-	                              face_count,             // in
-	                              array_size,             // in
-	                              mip_count,              // in
+	                              info,                   // in
 	                              &handle,                // out
 	                              &num_images,            // out
 	                              &size,                  // out
diff --git a/src/xrt/ipc/ipc_server_client.c b/src/xrt/ipc/ipc_server_client.c
index 857a253e8..698551e5b 100644
--- a/src/xrt/ipc/ipc_server_client.c
+++ b/src/xrt/ipc/ipc_server_client.c
@@ -273,15 +273,7 @@ ipc_handle_system_set_focused_client(volatile struct ipc_client_state *ics,
 
 xrt_result_t
 ipc_handle_swapchain_create(volatile struct ipc_client_state *ics,
-                            enum xrt_swapchain_create_flags create,
-                            enum xrt_swapchain_usage_bits bits,
-                            int64_t format,
-                            uint32_t sample_count,
-                            uint32_t width,
-                            uint32_t height,
-                            uint32_t face_count,
-                            uint32_t array_size,
-                            uint32_t mip_count,
+                            struct xrt_swapchain_create_info *info,
                             uint32_t *out_id,
                             uint32_t *out_num_images,
                             uint64_t *out_size,
@@ -306,17 +298,7 @@ ipc_handle_swapchain_create(volatile struct ipc_client_state *ics,
 	ics->num_swapchains++;
 
 	// create the swapchain
-	struct xrt_swapchain *xsc =
-	    xrt_comp_create_swapchain(ics->xc,      // Compositor
-	                              create,       // Flags
-	                              bits,         // Usage
-	                              format,       // Format
-	                              sample_count, // Sample count
-	                              width,        // Width
-	                              height,       // Height
-	                              face_count,   // Face count
-	                              array_size,   // Array size
-	                              mip_count);   // Mip count
+	struct xrt_swapchain *xsc = xrt_comp_create_swapchain(ics->xc, info);
 
 	uint32_t num_images = xsc->num_images;
 
@@ -324,9 +306,9 @@ ipc_handle_swapchain_create(volatile struct ipc_client_state *ics,
 
 	ics->xscs[index] = xsc;
 	ics->swapchain_data[index].active = true;
-	ics->swapchain_data[index].width = width;
-	ics->swapchain_data[index].height = height;
-	ics->swapchain_data[index].format = format;
+	ics->swapchain_data[index].width = info->width;
+	ics->swapchain_data[index].height = info->height;
+	ics->swapchain_data[index].format = info->format;
 	ics->swapchain_data[index].num_images = num_images;
 
 	// return our result to the caller.
diff --git a/src/xrt/ipc/proto.json b/src/xrt/ipc/proto.json
index fcdd0ccf8..b4f64bb9a 100644
--- a/src/xrt/ipc/proto.json
+++ b/src/xrt/ipc/proto.json
@@ -98,15 +98,7 @@
 
 	"swapchain_create": {
 		"in": [
-			{"name": "create", "type": "enum xrt_swapchain_create_flags"},
-			{"name": "bits", "type": "enum xrt_swapchain_usage_bits"},
-			{"name": "format", "type": "int64_t"},
-			{"name": "sample_count", "type": "uint32_t"},
-			{"name": "width", "type": "uint32_t"},
-			{"name": "height", "type": "uint32_t"},
-			{"name": "face_count", "type": "uint32_t"},
-			{"name": "array_size", "type": "uint32_t"},
-			{"name": "mip_count", "type": "uint32_t"}
+			{"name": "info", "type": "struct xrt_swapchain_create_info"}
 		],
 		"out": [
 			{"name": "id", "type": "uint32_t"},
diff --git a/src/xrt/state_trackers/oxr/oxr_swapchain.c b/src/xrt/state_trackers/oxr/oxr_swapchain.c
index 60d76c221..3aaa0bff6 100644
--- a/src/xrt/state_trackers/oxr/oxr_swapchain.c
+++ b/src/xrt/state_trackers/oxr/oxr_swapchain.c
@@ -198,11 +198,19 @@ oxr_create_swapchain(struct oxr_logger *log,
                      const XrSwapchainCreateInfo *createInfo,
                      struct oxr_swapchain **out_swapchain)
 {
-	struct xrt_swapchain *xsc = xrt_comp_create_swapchain(
-	    sess->compositor, convert_create_flags(createInfo->createFlags),
-	    convert_usage_bits(createInfo->usageFlags), createInfo->format,
-	    createInfo->sampleCount, createInfo->width, createInfo->height,
-	    createInfo->faceCount, createInfo->arraySize, createInfo->mipCount);
+	struct xrt_swapchain_create_info info;
+	info.create = convert_create_flags(createInfo->createFlags);
+	info.bits = convert_usage_bits(createInfo->usageFlags);
+	info.format = createInfo->format;
+	info.sample_count = createInfo->sampleCount;
+	info.width = createInfo->width;
+	info.height = createInfo->height;
+	info.face_count = createInfo->faceCount;
+	info.array_size = createInfo->arraySize;
+	info.mip_count = createInfo->mipCount;
+
+	struct xrt_swapchain *xsc =
+	    xrt_comp_create_swapchain(sess->compositor, &info);
 
 	if (xsc == NULL) {
 		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,