diff --git a/CMakeLists.txt b/CMakeLists.txt
index 14262e65..f915444c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -239,11 +239,11 @@ if(ENABLE_VULKAN)
 	)
 
 	set(RENDERER_VK_INCLUDE_FILES include/renderer_vk/renderer_vk.hpp
-		include/renderer_vk/vulkan_api.hpp include/renderer_vk/vk_debug.hpp
+		include/renderer_vk/vulkan_api.hpp include/renderer_vk/vk_debug.hpp include/renderer_vk/vk_memory.hpp
 	)
 
 	set(RENDERER_VK_SOURCE_FILES src/core/renderer_vk/renderer_vk.cpp
-		src/core/renderer_vk/vulkan_api.cpp src/core/renderer_vk/vk_debug.cpp
+		src/core/renderer_vk/vulkan_api.cpp src/core/renderer_vk/vk_debug.cpp src/core/renderer_vk/vk_memory.cpp
 	)
 
     set(HEADER_FILES ${HEADER_FILES} ${RENDERER_VK_INCLUDE_FILES})
diff --git a/include/renderer_vk/renderer_vk.hpp b/include/renderer_vk/renderer_vk.hpp
index 6ebbcb7e..9545a4d9 100644
--- a/include/renderer_vk/renderer_vk.hpp
+++ b/include/renderer_vk/renderer_vk.hpp
@@ -37,6 +37,8 @@ class RendererVK final : public Renderer {
 	// Todo: make this a configuration option
 	static constexpr usize frameBufferingCount = 3;
 
+	vk::UniqueDeviceMemory framebufferMemory = {};
+
 	// Frame-buffering data
 	// Each vector is `frameBufferingCount` in size
 	std::vector<vk::UniqueCommandBuffer> frameCommandBuffers = {};
@@ -44,6 +46,9 @@ class RendererVK final : public Renderer {
 	std::vector<vk::UniqueSemaphore> renderFinishedSemaphore = {};
 	std::vector<vk::UniqueFence> frameFinishedFences = {};
 
+	std::vector<vk::UniqueImage> topScreenImages = {};
+	std::vector<vk::UniqueImage> bottomScreenImages = {};
+
 	// Recreate the swapchain, possibly re-using the old one in the case of a resize
 	vk::Result recreateSwapchain(vk::SurfaceKHR surface, vk::Extent2D swapchainExtent);
 
diff --git a/include/renderer_vk/vk_memory.hpp b/include/renderer_vk/vk_memory.hpp
new file mode 100644
index 00000000..8bf3f25d
--- /dev/null
+++ b/include/renderer_vk/vk_memory.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <span>
+#include <type_traits>
+#include <utility>
+
+#include "helpers.hpp"
+#include "vulkan_api.hpp"
+
+namespace Vulkan {
+
+	// Will try to find a memory type that is suitable for the given requirements.
+	// Returns -1 if no suitable memory type was found.
+	s32 findMemoryTypeIndex(
+		vk::PhysicalDevice physicalDevice, u32 memoryTypeMask, vk::MemoryPropertyFlags memoryProperties,
+		vk::MemoryPropertyFlags memoryExcludeProperties = vk::MemoryPropertyFlagBits::eProtected
+	);
+
+	// Given an array of valid Vulkan image-handles or buffer-handles, these
+	// functions will allocate a single block of device-memory for all of them
+	// and bind them consecutively.
+	// There may be a case that all the buffers or images cannot be allocated
+	// to the same device memory due to their required memory-type.
+	std::tuple<vk::Result, vk::UniqueDeviceMemory> commitImageHeap(
+		vk::Device device, vk::PhysicalDevice physicalDevice, const std::span<const vk::Image> images,
+		vk::MemoryPropertyFlags memoryProperties = vk::MemoryPropertyFlagBits::eDeviceLocal,
+		vk::MemoryPropertyFlags memoryExcludeProperties = vk::MemoryPropertyFlagBits::eProtected
+	);
+
+	std::tuple<vk::Result, vk::UniqueDeviceMemory> commitBufferHeap(
+		vk::Device device, vk::PhysicalDevice physicalDevice, const std::span<const vk::Buffer> buffers,
+		vk::MemoryPropertyFlags memoryProperties = vk::MemoryPropertyFlagBits::eDeviceLocal,
+		vk::MemoryPropertyFlags memoryExcludeProperties = vk::MemoryPropertyFlagBits::eProtected
+	);
+
+}  // namespace Vulkan
\ No newline at end of file
diff --git a/src/core/renderer_vk/renderer_vk.cpp b/src/core/renderer_vk/renderer_vk.cpp
index 4b6956d5..310fdec3 100644
--- a/src/core/renderer_vk/renderer_vk.cpp
+++ b/src/core/renderer_vk/renderer_vk.cpp
@@ -1,12 +1,14 @@
 #include "renderer_vk/renderer_vk.hpp"
 
 #include <limits>
+#include <ranges>
 #include <span>
 #include <unordered_set>
 
 #include "SDL_vulkan.h"
 #include "helpers.hpp"
 #include "renderer_vk/vk_debug.hpp"
+#include "renderer_vk/vk_memory.hpp"
 
 // Finds the first queue family that satisfies `queueMask` and excludes `queueExcludeMask` bits
 // Returns -1 if not found
@@ -221,15 +223,27 @@ void RendererVK::display() {
 
 		Vulkan::DebugLabelScope debugScope(frameCommandBuffer.get(), frameScopeColor, "Frame");
 
-		// Prepare for color-clear
 		if (swapchainImageIndex != swapchainImageInvalid) {
+			// Prepare images for color-clear
 			frameCommandBuffer->pipelineBarrier(
 				vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags(), {}, {},
-				{vk::ImageMemoryBarrier(
-					vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined,
-					vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, swapchainImages[swapchainImageIndex],
-					vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
-				)}
+				{
+					vk::ImageMemoryBarrier(
+						vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined,
+						vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, swapchainImages[swapchainImageIndex],
+						vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
+					),
+					vk::ImageMemoryBarrier(
+						vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined,
+						vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
+						topScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
+					),
+					vk::ImageMemoryBarrier(
+						vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined,
+						vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
+						bottomScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
+					),
+				}
 			);
 
 			static const std::array<float, 4> clearColor = {{0.0f, 0.0f, 0.0f, 1.0f}};
@@ -238,6 +252,56 @@ void RendererVK::display() {
 				vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
 			);
 
+			//// Simulated rendering work, just clear the screens and get them ready to blit(transfer-src layout)
+			{
+				static const std::array<float, 4> topClearColor = {{1.0f, 0.0f, 0.0f, 1.0f}};
+				static const std::array<float, 4> bottomClearColor = {{0.0f, 1.0f, 0.0f, 1.0f}};
+				frameCommandBuffer->clearColorImage(
+					topScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferDstOptimal, topClearColor,
+					vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
+				);
+				frameCommandBuffer->clearColorImage(
+					bottomScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferDstOptimal, bottomClearColor,
+					vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
+				);
+				frameCommandBuffer->pipelineBarrier(
+					vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags(), {}, {},
+					{
+						vk::ImageMemoryBarrier(
+							vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eTransferDstOptimal,
+							vk::ImageLayout::eTransferSrcOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
+							topScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
+						),
+						vk::ImageMemoryBarrier(
+							vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eTransferDstOptimal,
+							vk::ImageLayout::eTransferSrcOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
+							bottomScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
+						),
+					}
+				);
+			}
+
+			// Blip top/bottom screen onto swapchain image
+			{
+				static const vk::ImageBlit topScreenBlit(
+					vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), {vk::Offset3D{}, vk::Offset3D{400, 240, 1}},
+					vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), {vk::Offset3D{}, vk::Offset3D{400, 240, 1}}
+				);
+				static const vk::ImageBlit bottomScreenBlit(
+					vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), {vk::Offset3D{}, vk::Offset3D{320, 240, 1}},
+					vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1),
+					{vk::Offset3D{(400 / 2) - (320 / 2), 240, 0}, vk::Offset3D{(400 / 2) + (320 / 2), 240 + 240, 1}}
+				);
+				frameCommandBuffer->blitImage(
+					topScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferSrcOptimal, swapchainImages[swapchainImageIndex],
+					vk::ImageLayout::eTransferDstOptimal, {topScreenBlit}, vk::Filter::eNearest
+				);
+				frameCommandBuffer->blitImage(
+					bottomScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferSrcOptimal, swapchainImages[swapchainImageIndex],
+					vk::ImageLayout::eTransferDstOptimal, {bottomScreenBlit}, vk::Filter::eNearest
+				);
+			}
+
 			// Prepare for present
 			frameCommandBuffer->pipelineBarrier(
 				vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::DependencyFlags(), {}, {},
@@ -555,14 +619,74 @@ void RendererVK::initGraphicsContext(SDL_Window* window) {
 	swapImageFreeSemaphore.resize(frameBufferingCount);
 	renderFinishedSemaphore.resize(frameBufferingCount);
 	frameFinishedFences.resize(frameBufferingCount);
-	vk::Extent2D swapchainExtent;
-	{
-		int windowWidth, windowHeight;
-		SDL_Vulkan_GetDrawableSize(window, &windowWidth, &windowHeight);
-		swapchainExtent.width = windowWidth;
-		swapchainExtent.height = windowHeight;
+
+	vk::ImageCreateInfo topScreenInfo = {};
+	topScreenInfo.setImageType(vk::ImageType::e2D);
+	topScreenInfo.setFormat(vk::Format::eR8G8B8A8Unorm);
+	topScreenInfo.setExtent(vk::Extent3D(400, 240, 1));
+	topScreenInfo.setMipLevels(1);
+	topScreenInfo.setArrayLayers(2);  // Two image layers, for 3D mode
+	topScreenInfo.setSamples(vk::SampleCountFlagBits::e1);
+	topScreenInfo.setTiling(vk::ImageTiling::eOptimal);
+	topScreenInfo.setUsage(
+		vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eInputAttachment | vk::ImageUsageFlagBits::eTransferSrc |
+		vk::ImageUsageFlagBits::eTransferDst
+	);
+	topScreenInfo.setSharingMode(vk::SharingMode::eExclusive);
+	topScreenInfo.setInitialLayout(vk::ImageLayout::eUndefined);
+
+	vk::ImageCreateInfo bottomScreenInfo = topScreenInfo;
+	bottomScreenInfo.setExtent(vk::Extent3D(320, 240, 1));
+	bottomScreenInfo.setArrayLayers(1);
+
+	topScreenImages.resize(frameBufferingCount);
+	bottomScreenImages.resize(frameBufferingCount);
+
+	for (usize i = 0; i < frameBufferingCount; i++) {
+		if (auto createResult = device->createSemaphoreUnique(semaphoreInfo); createResult.result == vk::Result::eSuccess) {
+			swapImageFreeSemaphore[i] = std::move(createResult.value);
+		} else {
+			Helpers::panic("Error creating 'present-ready' semaphore: %s\n", vk::to_string(createResult.result).c_str());
+		}
+
+		if (auto createResult = device->createSemaphoreUnique(semaphoreInfo); createResult.result == vk::Result::eSuccess) {
+			renderFinishedSemaphore[i] = std::move(createResult.value);
+		} else {
+			Helpers::panic("Error creating 'post-render' semaphore: %s\n", vk::to_string(createResult.result).c_str());
+		}
+
+		if (auto createResult = device->createFenceUnique(fenceInfo); createResult.result == vk::Result::eSuccess) {
+			frameFinishedFences[i] = std::move(createResult.value);
+		} else {
+			Helpers::panic("Error creating 'present-ready' semaphore: %s\n", vk::to_string(createResult.result).c_str());
+		}
+
+		if (auto createResult = device->createImageUnique(topScreenInfo); createResult.result == vk::Result::eSuccess) {
+			topScreenImages[i] = std::move(createResult.value);
+		} else {
+			Helpers::panic("Error creating top-screen image: %s\n", vk::to_string(createResult.result).c_str());
+		}
+
+		if (auto createResult = device->createImageUnique(bottomScreenInfo); createResult.result == vk::Result::eSuccess) {
+			bottomScreenImages[i] = std::move(createResult.value);
+		} else {
+			Helpers::panic("Error creating bottom-screen image: %s\n", vk::to_string(createResult.result).c_str());
+		}
+	}
+
+	// Commit memory to all of our images
+	{
+		const auto getImage = [](const vk::UniqueImage& image) -> vk::Image { return image.get(); };
+		std::vector<vk::Image> images;
+		std::ranges::transform(topScreenImages, std::back_inserter(images), getImage);
+		std::ranges::transform(bottomScreenImages, std::back_inserter(images), getImage);
+
+		if (auto [result, imageMemory] = Vulkan::commitImageHeap(device.get(), physicalDevice, images); result == vk::Result::eSuccess) {
+			framebufferMemory = std::move(imageMemory);
+		} else {
+			Helpers::panic("Error allocating framebuffer memory: %s\n", vk::to_string(result).c_str());
+		}
 	}
-	recreateSwapchain(surface.get(), swapchainExtent);
 }
 
 void RendererVK::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) {}
diff --git a/src/core/renderer_vk/vk_memory.cpp b/src/core/renderer_vk/vk_memory.cpp
new file mode 100644
index 00000000..c9087719
--- /dev/null
+++ b/src/core/renderer_vk/vk_memory.cpp
@@ -0,0 +1,174 @@
+#include "renderer_vk/vk_memory.hpp"
+
+namespace Vulkan {
+
+	static constexpr vk::DeviceSize alignUp(vk::DeviceSize value, std::size_t size) {
+		const vk::DeviceSize mod = static_cast<vk::DeviceSize>(value % size);
+		value -= mod;
+		return static_cast<vk::DeviceSize>(mod == vk::DeviceSize{0} ? value : value + size);
+	}
+
+	// Given a speculative heap-allocation, defined by its current size and
+	// memory-type bits, appends a memory requirements structure to it, updating
+	// both the size and the required memory-type-bits. Returns the offset within
+	// the heap for the current MemoryRequirements Todo: Sun Apr 23 13:28:25 PDT
+	// 2023 Rather than using a running-size of the heap, look at all of the memory
+	// requests and optimally create a packing for all of the offset and alignment
+	// requirements. Such as by satisfying all of the largest alignments first, and
+	// then the smallest, to reduce padding
+	static vk::DeviceSize commitMemoryRequestToHeap(
+		const vk::MemoryRequirements& curMemoryRequirements, vk::DeviceSize& curHeapEnd, u32& curMemoryTypeBits, vk::DeviceSize sizeAlignment
+	) {
+		// Accumulate a mask of all the memory types that satisfies each of the
+		// handles
+		curMemoryTypeBits &= curMemoryRequirements.memoryTypeBits;
+
+		// Pad up the memory sizes so they are not considered aliasing
+		const vk::DeviceSize curMemoryOffset = alignUp(curHeapEnd, curMemoryRequirements.alignment);
+		// Pad the size by the required size-alignment.
+		// Intended for BufferImageGranularity
+		const vk::DeviceSize curMemorySize = alignUp(curMemoryRequirements.size, sizeAlignment);
+
+		curHeapEnd = (curMemoryOffset + curMemorySize);
+		return curMemoryOffset;
+	}
+
+	s32 findMemoryTypeIndex(
+		vk::PhysicalDevice physicalDevice, u32 memoryTypeMask, vk::MemoryPropertyFlags memoryProperties,
+		vk::MemoryPropertyFlags memoryExcludeProperties
+	) {
+		const vk::PhysicalDeviceMemoryProperties deviceMemoryProperties = physicalDevice.getMemoryProperties();
+		// Iterate the physical device's memory types until we find a match
+		for (std::size_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++) {
+			if(
+			// Is within memory type mask
+			(((memoryTypeMask >> i) & 0b1) == 0b1) &&
+			// Has property flags
+			(deviceMemoryProperties.memoryTypes[i].propertyFlags
+			 & memoryProperties)
+				== memoryProperties
+			&&
+			// None of the excluded properties are enabled
+			!(deviceMemoryProperties.memoryTypes[i].propertyFlags
+			  & memoryExcludeProperties) )
+		{
+				return static_cast<u32>(i);
+			}
+		}
+
+		return -1;
+	}
+
+	std::tuple<vk::Result, vk::UniqueDeviceMemory> commitImageHeap(
+		vk::Device device, vk::PhysicalDevice physicalDevice, const std::span<const vk::Image> images, vk::MemoryPropertyFlags memoryProperties,
+		vk::MemoryPropertyFlags memoryExcludeProperties
+	) {
+		vk::MemoryAllocateInfo imageHeapAllocInfo = {};
+		u32 imageHeapMemoryTypeBits = 0xFFFFFFFF;
+		std::vector<vk::BindImageMemoryInfo> imageHeapBinds;
+
+		const vk::DeviceSize bufferImageGranularity = physicalDevice.getProperties().limits.bufferImageGranularity;
+
+		for (const vk::Image& curImage : images) {
+			const vk::DeviceSize curBindOffset = commitMemoryRequestToHeap(
+				device.getImageMemoryRequirements(curImage), imageHeapAllocInfo.allocationSize, imageHeapMemoryTypeBits, bufferImageGranularity
+			);
+
+			if (imageHeapMemoryTypeBits == 0) {
+				// No possible memory heap for all of the images to share
+				return std::make_tuple(vk::Result::eErrorOutOfDeviceMemory, vk::UniqueDeviceMemory());
+			}
+
+			// Put nullptr for the device memory for now
+			imageHeapBinds.emplace_back(vk::BindImageMemoryInfo{curImage, nullptr, curBindOffset});
+		}
+
+		const s32 memoryTypeIndex = findMemoryTypeIndex(physicalDevice, imageHeapMemoryTypeBits, memoryProperties, memoryExcludeProperties);
+
+		if (memoryTypeIndex < 0) {
+			// Unable to find a memory heap that satisfies all the images
+			return std::make_tuple(vk::Result::eErrorOutOfDeviceMemory, vk::UniqueDeviceMemory());
+		}
+
+		imageHeapAllocInfo.memoryTypeIndex = memoryTypeIndex;
+
+		vk::UniqueDeviceMemory imageHeapMemory = {};
+
+		if (auto allocResult = device.allocateMemoryUnique(imageHeapAllocInfo); allocResult.result == vk::Result::eSuccess) {
+			imageHeapMemory = std::move(allocResult.value);
+		} else {
+			return std::make_tuple(allocResult.result, vk::UniqueDeviceMemory());
+		}
+
+		// Assign the device memory to the bindings
+		for (vk::BindImageMemoryInfo& curBind : imageHeapBinds) {
+			curBind.memory = imageHeapMemory.get();
+		}
+
+		// Now bind them all in one call
+		if (const vk::Result bindResult = device.bindImageMemory2(imageHeapBinds); bindResult == vk::Result::eSuccess) {
+			// Binding memory succeeded
+		} else {
+			return std::make_tuple(bindResult, vk::UniqueDeviceMemory());
+		}
+
+		return std::make_tuple(vk::Result::eSuccess, std::move(imageHeapMemory));
+	}
+
+	std::tuple<vk::Result, vk::UniqueDeviceMemory> commitBufferHeap(
+		vk::Device device, vk::PhysicalDevice physicalDevice, const std::span<const vk::Buffer> buffers, vk::MemoryPropertyFlags memoryProperties,
+		vk::MemoryPropertyFlags memoryExcludeProperties
+	) {
+		vk::MemoryAllocateInfo bufferHeapAllocInfo = {};
+		u32 bufferHeapMemoryTypeBits = 0xFFFFFFFF;
+		std::vector<vk::BindBufferMemoryInfo> bufferHeapBinds;
+
+		const vk::DeviceSize bufferImageGranularity = physicalDevice.getProperties().limits.bufferImageGranularity;
+
+		for (const vk::Buffer& curBuffer : buffers) {
+			const vk::DeviceSize curBindOffset = commitMemoryRequestToHeap(
+				device.getBufferMemoryRequirements(curBuffer), bufferHeapAllocInfo.allocationSize, bufferHeapMemoryTypeBits, bufferImageGranularity
+			);
+
+			if (bufferHeapMemoryTypeBits == 0) {
+				// No possible memory heap for all of the buffers to share
+				return std::make_tuple(vk::Result::eErrorOutOfDeviceMemory, vk::UniqueDeviceMemory());
+			}
+
+			// Put nullptr for the device memory for now
+			bufferHeapBinds.emplace_back(vk::BindBufferMemoryInfo{curBuffer, nullptr, curBindOffset});
+		}
+
+		const s32 memoryTypeIndex = findMemoryTypeIndex(physicalDevice, bufferHeapMemoryTypeBits, memoryProperties, memoryExcludeProperties);
+
+		if (memoryTypeIndex < 0) {
+			// Unable to find a memory heap that satisfies all the buffers
+			return std::make_tuple(vk::Result::eErrorOutOfDeviceMemory, vk::UniqueDeviceMemory());
+		}
+
+		bufferHeapAllocInfo.memoryTypeIndex = memoryTypeIndex;
+
+		vk::UniqueDeviceMemory bufferHeapMemory = {};
+
+		if (auto allocResult = device.allocateMemoryUnique(bufferHeapAllocInfo); allocResult.result == vk::Result::eSuccess) {
+			bufferHeapMemory = std::move(allocResult.value);
+		} else {
+			return std::make_tuple(allocResult.result, vk::UniqueDeviceMemory());
+		}
+
+		// Assign the device memory to the bindings
+		for (vk::BindBufferMemoryInfo& curBind : bufferHeapBinds) {
+			curBind.memory = bufferHeapMemory.get();
+		}
+
+		// Now bind them all in one call
+		if (const vk::Result bindResult = device.bindBufferMemory2(bufferHeapBinds); bindResult == vk::Result::eSuccess) {
+			// Binding memory succeeded
+		} else {
+			return std::make_tuple(bindResult, vk::UniqueDeviceMemory());
+		}
+
+		return std::make_tuple(vk::Result::eSuccess, std::move(bufferHeapMemory));
+	}
+
+}  // namespace Vulkan
\ No newline at end of file