Index: crash-logger.cpp
===================================================================
--- crash-logger.cpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
+++ crash-logger.cpp	(revision 87c8f1abdf1a94f87d0f0051fbc134d1ec1fa9ee)
@@ -158,5 +158,4 @@
       char* begin_name = NULL;
       char* begin_offset = NULL;
-      char* end_offset = NULL;
 
 #ifdef MAC
@@ -200,4 +199,6 @@
       write(fd_out, "\n", 1);
 #else
+      char* end_offset = NULL;
+
       for (char *p = symbollist[i]; *p; p++) {
          if (*p == '(') {
Index: graphics-pipeline_vulkan.cpp
===================================================================
--- graphics-pipeline_vulkan.cpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
+++ graphics-pipeline_vulkan.cpp	(revision 87c8f1abdf1a94f87d0f0051fbc134d1ec1fa9ee)
@@ -5,14 +5,20 @@
 #include <iostream>
 
+#include "vulkan-utils.hpp"
+
 using namespace std;
 
 // TODO: Remove any instances of cout and instead throw exceptions
 
-GraphicsPipeline_Vulkan::GraphicsPipeline_Vulkan(VkDevice device, VkRenderPass renderPass, Viewport viewport,
-      int vertexSize) {
+GraphicsPipeline_Vulkan::GraphicsPipeline_Vulkan(VkPhysicalDevice physicalDevice, VkDevice device,
+      VkRenderPass renderPass, Viewport viewport, int vertexSize) {
+   this->physicalDevice = physicalDevice;
    this->device = device;
    this->renderPass = renderPass;
    this->viewport = viewport;
 
+   // Since there is only one array of vertex data, we use binding = 0
+   // I'll probably do that for the foreseeable future
+   // I can calculate the stride myself given info about all the varying attributes
    this->bindingDescription.binding = 0;
    this->bindingDescription.stride = vertexSize;
@@ -21,4 +27,56 @@
 
 GraphicsPipeline_Vulkan::~GraphicsPipeline_Vulkan() {
+}
+
+void GraphicsPipeline_Vulkan::createVertexBuffer(const void* bufferData, int vertexSize,
+      VkCommandPool commandPool, VkQueue graphicsQueue) {
+   VkDeviceSize bufferSize = numVertices * vertexSize;
+   VkDeviceSize bufferCapacity = vertexCapacity * vertexSize;
+
+   VkBuffer stagingBuffer;
+   VkDeviceMemory stagingBufferMemory;
+   VulkanUtils::createBuffer(device, physicalDevice, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+      stagingBuffer, stagingBufferMemory);
+
+   void* data;
+   vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
+   memcpy(data, bufferData, (size_t) bufferSize);
+   vkUnmapMemory(device, stagingBufferMemory);
+
+   VulkanUtils::createBuffer(device, physicalDevice, bufferCapacity,
+      VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
+      VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);
+
+   VulkanUtils::copyBuffer(device, commandPool, stagingBuffer, vertexBuffer, 0, 0, bufferSize, graphicsQueue);
+
+   vkDestroyBuffer(device, stagingBuffer, nullptr);
+   vkFreeMemory(device, stagingBufferMemory, nullptr);
+}
+
+void GraphicsPipeline_Vulkan::createIndexBuffer(const void* bufferData, int indexSize,
+      VkCommandPool commandPool, VkQueue graphicsQueue) {
+   VkDeviceSize bufferSize = numIndices * indexSize;
+   VkDeviceSize bufferCapacity = indexCapacity * indexSize;
+
+   VkBuffer stagingBuffer;
+   VkDeviceMemory stagingBufferMemory;
+   VulkanUtils::createBuffer(device, physicalDevice, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+      stagingBuffer, stagingBufferMemory);
+
+   void* data;
+   vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
+   memcpy(data, bufferData, (size_t) bufferSize);
+   vkUnmapMemory(device, stagingBufferMemory);
+
+   VulkanUtils::createBuffer(device, physicalDevice, bufferCapacity,
+      VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
+      VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
+
+   VulkanUtils::copyBuffer(device, commandPool, stagingBuffer, indexBuffer, 0, 0, bufferSize, graphicsQueue);
+
+   vkDestroyBuffer(device, stagingBuffer, nullptr);
+   vkFreeMemory(device, stagingBufferMemory, nullptr);
 }
 
@@ -313,10 +371,15 @@
 
 void GraphicsPipeline_Vulkan::cleanup() {
-   vkDestroyPipeline(this->device, this->pipeline, nullptr);
-   vkDestroyDescriptorPool(this->device, this->descriptorPool, nullptr);
-   vkDestroyPipelineLayout(this->device, this->pipelineLayout, nullptr);
+   vkDestroyPipeline(device, pipeline, nullptr);
+   vkDestroyDescriptorPool(device, descriptorPool, nullptr);
+   vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
 }
 
 void GraphicsPipeline_Vulkan::cleanupBuffers() {
-   vkDestroyDescriptorSetLayout(this->device, this->descriptorSetLayout, nullptr);
-}
+   vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
+
+   vkDestroyBuffer(device, vertexBuffer, nullptr);
+   vkFreeMemory(device, vertexBufferMemory, nullptr);
+   vkDestroyBuffer(device, indexBuffer, nullptr);
+   vkFreeMemory(device, indexBufferMemory, nullptr);
+}
Index: graphics-pipeline_vulkan.hpp
===================================================================
--- graphics-pipeline_vulkan.hpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
+++ graphics-pipeline_vulkan.hpp	(revision 87c8f1abdf1a94f87d0f0051fbc134d1ec1fa9ee)
@@ -20,6 +20,16 @@
 class GraphicsPipeline_Vulkan : public GraphicsPipeline {
    public:
-      GraphicsPipeline_Vulkan(VkDevice device, VkRenderPass renderPass, Viewport viewport, int vertexSize);
+      GraphicsPipeline_Vulkan(VkPhysicalDevice physicalDevice, VkDevice device, VkRenderPass renderPass,
+         Viewport viewport, int vertexSize);
       ~GraphicsPipeline_Vulkan();
+
+      template<class VertexType, class IndexType>
+      void bindData(const vector<VertexType>& vertices, const vector<IndexType>& indices,
+         VkCommandPool commandPool, VkQueue graphicsQueue);
+
+      void createVertexBuffer(const void* bufferData, int vertexSize, VkCommandPool commandPool,
+         VkQueue graphicsQueue);
+      void createIndexBuffer(const void* bufferData, int indexSize, VkCommandPool commandPool,
+         VkQueue graphicsQueue);
 
       // Maybe I should rename these to addVertexAttribute (addVaryingAttribute) and addUniformAttribute
@@ -44,4 +54,5 @@
       vector<char> readFile(const string& filename);
 
+      VkPhysicalDevice physicalDevice;
       VkDevice device;
       VkRenderPass renderPass;
@@ -58,5 +69,29 @@
       VkDescriptorPool descriptorPool;
       vector<VkDescriptorSet> descriptorSets;
+
+      size_t numVertices;
+      size_t vertexCapacity;
+      VkBuffer vertexBuffer;
+      VkDeviceMemory vertexBufferMemory;
+
+      size_t numIndices;
+      size_t indexCapacity;
+      VkBuffer indexBuffer;
+      VkDeviceMemory indexBufferMemory;
 };
 
+// TODO: Probably better to template the whole class and to also combine this function
+// and the constructor since I call this right after the constructor anyway
+template<class VertexType, class IndexType>
+void GraphicsPipeline_Vulkan::bindData(const vector<VertexType>& vertices, const vector<IndexType>& indices,
+      VkCommandPool commandPool, VkQueue graphicsQueue) {
+   numVertices = vertices.size();
+   vertexCapacity = numVertices * 2;
+   createVertexBuffer(vertices.data(), sizeof(VertexType), commandPool, graphicsQueue);
+
+   numIndices = indices.size();
+   indexCapacity = numIndices * 2;
+   createIndexBuffer(indices.data(), sizeof(IndexType), commandPool, graphicsQueue);
+}
+
 #endif // _GRAPHICS_PIPELINE_VULKAN_H
Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
+++ vulkan-game.cpp	(revision 87c8f1abdf1a94f87d0f0051fbc134d1ec1fa9ee)
@@ -21,4 +21,7 @@
    gui = nullptr;
    window = nullptr;
+
+   currentFrame = 0;
+   framebufferResized = false;
 }
 
@@ -138,6 +141,24 @@
    createUniformBuffers();
 
-   graphicsPipelines.push_back(GraphicsPipeline_Vulkan(device, renderPass,
+   vector<Vertex> sceneVertices = {
+      {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}},
+      {{ 0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}},
+      {{ 0.5f,  0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
+      {{-0.5f,  0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
+
+      {{-0.5f, -0.5f,  0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}},
+      {{ 0.5f, -0.5f,  0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}},
+      {{ 0.5f,  0.5f,  0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
+      {{-0.5f,  0.5f,  0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}}
+   };
+   vector<uint16_t> sceneIndices = {
+      0, 1, 2, 2, 3, 0,
+      4, 5, 6, 6, 7, 4
+   };
+
+   graphicsPipelines.push_back(GraphicsPipeline_Vulkan(physicalDevice, device, renderPass,
       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, sizeof(Vertex)));
+
+   graphicsPipelines.back().bindData(sceneVertices, sceneIndices, commandPool, graphicsQueue);
 
    graphicsPipelines.back().addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&Vertex::pos));
@@ -155,6 +176,18 @@
    graphicsPipelines.back().createDescriptorSets(swapChainImages);
 
-   graphicsPipelines.push_back(GraphicsPipeline_Vulkan(device, renderPass,
+   vector<OverlayVertex> overlayVertices = {
+      {{-1.0f,  1.0f,  0.0f}, {0.0f, 1.0f}},
+      {{ 1.0f,  1.0f,  0.0f}, {1.0f, 1.0f}},
+      {{ 1.0f, -1.0f,  0.0f}, {1.0f, 0.0f}},
+      {{-1.0f, -1.0f,  0.0f}, {0.0f, 0.0f}}
+   };
+   vector<uint16_t> overlayIndices = {
+      0, 1, 2, 2, 3, 0
+   };
+
+   graphicsPipelines.push_back(GraphicsPipeline_Vulkan(physicalDevice, device, renderPass,
       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, sizeof(OverlayVertex)));
+
+   graphicsPipelines.back().bindData(overlayVertices, overlayIndices, commandPool, graphicsQueue);
 
    graphicsPipelines.back().addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&OverlayVertex::pos));
@@ -238,4 +271,10 @@
 
 void VulkanGame::renderScene() {
+   vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, numeric_limits<uint64_t>::max());
+
+   uint32_t imageIndex;
+
+   currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
+   currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
 }
 
Index: vulkan-game.hpp
===================================================================
--- vulkan-game.hpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
+++ vulkan-game.hpp	(revision 87c8f1abdf1a94f87d0f0051fbc134d1ec1fa9ee)
@@ -91,5 +91,7 @@
       vector<VkFence> inFlightFences;
 
-      bool framebufferResized = false;
+      size_t currentFrame;
+
+      bool framebufferResized;
 
       bool initWindow(int width, int height, unsigned char guiFlags);
Index: vulkan-ref.cpp
===================================================================
--- vulkan-ref.cpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
+++ vulkan-ref.cpp	(revision 87c8f1abdf1a94f87d0f0051fbc134d1ec1fa9ee)
@@ -72,5 +72,4 @@
    glm::vec2 texCoord;
 };
-/*** END OF REFACTORED CODE ***/
 
 struct UniformBufferObject {
@@ -80,5 +79,4 @@
 };
 
-/*** START OF REFACTORED CODE ***/
 struct DescriptorInfo {
    VkDescriptorType type;
@@ -88,8 +86,6 @@
    VkDescriptorImageInfo* imageData;
 };
-/*** END OF REFACTORED CODE ***/
 
 struct GraphicsPipelineInfo {
-/*** START OF REFACTORED CODE ***/
    VkPipelineLayout pipelineLayout;
    VkPipeline pipeline;
@@ -103,7 +99,6 @@
    VkDescriptorSetLayout descriptorSetLayout;
    vector<VkDescriptorSet> descriptorSets;
-/*** END OF REFACTORED CODE ***/
-
-   size_t numVertices; // Currently unused
+
+   size_t numVertices;
    size_t vertexCapacity;
    VkBuffer vertexBuffer;
@@ -116,5 +111,4 @@
 };
 
-/*** START OF REFACTORED CODE ***/
 VkResult CreateDebugUtilsMessengerEXT(VkInstance instance,
       const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
@@ -223,7 +217,7 @@
       vector<VkSemaphore> renderFinishedSemaphores;
       vector<VkFence> inFlightFences;
+
+      size_t currentFrame = 0;
 /*** END OF REFACTORED CODE ***/
-
-      size_t currentFrame = 0;
 
       size_t numPlanes = 0; // temp
@@ -340,5 +334,4 @@
          overlayImageInfo.imageView = sdlOverlayImageView;
          overlayImageInfo.sampler = textureSampler;
-/*** END OF REFACTORED CODE ***/
 
          // SHADER-SPECIFIC STUFF STARTS HERE
@@ -364,5 +357,4 @@
             sceneIndices.data(), sizeof(uint16_t), sceneIndices.size());
 
-/*** START OF REFACTORED CODE ***/
          addAttributeDescription(scenePipeline, VK_FORMAT_R32G32B32_SFLOAT, offset_of(&Vertex::pos));
          addAttributeDescription(scenePipeline, VK_FORMAT_R32G32B32_SFLOAT, offset_of(&Vertex::color));
@@ -373,5 +365,4 @@
 
          createDescriptorSetLayout(scenePipeline);
-/*** END OF REFACTORED CODE ***/
 
          numPlanes = 2;
@@ -391,5 +382,4 @@
             overlayIndices.data(), sizeof(uint16_t), overlayIndices.size());
 
-/*** START OF REFACTORED CODE ***/
          addAttributeDescription(overlayPipeline, VK_FORMAT_R32G32B32_SFLOAT, offset_of(&OverlayVertex::pos));
          addAttributeDescription(overlayPipeline, VK_FORMAT_R32G32_SFLOAT, offset_of(&OverlayVertex::texCoord));
@@ -812,5 +802,4 @@
          info.bindingDescription.stride = vertexSize;
          info.bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
-/*** END OF REFACTORED CODE ***/
 
          info.numVertices = numVertices;
@@ -1393,5 +1382,4 @@
          }
       }
-/*** END OF REFACTORED CODE ***/
 
       void createVertexBuffer(GraphicsPipelineInfo& info, const void* vertexData, int vertexSize) {
@@ -1443,5 +1431,4 @@
       }
 
-/*** START OF REFACTORED CODE ***/
       void createUniformBuffers() {
          VkDeviceSize bufferSize = sizeof(UniformBufferObject);
@@ -1507,4 +1494,5 @@
       }
 
+/*** START OF REFACTORED CODE ***/
       void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset,
             VkDeviceSize size) {
@@ -1550,5 +1538,4 @@
       }
 
-/*** START OF REFACTORED CODE ***/
       uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
          VkPhysicalDeviceMemoryProperties memProperties;
@@ -1801,8 +1788,8 @@
 
       void drawFrame() {
+         vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, numeric_limits<uint64_t>::max());
+
+         uint32_t imageIndex;
 /*** END OF REFACTORED CODE ***/
-         vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, numeric_limits<uint64_t>::max());
-
-         uint32_t imageIndex;
 
          VkResult result = vkAcquireNextImageKHR(device, swapChain, numeric_limits<uint64_t>::max(),
@@ -1861,7 +1848,7 @@
          }
 
+/*** START OF REFACTORED CODE ***/
          currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
          currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
-/*** START OF REFACTORED CODE ***/
       }
 
@@ -2052,5 +2039,4 @@
       void cleanupPipelineBuffers(GraphicsPipelineInfo& pipeline) {
          vkDestroyDescriptorSetLayout(device, pipeline.descriptorSetLayout, nullptr);
-/*** END OF REFACTORED CODE ***/
 
          vkDestroyBuffer(device, pipeline.vertexBuffer, nullptr);
@@ -2059,4 +2045,5 @@
          vkFreeMemory(device, pipeline.indexBufferMemory, nullptr);
       }
+/*** END OF REFACTORED CODE ***/
 
       static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
Index: vulkan-utils.cpp
===================================================================
--- vulkan-utils.cpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
+++ vulkan-utils.cpp	(revision 87c8f1abdf1a94f87d0f0051fbc134d1ec1fa9ee)
@@ -482,4 +482,15 @@
 }
 
+void VulkanUtils::copyBuffer(VkDevice device, VkCommandPool commandPool, VkBuffer srcBuffer,
+      VkBuffer dstBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size,
+      VkQueue graphicsQueue) {
+   VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
+
+   VkBufferCopy copyRegion = { srcOffset, dstOffset, size };
+   vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
+
+   endSingleTimeCommands(device, commandPool, commandBuffer, graphicsQueue);
+}
+
 bool VulkanUtils::hasStencilComponent(VkFormat format) {
    return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
Index: vulkan-utils.hpp
===================================================================
--- vulkan-utils.hpp	(revision 34bdf3ab3957de6744017a27609ea5f1be36d7ae)
+++ vulkan-utils.hpp	(revision 87c8f1abdf1a94f87d0f0051fbc134d1ec1fa9ee)
@@ -84,4 +84,7 @@
             uint32_t width, uint32_t height, VkQueue graphicsQueue);
 
+      static void copyBuffer(VkDevice device, VkCommandPool commandPool, VkBuffer srcBuffer, VkBuffer dstBuffer,
+            VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size, VkQueue graphicsQueue);
+
       static bool hasStencilComponent(VkFormat format);
 
