Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision de32fdaea94305c3a14e4d64c54d31f4571bd34f)
+++ vulkan-game.cpp	(revision c7fb8836bdb0128dbe9dff186dd0f4e8141fbb1a)
@@ -171,4 +171,6 @@
       VkPipeline graphicsPipeline;
       VkCommandPool commandPool;
+      VkDescriptorPool descriptorPool;
+      vector<VkDescriptorSet> descriptorSets;
 
       VkBuffer vertexBuffer;
@@ -224,4 +226,6 @@
          createIndexBuffer();
          createUniformBuffers();
+         createDescriptorPool();
+         createDescriptorSets();
          createCommandBuffers();
          createSyncObjects();
@@ -248,4 +252,6 @@
          createFramebuffers();
          createUniformBuffers();
+         createDescriptorPool();
+         createDescriptorSets();
          createCommandBuffers();
       }
@@ -272,4 +278,6 @@
             vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
          }
+
+         vkDestroyDescriptorPool(device, descriptorPool, nullptr);
       }
 
@@ -802,5 +810,5 @@
          rasterizer.lineWidth = 1.0f;
          rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
-         rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
+         rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
          rasterizer.depthBiasEnable = false;
 
@@ -957,17 +965,4 @@
       }
 
-      void createUniformBuffers() {
-         VkDeviceSize bufferSize = sizeof(UniformBufferObject);
-
-         uniformBuffers.resize(swapChainImages.size());
-         uniformBuffersMemory.resize(swapChainImages.size());
-
-         for (size_t i = 0; i < swapChainImages.size(); i++) {
-            createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
-               VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
-               uniformBuffers[i], uniformBuffersMemory[i]);
-         }
-      }
-
       void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties,
             VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
@@ -1046,4 +1041,67 @@
       }
 
+      void createUniformBuffers() {
+         VkDeviceSize bufferSize = sizeof(UniformBufferObject);
+
+         uniformBuffers.resize(swapChainImages.size());
+         uniformBuffersMemory.resize(swapChainImages.size());
+
+         for (size_t i = 0; i < swapChainImages.size(); i++) {
+            createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+               VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+               uniformBuffers[i], uniformBuffersMemory[i]);
+         }
+      }
+
+      void createDescriptorPool() {
+         VkDescriptorPoolSize poolSize = {};
+         poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+         poolSize.descriptorCount = static_cast<uint32_t>(swapChainImages.size());
+
+         VkDescriptorPoolCreateInfo poolInfo = {};
+         poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+         poolInfo.poolSizeCount = 1;
+         poolInfo.pPoolSizes = &poolSize;
+         poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());
+
+         if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
+            throw runtime_error("failed to create descriptor pool!");
+         }
+      }
+
+      void createDescriptorSets() {
+         vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), descriptorSetLayout);
+         VkDescriptorSetAllocateInfo allocInfo = {};
+         allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+         allocInfo.descriptorPool = descriptorPool;
+         allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size());
+         allocInfo.pSetLayouts = layouts.data();
+
+         descriptorSets.resize(swapChainImages.size());
+         if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
+            throw runtime_error("failed to allocate descriptor sets!");
+         }
+
+         for (size_t i = 0; i < swapChainImages.size(); i++) {
+            VkDescriptorBufferInfo bufferInfo = {};
+            bufferInfo.buffer = uniformBuffers[i];
+            bufferInfo.offset = 0;
+            bufferInfo.range = sizeof(UniformBufferObject);
+
+            VkWriteDescriptorSet descriptorWrite = {};
+            descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+            descriptorWrite.dstSet = descriptorSets[i];
+            descriptorWrite.dstBinding = 0;
+            descriptorWrite.dstArrayElement = 0;
+            descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+            descriptorWrite.descriptorCount = 1;
+            descriptorWrite.pBufferInfo = &bufferInfo;
+            descriptorWrite.pImageInfo = nullptr;
+            descriptorWrite.pTexelBufferView = nullptr;
+
+            vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
+         }
+      }
+
       void createCommandBuffers() {
          commandBuffers.resize(swapChainFramebuffers.size());
@@ -1088,4 +1146,5 @@
 
             vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT16);
+            vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);
 
             vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
