diff --git a/Vulkan/Vulkan.vcxproj b/Vulkan/Vulkan.vcxproj
index eb0166f..6d5e667 100644
--- a/Vulkan/Vulkan.vcxproj
+++ b/Vulkan/Vulkan.vcxproj
@@ -168,11 +168,13 @@
+
+
-
+
diff --git a/Vulkan/Vulkan.vcxproj.filters b/Vulkan/Vulkan.vcxproj.filters
index e63f622..eeb7862 100644
--- a/Vulkan/Vulkan.vcxproj.filters
+++ b/Vulkan/Vulkan.vcxproj.filters
@@ -74,7 +74,13 @@
Header Files
-
+
+ Header Files
+
+
+ Header Files
+
+
Header Files
diff --git a/Vulkan/compile.bat b/Vulkan/compile.bat
new file mode 100644
index 0000000..0741ede
--- /dev/null
+++ b/Vulkan/compile.bat
@@ -0,0 +1,3 @@
+glslc res/shaders/shader.vert -o res/shaders/vert.spv
+glslc res/shaders/shader.frag -o res/shaders/frag.spv
+pause
\ No newline at end of file
diff --git a/Vulkan/res/shaders/frag.spv b/Vulkan/res/shaders/frag.spv
index da37f7e..841eb58 100644
Binary files a/Vulkan/res/shaders/frag.spv and b/Vulkan/res/shaders/frag.spv differ
diff --git a/Vulkan/res/shaders/shader.frag b/Vulkan/res/shaders/shader.frag
index 7122ce8..500463e 100644
--- a/Vulkan/res/shaders/shader.frag
+++ b/Vulkan/res/shaders/shader.frag
@@ -1,8 +1,12 @@
#version 450
+layout(set = 1, binding = 0) uniform sampler2D texSampler;
+
layout(location = 0) in vec3 fragColor;
+layout(location = 1) in vec2 fragTexCoord;
+
layout(location = 0) out vec4 outColor;
void main() {
- outColor = vec4(fragColor, 1.0);
+ outColor = vec4(fragColor, 1.0) * texture(texSampler, fragTexCoord);
}
diff --git a/Vulkan/res/shaders/shader.vert b/Vulkan/res/shaders/shader.vert
index 00a3fb8..a537cc4 100644
--- a/Vulkan/res/shaders/shader.vert
+++ b/Vulkan/res/shaders/shader.vert
@@ -10,10 +10,13 @@ layout(set = 0, binding = 0) uniform SceneUniformBufferObject
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;
+layout(location = 2) in vec2 inTexCoord;
layout(location = 0) out vec3 fragColor;
+layout(location = 1) out vec2 fragTexCoord;
void main() {
gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition.x, 0.0, inPosition.y, 1.0);
fragColor = inColor;
+ fragTexCoord = inTexCoord;
}
\ No newline at end of file
diff --git a/Vulkan/res/shaders/vert.spv b/Vulkan/res/shaders/vert.spv
index f7d1531..5fadf46 100644
Binary files a/Vulkan/res/shaders/vert.spv and b/Vulkan/res/shaders/vert.spv differ
diff --git a/Vulkan/res/textures/texture.png b/Vulkan/res/textures/texture.png
new file mode 100644
index 0000000..8d45e99
Binary files /dev/null and b/Vulkan/res/textures/texture.png differ
diff --git a/Vulkan/src/Buffer.h b/Vulkan/src/Buffer.h
index a39c304..9298bb8 100644
--- a/Vulkan/src/Buffer.h
+++ b/Vulkan/src/Buffer.h
@@ -36,7 +36,7 @@ public:
VkMemoryAllocateInfo allocateInfo{};
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.allocationSize = memoryRequirements.size;
- allocateInfo.memoryTypeIndex = FindMemoryType(instance, memoryRequirements.memoryTypeBits, properties);
+ allocateInfo.memoryTypeIndex = instance.FindMemoryType(memoryRequirements.memoryTypeBits, properties);
CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, &memory), "Failed to allocate buffer memory");
@@ -85,10 +85,11 @@ public:
CopyBuffer(instance, stagingBuffer, *this, offset, size);
}
- void Map()
+ void* Map()
{
CP_ASSERT(mappedData == nullptr, "Mapping an already mapped buffer");
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
+ return mappedData;
}
void Unmap()
@@ -166,17 +167,4 @@ public:
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), 1, &commandBuffer);
}
-
-private:
- static uint32_t FindMemoryType(Instance& instance, uint32_t typeFilter, VkMemoryPropertyFlags properties)
- {
- VkPhysicalDeviceMemoryProperties memoryProperties;
- vkGetPhysicalDeviceMemoryProperties(instance.GetPhysicalDevice(), &memoryProperties);
- for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i)
- {
- if ((typeFilter & (1 << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
- return i;
- }
- throw std::runtime_error("Failed to find suitable memory type");
- }
};
diff --git a/Vulkan/src/DescriptorPool.h b/Vulkan/src/DescriptorPool.h
new file mode 100644
index 0000000..0d7438f
--- /dev/null
+++ b/Vulkan/src/DescriptorPool.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "Common.h"
+#include "Instance.h"
+#include
+
+class DescriptorPool final
+{
+ CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorPool);
+private:
+ Instance& instance;
+
+ VkDescriptorPool descriptorPool;
+ static const int DESCRIPTOR_SET_COUNT = 100;
+public:
+ DescriptorPool(Instance& instance)
+ : instance{instance}
+ {
+ std::vector poolSizes{2};
+ poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ poolSizes[0].descriptorCount = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight(); // TODO: how should this actually be determined?
+
+ poolSizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLER;
+ poolSizes[1].descriptorCount = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight(); // TODO: how should this actually be determined?
+
+ VkDescriptorPoolCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ createInfo.poolSizeCount = poolSizes.size();
+ createInfo.pPoolSizes = poolSizes.data();
+ createInfo.maxSets = DESCRIPTOR_SET_COUNT * instance.GetMaxFramesInFlight();
+
+ CP_VK_ASSERT(vkCreateDescriptorPool(instance.GetDevice(), &createInfo, nullptr, &descriptorPool), "Failed to initialize descriptor pool");
+ }
+
+ ~DescriptorPool()
+ {
+ vkDestroyDescriptorPool(instance.GetDevice(), descriptorPool, nullptr);
+ }
+
+ std::vector AllocateDescriptorSets(VkDescriptorSetLayout descriptorSetLayout)
+ {
+ std::vector descriptorSets;
+ std::vector layouts{static_cast(instance.GetMaxFramesInFlight()), descriptorSetLayout};
+ VkDescriptorSetAllocateInfo allocateInfo{};
+ allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ allocateInfo.descriptorPool = descriptorPool;
+ allocateInfo.descriptorSetCount = instance.GetMaxFramesInFlight();
+ allocateInfo.pSetLayouts = layouts.data();
+
+ descriptorSets.resize(instance.GetMaxFramesInFlight());
+ CP_VK_ASSERT(vkAllocateDescriptorSets(instance.GetDevice(), &allocateInfo, descriptorSets.data()), "Failed to allocate descriptor sets");
+
+ return descriptorSets;
+ }
+};
diff --git a/Vulkan/src/DescriptorSet.h b/Vulkan/src/DescriptorSet.h
new file mode 100644
index 0000000..5c23fe5
--- /dev/null
+++ b/Vulkan/src/DescriptorSet.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include "Common.h"
+#include "DescriptorPool.h"
+#include "Sampler.h"
+#include "UniformBuffer.h"
+#include
+
+class DescriptorSet
+{
+ CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorSet);
+private:
+ Instance& instance;
+ DescriptorPool& descriptorPool;
+ VkDescriptorSetLayout descriptorSetLayout;
+
+ std::vector descriptorSets;
+
+public:
+ DescriptorSet(Instance& instance, DescriptorPool& descriptorPool, VkDescriptorSetLayout descriptorSetLayout)
+ : instance{instance}, descriptorPool{descriptorPool}, descriptorSetLayout{descriptorSetLayout}
+ {
+ descriptorSets = descriptorPool.AllocateDescriptorSets(descriptorSetLayout);
+ }
+
+ void AddUniform(const UniformBuffer& uniformBuffer, uint32_t binding)
+ {
+ for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
+ VkDescriptorBufferInfo bufferInfo = uniformBuffer.GetDescriptorBufferInfo(i);
+
+ VkWriteDescriptorSet descriptorWrite{};
+ descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrite.dstSet = descriptorSets[i];
+ descriptorWrite.dstBinding = binding;
+ descriptorWrite.dstArrayElement = 0;
+ descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptorWrite.descriptorCount = 1;
+ descriptorWrite.pBufferInfo = &bufferInfo;
+ descriptorWrite.pImageInfo = nullptr;
+ descriptorWrite.pTexelBufferView = nullptr;
+ vkUpdateDescriptorSets(instance.GetDevice(), 1, &descriptorWrite, 0, nullptr);
+ }
+ }
+
+ void AddSampler(const Sampler& sampler, uint32_t binding)
+ {
+ VkDescriptorImageInfo imageInfo = sampler.GetDescriptorImageInfo();
+ for (auto&& descriptorSet : descriptorSets) {
+ VkWriteDescriptorSet descriptorWrite{};
+ descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrite.dstSet = descriptorSet;
+ descriptorWrite.dstBinding = binding;
+ descriptorWrite.dstArrayElement = 0;
+ descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ descriptorWrite.descriptorCount = 1;
+ descriptorWrite.pBufferInfo = nullptr;
+ descriptorWrite.pImageInfo = &imageInfo;
+ descriptorWrite.pTexelBufferView = nullptr;
+ vkUpdateDescriptorSets(instance.GetDevice(), 1, &descriptorWrite, 0, nullptr);
+ }
+ }
+
+ VkDescriptorSet GetHandle() const
+ {
+ return descriptorSets[instance.GetFlightIndex()];
+ }
+};
\ No newline at end of file
diff --git a/Vulkan/src/Instance.h b/Vulkan/src/Instance.h
index b2847c0..855e58a 100644
--- a/Vulkan/src/Instance.h
+++ b/Vulkan/src/Instance.h
@@ -157,6 +157,19 @@ public:
return *swapChain;
}
+ // TODO: Create Device class and move this there
+ uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
+ {
+ VkPhysicalDeviceMemoryProperties memoryProperties;
+ vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
+ for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i)
+ {
+ if ((typeFilter & (1 << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
+ return i;
+ }
+ throw std::runtime_error("Failed to find suitable memory type");
+ }
+
private:
void InitializeWindow(const std::string& applicationName)
{
@@ -277,6 +290,7 @@ private:
std::vector deviceExtensions = GetRequiredDeviceExtensions();
VkPhysicalDeviceFeatures deviceFeatures{};
deviceFeatures.fillModeNonSolid = VK_TRUE;
+ deviceFeatures.samplerAnisotropy = VK_TRUE;
VkDeviceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = queueCreateInfos.data();
@@ -380,7 +394,7 @@ private:
VkPhysicalDeviceFeatures deviceFeatures;
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
- if (!deviceFeatures.fillModeNonSolid)
+ if (!deviceFeatures.fillModeNonSolid || !deviceFeatures.samplerAnisotropy)
return false;
QueueFamiliesQuery query{surface, device};
diff --git a/Vulkan/src/Pipeline.h b/Vulkan/src/Pipeline.h
index a68228f..f6d9238 100644
--- a/Vulkan/src/Pipeline.h
+++ b/Vulkan/src/Pipeline.h
@@ -15,8 +15,7 @@ class Pipeline
private:
Instance& instance;
- VkDescriptorSetLayout vertexDescriptorSetLayout;
- VkDescriptorSetLayout fragmentDescriptorSetLayout;
+ std::vector descriptorSetLayouts{};
VkPipelineLayout pipelineLayout;
VkPipeline graphicsPipeline;
@@ -24,7 +23,7 @@ public:
Pipeline(Instance& instance, PipelineCreator creator)
: instance{instance}
{
- InitializeDescriptorSetLayouts(creator);
+ InitializeDescriptorSetLayout(creator);
InitializePipeline(creator);
}
@@ -32,8 +31,10 @@ public:
{
vkDestroyPipeline(instance.GetDevice(), graphicsPipeline, nullptr);
vkDestroyPipelineLayout(instance.GetDevice(), pipelineLayout, nullptr);
- vkDestroyDescriptorSetLayout(instance.GetDevice(), vertexDescriptorSetLayout, nullptr);
- vkDestroyDescriptorSetLayout(instance.GetDevice(), fragmentDescriptorSetLayout, nullptr);
+ for (auto&& descriptorSetLayout : descriptorSetLayouts)
+ {
+ vkDestroyDescriptorSetLayout(instance.GetDevice(), descriptorSetLayout, nullptr);
+ }
}
void Bind(VkCommandBuffer commandBuffer)
@@ -59,21 +60,32 @@ public:
return pipelineLayout;
}
- VkDescriptorSetLayout GetVertexDescriptorSetLayout()
+ VkDescriptorSetLayout GetDescriptorSetLayout(uint32_t setIndex) const
{
- return vertexDescriptorSetLayout;
- }
-
- VkDescriptorSetLayout GetFragmentDescriptorSetLayout()
- {
- return fragmentDescriptorSetLayout;
+ return descriptorSetLayouts[setIndex];
}
private:
- void InitializeDescriptorSetLayouts(const PipelineCreator& creator)
+ void InitializeDescriptorSetLayout(const PipelineCreator& creator)
{
- vertexDescriptorSetLayout = InitializeDescriptorSetLayouts(creator.vertexDescriptorSetLayouts, VK_SHADER_STAGE_VERTEX_BIT);
- fragmentDescriptorSetLayout = InitializeDescriptorSetLayouts(creator.fragmentDescriptorSetLayouts, VK_SHADER_STAGE_FRAGMENT_BIT);
+ descriptorSetLayouts.resize(creator.descriptorSetLayouts.size());
+ int i = 0;
+ for (auto&& binding : creator.descriptorSetLayouts)
+ {
+ VkDescriptorSetLayoutBinding layoutBinding{};
+ layoutBinding.binding = 0;
+ layoutBinding.descriptorType = binding.second.type;
+ layoutBinding.descriptorCount = 1;
+ layoutBinding.stageFlags = binding.second.flags;
+ layoutBinding.pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ createInfo.bindingCount = 1;
+ createInfo.pBindings = &layoutBinding;
+
+ CP_VK_ASSERT(vkCreateDescriptorSetLayout(instance.GetDevice(), &createInfo, nullptr, &descriptorSetLayouts[i++]), "Failed to initialize descriptor set layout");
+ }
}
void InitializePipeline(const PipelineCreator& creator)
@@ -185,13 +197,10 @@ private:
colorBlendCreateInfo.blendConstants[2] = 0.0f;
colorBlendCreateInfo.blendConstants[3] = 0.0f;
- std::vector layouts{};
- if (vertexDescriptorSetLayout != VK_NULL_HANDLE) layouts.emplace_back(vertexDescriptorSetLayout);
- if (fragmentDescriptorSetLayout != VK_NULL_HANDLE) layouts.emplace_back(fragmentDescriptorSetLayout );
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutCreateInfo.setLayoutCount = layouts.size();
- pipelineLayoutCreateInfo.pSetLayouts = layouts.data();
+ pipelineLayoutCreateInfo.setLayoutCount = descriptorSetLayouts.size();
+ pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts.data();
pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
pipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
@@ -234,37 +243,4 @@ private:
return shaderModule;
}
- VkDescriptorSetLayout InitializeDescriptorSetLayouts(const std::set& bindings, VkShaderStageFlags flags)
- {
- VkDescriptorSetLayout descriptorSetLayout;
- std::vector descriptorSetLayoutBindings{bindings.size()};
-
- int i = 0;
- for (auto&& binding : bindings)
- {
- VkDescriptorSetLayoutBinding layoutBinding{};
- layoutBinding.binding = binding;
- layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- layoutBinding.descriptorCount = 1;
- layoutBinding.stageFlags = flags;
- layoutBinding.pImmutableSamplers = nullptr;
- descriptorSetLayoutBindings[i++] = layoutBinding;
- }
-
- if (!descriptorSetLayoutBindings.empty())
- {
- VkDescriptorSetLayoutCreateInfo createInfo{};
- createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- createInfo.bindingCount = descriptorSetLayoutBindings.size();
- createInfo.pBindings = descriptorSetLayoutBindings.data();
-
- CP_VK_ASSERT(vkCreateDescriptorSetLayout(instance.GetDevice(), &createInfo, nullptr, &descriptorSetLayout), "Failed to initialize descriptor set layout");
-
- return descriptorSetLayout;
- }
- else
- {
- return VK_NULL_HANDLE;
- }
- }
};
\ No newline at end of file
diff --git a/Vulkan/src/PipelineCreator.h b/Vulkan/src/PipelineCreator.h
index 9acfd3f..63553c0 100644
--- a/Vulkan/src/PipelineCreator.h
+++ b/Vulkan/src/PipelineCreator.h
@@ -6,10 +6,14 @@
class PipelineCreator
{
+ struct DescriptorSetLayout
+ {
+ VkDescriptorType type;
+ VkShaderStageFlags flags;
+ };
friend class Pipeline;
private:
- std::set vertexDescriptorSetLayouts{};
- std::set fragmentDescriptorSetLayouts{};
+ std::map descriptorSetLayouts{};
std::string vertexShader;
std::string fragmentShader;
@@ -29,15 +33,9 @@ public:
vertexDescriptor = descriptor;
}
- void AddVertexDescriptorSetLayoutBinding(uint32_t binding)
+ void AddDescriptorSetLayoutBinding(uint32_t set, VkDescriptorType type, VkShaderStageFlags stageFlags)
{
- CP_ASSERT(binding == 0, "Currently only support uniforms with binding = 0");
- vertexDescriptorSetLayouts.emplace(binding);
- }
-
- void AddFragmentDescriptorSetLayoutBinding(uint32_t binding)
- {
- fragmentDescriptorSetLayouts.emplace(binding);
+ descriptorSetLayouts.emplace(set, DescriptorSetLayout{type, stageFlags});
}
void SetPrimitiveTopology(VkPrimitiveTopology primitiveTopology)
diff --git a/Vulkan/src/Sampler.h b/Vulkan/src/Sampler.h
new file mode 100644
index 0000000..58849ff
--- /dev/null
+++ b/Vulkan/src/Sampler.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "Common.h"
+#include "Instance.h"
+#include "Pipeline.h"
+
+class Sampler
+{
+ CP_DELETE_COPY_AND_MOVE_CTOR(Sampler);
+private:
+ Instance& instance;
+ VkImageView imageView;
+
+ VkSampler textureSampler;
+public:
+ Sampler(Instance& instance, VkImageView imageView)
+ : instance{instance}, imageView{imageView}
+ {
+ InitializeSampler(imageView);
+ }
+
+ ~Sampler()
+ {
+ vkDestroySampler(instance.GetDevice(), textureSampler, nullptr);
+ }
+
+ VkDescriptorImageInfo GetDescriptorImageInfo() const
+ {
+ VkDescriptorImageInfo imageInfo{};
+ imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ imageInfo.imageView = imageView;
+ imageInfo.sampler = textureSampler;
+
+ return imageInfo;
+ }
+private:
+ void InitializeSampler(VkImageView imageView)
+ {
+ VkPhysicalDeviceProperties properties{};
+ vkGetPhysicalDeviceProperties(instance.GetPhysicalDevice(), &properties);
+
+ VkSamplerCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ createInfo.magFilter = VK_FILTER_LINEAR;
+ createInfo.minFilter = VK_FILTER_LINEAR;
+ createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ createInfo.anisotropyEnable = VK_TRUE;
+ createInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
+ createInfo.unnormalizedCoordinates = VK_FALSE;
+ createInfo.compareEnable = VK_FALSE;
+ createInfo.compareOp = VK_COMPARE_OP_ALWAYS;
+ createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
+ createInfo.mipLodBias = 0.0f;
+ createInfo.minLod = 0.0f;
+ createInfo.maxLod = 0.0f;
+
+ CP_VK_ASSERT(vkCreateSampler(instance.GetDevice(), &createInfo, nullptr, &textureSampler), "Failed to initialize texture sampler");
+ }
+};
diff --git a/Vulkan/src/UniformBuffer.h b/Vulkan/src/UniformBuffer.h
index bd75947..3853b06 100644
--- a/Vulkan/src/UniformBuffer.h
+++ b/Vulkan/src/UniformBuffer.h
@@ -5,84 +5,28 @@
#include "Pipeline.h"
#include
-template
class UniformBuffer : public Buffer
{
CP_DELETE_COPY_AND_MOVE_CTOR(UniformBuffer);
-private:
- Pipeline& pipeline;
-
- VkDescriptorPool descriptorPool;
- std::vector descriptorSets;
public:
- UniformBuffer(Instance& instance, Pipeline& pipeline, uint32_t binding, VkDescriptorSetLayout layout)
- : Buffer{instance, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(T), instance.GetMaxFramesInFlight()}, pipeline{pipeline}
- {
- InitializeDescriptorPool();
- InitializeDescriptorSet(binding, layout);
- }
-
- ~UniformBuffer() override
- {
- vkDestroyDescriptorPool(instance.GetDevice(), descriptorPool, nullptr);
- }
+ UniformBuffer(Instance& instance, VkDeviceSize size)
+ : Buffer{instance, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, size, instance.GetMaxFramesInFlight()}
+ {}
+ template
void Update(const T& t)
{
+ CP_ASSERT(sizeof(T) == Buffer::GetSize(), "Template size is not the same as buffer size %u != %u", sizeof(T), Buffer::GetSize());
Buffer::Update((void*)&t, instance.GetFlightIndex());
}
void Bind(VkCommandBuffer commandBuffer) const
{
- vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.GetPipelineLayout(), 0, 1, &descriptorSets[instance.GetFlightIndex()], 0, nullptr);
+ // vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.GetPipelineLayout(), 0, 1, &descriptorSets[instance.GetFlightIndex()], 0, nullptr);
}
-private:
- void InitializeDescriptorPool()
- {
- VkDescriptorPoolSize poolSize{};
- poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- poolSize.descriptorCount = instance.GetMaxFramesInFlight();
-
- VkDescriptorPoolCreateInfo createInfo{};
- createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
- createInfo.poolSizeCount = 1;
- createInfo.pPoolSizes = &poolSize;
- createInfo.maxSets = instance.GetMaxFramesInFlight();
-
- CP_VK_ASSERT(vkCreateDescriptorPool(instance.GetDevice(), &createInfo, nullptr, &descriptorPool), "Failed to initialize descriptor pool");
- }
-
- void InitializeDescriptorSet(uint32_t binding, VkDescriptorSetLayout layout)
- {
- std::vector layouts{static_cast(instance.GetMaxFramesInFlight()), layout};
- VkDescriptorSetAllocateInfo allocateInfo{};
- allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- allocateInfo.descriptorPool = descriptorPool;
- allocateInfo.descriptorSetCount = instance.GetMaxFramesInFlight();
- allocateInfo.pSetLayouts = layouts.data();
-
- descriptorSets.resize(instance.GetMaxFramesInFlight());
- CP_VK_ASSERT(vkAllocateDescriptorSets(instance.GetDevice(), &allocateInfo, descriptorSets.data()), "Failed to allocate descriptor sets");
- for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
- VkDescriptorBufferInfo bufferInfo = GetDescriptorBufferInfo(i);
-
- VkWriteDescriptorSet descriptorWrite{};
- descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- descriptorWrite.dstSet = descriptorSets[i];
- descriptorWrite.dstBinding = binding;
- descriptorWrite.dstArrayElement = 0;
- descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptorWrite.descriptorCount = 1;
- descriptorWrite.pBufferInfo = &bufferInfo;
- descriptorWrite.pImageInfo = nullptr;
- descriptorWrite.pTexelBufferView = nullptr;
- vkUpdateDescriptorSets(instance.GetDevice(), 1, &descriptorWrite, 0, nullptr);
- }
- }
-
- VkDescriptorBufferInfo GetDescriptorBufferInfo(int index)
+ VkDescriptorBufferInfo GetDescriptorBufferInfo(int index) const
{
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = handle;
diff --git a/Vulkan/src/Vertex.h b/Vulkan/src/Vertex.h
index 852b609..9700f2f 100644
--- a/Vulkan/src/Vertex.h
+++ b/Vulkan/src/Vertex.h
@@ -7,41 +7,15 @@
struct Vertex {
glm::vec2 pos;
glm::vec3 color;
+ glm::vec2 texCoord;
static VertexDescriptor GetDescriptor()
{
VertexDescriptor descriptor{};
descriptor.AddAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, pos));
descriptor.AddAttribute(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color));
+ descriptor.AddAttribute(0, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, texCoord));
return descriptor;
}
-
- static VkVertexInputBindingDescription GetBindingDescription()
- {
- VkVertexInputBindingDescription description{};
-
- description.binding = 0;
- description.stride = sizeof(Vertex);
- description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
-
- return description;
- }
-
- static std::vector GetAttributeDescriptions()
- {
- std::vector descriptions{2};
-
- descriptions[0].binding = 0;
- descriptions[0].location = 0;
- descriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
- descriptions[0].offset = offsetof(Vertex, pos);
-
- descriptions[1].binding = 0;
- descriptions[1].location = 1;
- descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
- descriptions[1].offset = offsetof(Vertex, color);
-
- return descriptions;
- }
};
diff --git a/Vulkan/src/main.cpp b/Vulkan/src/main.cpp
index 7cb4061..0fd310c 100644
--- a/Vulkan/src/main.cpp
+++ b/Vulkan/src/main.cpp
@@ -5,8 +5,11 @@
#include "Instance.h"
#include "Timer.h"
#include "UniformBuffer.h"
+#include "Sampler.h"
#include "Vertex.h"
#include "Pipeline.h"
+#include "DescriptorPool.h"
+#include "DescriptorSet.h"
#include
#include
@@ -14,29 +17,16 @@
#include
#include
#include
+#define STB_IMAGE_IMPLEMENTATION
#include
#include
#include
const std::vector vertices = {
- Vertex{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
- Vertex{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
- Vertex{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
- Vertex{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}
-};
-
-const std::vector positions = {
- {-0.5f, -0.5f},
- {0.5f, -0.5f},
- {0.5f, 0.5f},
- {-0.5f, 0.5f}
-};
-
-const std::vector colors = {
- glm::vec3{1.0f, 0.0f, 0.0f},
- glm::vec3{0.0f, 1.0f, 0.0f},
- glm::vec3{0.0f, 0.0f, 1.0f},
- glm::vec3{1.0f, 1.0f, 1.0f}
+ Vertex{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
+ Vertex{{ 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
+ Vertex{{ 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
+ Vertex{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}
};
const std::vector indices = {
@@ -58,15 +48,27 @@ private:
std::unique_ptr graphicsPipeline;
std::unique_ptr vertexBuffer;
std::unique_ptr indexBuffer;
- std::unique_ptr> shaderUniformBuffer;
+ std::unique_ptr shaderUniformBuffer;
+ std::unique_ptr sampler;
+ std::unique_ptr descriptorPool;
+ std::unique_ptr uniformDescriptorSet;
+ std::unique_ptr samplerDescriptorSet;
std::vector commandBuffers;
+ VkImage textureImage;
+ VkDeviceMemory textureImageMemory;
+ VkImageView textureImageView;
+
public:
Application()
{
InitializeInstance();
InitializeGraphicsPipeline();
+ InitializeTextureImage();
+ InitializeTextureImageView();
+ InitializeTextureSampler();
InitializeUniformBuffer();
+ InitializeDescriptorSets();
InitializeVertexBuffer();
InitializeIndexBuffer();
InitializeCommandBuffers();
@@ -75,6 +77,9 @@ public:
~Application()
{
vkDeviceWaitIdle(instance->GetDevice());
+ vkDestroyImage(instance->GetDevice(), textureImage, nullptr);
+ vkFreeMemory(instance->GetDevice(), textureImageMemory, nullptr);
+ vkDestroyImageView(instance->GetDevice(), textureImageView, nullptr);
}
Application(Application&&) = delete;
@@ -100,15 +105,207 @@ private:
instance = std::make_unique("Vulkan Tutorial");
}
+ void InitializeTextureImage()
+ {
+ int texWidth;
+ int texHeight;
+ int texChannels;
+ stbi_uc* pixels = stbi_load("res/textures/texture.png", &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
+
+ CP_ASSERT(pixels, "Failed to load texture image");
+
+ VkDeviceSize bufferSize = texWidth * texHeight * 4;
+ Buffer stagingBuffer{*instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
+ void* data = stagingBuffer.Map();
+ memcpy(data, pixels, bufferSize);
+ stagingBuffer.Unmap();
+ stbi_image_free(pixels);
+
+ VkImageCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ createInfo.imageType = VK_IMAGE_TYPE_2D;
+ createInfo.extent.width = texWidth;
+ createInfo.extent.height = texHeight;
+ createInfo.extent.depth = 1;
+ createInfo.mipLevels = 1;
+ createInfo.arrayLayers = 1;
+ createInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
+ createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ createInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+ createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+ createInfo.flags = 0;
+
+ CP_VK_ASSERT(vkCreateImage(instance->GetDevice(), &createInfo, nullptr, &textureImage), "Failed to initialize texture image");
+
+ VkMemoryRequirements memoryRequirements;
+ vkGetImageMemoryRequirements(instance->GetDevice(), textureImage, &memoryRequirements);
+
+ VkMemoryAllocateInfo allocateInfo{};
+ allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ allocateInfo.allocationSize = memoryRequirements.size;
+ allocateInfo.memoryTypeIndex = instance->FindMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ CP_VK_ASSERT(vkAllocateMemory(instance->GetDevice(), &allocateInfo, nullptr, &textureImageMemory), "Failed to initiallizse texture image memory");
+
+ vkBindImageMemory(instance->GetDevice(), textureImage, textureImageMemory, 0);
+
+ TransitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+ CopyBufferToImage(stagingBuffer, textureImage, texWidth, texHeight);
+ TransitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ }
+
+ void InitializeTextureImageView()
+ {
+ textureImageView = CreateImageView();
+ }
+
+ void InitializeTextureSampler()
+ {
+ sampler = std::make_unique(*instance, textureImageView);
+ }
+
+ VkImageView CreateImageView()
+ {
+ VkImageView imageView;
+ VkImageViewCreateInfo createInfo{};
+ createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ createInfo.image = textureImage;
+ createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ createInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
+ createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ createInfo.subresourceRange.baseMipLevel = 0;
+ createInfo.subresourceRange.levelCount = 1;
+ createInfo.subresourceRange.baseArrayLayer = 0;
+ createInfo.subresourceRange.layerCount = 1;
+ CP_VK_ASSERT(vkCreateImageView(instance->GetDevice(), &createInfo, nullptr, &imageView), "Failed to initialize ImageView");
+
+ return imageView;
+ }
+
+ void TransitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout)
+ {
+ VkCommandBuffer commandBuffer = BeginSingleUseCommandBuffer();
+
+ VkImageMemoryBarrier barrier{};
+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ barrier.oldLayout = oldLayout;
+ barrier.newLayout = newLayout;
+ barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.image = image;
+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ barrier.subresourceRange.baseMipLevel = 0;
+ barrier.subresourceRange.levelCount = 1;
+ barrier.subresourceRange.baseArrayLayer = 0;
+ barrier.subresourceRange.layerCount = 1;
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = 0;
+
+ VkPipelineStageFlags srcStage;
+ VkPipelineStageFlags dstStage;
+
+ if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+
+ srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ } else {
+ throw std::invalid_argument("Unsupported layout transition");
+ }
+
+ vkCmdPipelineBarrier(commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
+
+ EndSinglelUseCommandBuffer(commandBuffer);
+ }
+
+ void CopyBufferToImage(const Buffer& buffer, VkImage image, uint32_t width, uint32_t height)
+ {
+
+ VkCommandBuffer commandBuffer = BeginSingleUseCommandBuffer();
+
+ VkBufferImageCopy region{};
+ region.bufferOffset = 0;
+ region.bufferRowLength = 0;
+ region.bufferImageHeight = 0;
+
+ region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ region.imageSubresource.mipLevel = 0;
+ region.imageSubresource.baseArrayLayer = 0;
+ region.imageSubresource.layerCount = 1;
+
+ region.imageOffset = {0, 0, 0};
+ region.imageExtent = {width, height, 1};
+
+ vkCmdCopyBufferToImage(commandBuffer, buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
+
+ EndSinglelUseCommandBuffer(commandBuffer);
+ }
+
+ VkCommandBuffer BeginSingleUseCommandBuffer()
+ {
+ VkCommandBufferAllocateInfo allocInfo{};
+ allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ allocInfo.commandPool = instance->GetCommandPool();
+ allocInfo.commandBufferCount = 1;
+
+ VkCommandBuffer commandBuffer;
+ vkAllocateCommandBuffers(instance->GetDevice(), &allocInfo, &commandBuffer);
+
+ VkCommandBufferBeginInfo beginInfo{};
+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+
+ vkBeginCommandBuffer(commandBuffer, &beginInfo);
+ return commandBuffer;
+ }
+
+ void EndSinglelUseCommandBuffer(VkCommandBuffer commandBuffer)
+ {
+ vkEndCommandBuffer(commandBuffer);
+
+ VkSubmitInfo submitInfo{};
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &commandBuffer;
+
+ vkQueueSubmit(instance->GetGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
+ vkQueueWaitIdle(instance->GetGraphicsQueue());
+
+ vkFreeCommandBuffers(instance->GetDevice(), instance->GetCommandPool(), 1, &commandBuffer);
+
+ }
+
void InitializeUniformBuffer()
{
- shaderUniformBuffer = std::make_unique>(*instance, *graphicsPipeline, 0, graphicsPipeline->GetVertexDescriptorSetLayout());
+ shaderUniformBuffer = std::make_unique(*instance, sizeof(ShaderUniform));
+ }
+
+ void InitializeDescriptorSets()
+ {
+ descriptorPool = std::make_unique(*instance);
+
+ uniformDescriptorSet = std::make_unique(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
+ uniformDescriptorSet->AddUniform(*shaderUniformBuffer, 0);
+
+ samplerDescriptorSet = std::make_unique(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(1));
+ samplerDescriptorSet->AddSampler(*sampler, 0);
}
void InitializeGraphicsPipeline()
{
PipelineCreator creator{"res/shaders/vert.spv", "res/shaders/frag.spv"};
- creator.AddVertexDescriptorSetLayoutBinding(0);
+ creator.AddDescriptorSetLayoutBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT);
+ creator.AddDescriptorSetLayoutBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
creator.SetVertexDescriptor(Vertex::GetDescriptor());
creator.SetCullMode(VK_CULL_MODE_NONE);
graphicsPipeline = std::make_unique(*instance, creator);
@@ -171,6 +368,11 @@ private:
indexBuffer->Bind(commandBuffer);
shaderUniformBuffer->Bind(commandBuffer);
+ std::vector sets{uniformDescriptorSet->GetHandle(), samplerDescriptorSet->GetHandle()};
+ vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->GetPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
+ // Replace the two lines above with this somehow:
+ // graphicsPipeline->BindDescriptorSets(uniformDescriptorSet, samplerDescriptorSet);
+
indexBuffer->Draw(commandBuffer);
vkCmdEndRenderPass(commandBuffer);