Add Sampler

- Add DescriptorSet and DescriptorPool abstractions to support Samplers
This commit is contained in:
Thraix
2023-01-19 23:15:11 +01:00
parent 8c8590d10a
commit 87ed5739b3
18 changed files with 491 additions and 194 deletions
+3 -1
View File
@@ -168,11 +168,13 @@
<ClInclude Include="src\Buffer.h" />
<ClInclude Include="src\Common.h" />
<ClInclude Include="src\DebugMessenger.h" />
<ClInclude Include="src\DescriptorSet.h" />
<ClInclude Include="src\DescriptorPool.h" />
<ClInclude Include="src\FileSystem.h" />
<ClInclude Include="src\Framebuffer.h" />
<ClInclude Include="src\IndexBuffer.h" />
<ClInclude Include="src\Pipeline.h" />
<ClInclude Include="src\PipelineCreator.h" />
<ClInclude Include="src\Sampler.h" />
<ClInclude Include="src\UniformBuffer.h" />
<ClInclude Include="src\Instance.h" />
<ClInclude Include="src\QueueFamilies.h" />
+7 -1
View File
@@ -74,7 +74,13 @@
<ClInclude Include="src\VertexDescriptor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Framebuffer.h">
<ClInclude Include="src\Sampler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\DescriptorSet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\DescriptorPool.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
+3
View File
@@ -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
Binary file not shown.
+5 -1
View File
@@ -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);
}
+3
View File
@@ -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;
}
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

+3 -15
View File
@@ -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");
}
};
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include "Common.h"
#include "Instance.h"
#include <vulkan/vulkan.hpp>
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<VkDescriptorPoolSize> 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<VkDescriptorSet> AllocateDescriptorSets(VkDescriptorSetLayout descriptorSetLayout)
{
std::vector<VkDescriptorSet> descriptorSets;
std::vector<VkDescriptorSetLayout> layouts{static_cast<size_t>(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;
}
};
+67
View File
@@ -0,0 +1,67 @@
#pragma once
#include "Common.h"
#include "DescriptorPool.h"
#include "Sampler.h"
#include "UniformBuffer.h"
#include <vulkan/vulkan.hpp>
class DescriptorSet
{
CP_DELETE_COPY_AND_MOVE_CTOR(DescriptorSet);
private:
Instance& instance;
DescriptorPool& descriptorPool;
VkDescriptorSetLayout descriptorSetLayout;
std::vector<VkDescriptorSet> 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()];
}
};
+15 -1
View File
@@ -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<const char*> 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};
+29 -53
View File
@@ -15,8 +15,7 @@ class Pipeline
private:
Instance& instance;
VkDescriptorSetLayout vertexDescriptorSetLayout;
VkDescriptorSetLayout fragmentDescriptorSetLayout;
std::vector<VkDescriptorSetLayout> 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<VkDescriptorSetLayout> 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<uint32_t>& bindings, VkShaderStageFlags flags)
{
VkDescriptorSetLayout descriptorSetLayout;
std::vector<VkDescriptorSetLayoutBinding> 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;
}
}
};
+8 -10
View File
@@ -6,10 +6,14 @@
class PipelineCreator
{
struct DescriptorSetLayout
{
VkDescriptorType type;
VkShaderStageFlags flags;
};
friend class Pipeline;
private:
std::set<uint32_t> vertexDescriptorSetLayouts{};
std::set<uint32_t> fragmentDescriptorSetLayouts{};
std::map<uint32_t, DescriptorSetLayout> 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)
+61
View File
@@ -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");
}
};
+7 -63
View File
@@ -5,84 +5,28 @@
#include "Pipeline.h"
#include <vulkan/vulkan.hpp>
template <typename T>
class UniformBuffer : public Buffer
{
CP_DELETE_COPY_AND_MOVE_CTOR(UniformBuffer);
private:
Pipeline& pipeline;
VkDescriptorPool descriptorPool;
std::vector<VkDescriptorSet> 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 <typename T>
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<VkDescriptorSetLayout> layouts{static_cast<size_t>(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;
+2 -28
View File
@@ -7,41 +7,15 @@
struct Vertex {
glm::vec2 pos;
glm::vec3 color;
glm::vec2 texCoord;
static VertexDescriptor GetDescriptor()
{
VertexDescriptor descriptor{};
descriptor.AddAttribute<Vertex>(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, pos));
descriptor.AddAttribute<Vertex>(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color));
descriptor.AddAttribute<Vertex>(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<VkVertexInputAttributeDescription> GetAttributeDescriptions()
{
std::vector<VkVertexInputAttributeDescription> 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;
}
};
+223 -21
View File
@@ -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 <GLFW/glfw3.h>
#include <iostream>
@@ -14,29 +17,16 @@
#include <optional>
#include <set>
#include <glm/glm.hpp>
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
#include <glm/gtc/matrix_transform.hpp>
#include <chrono>
const std::vector<Vertex> 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<glm::vec2> positions = {
{-0.5f, -0.5f},
{0.5f, -0.5f},
{0.5f, 0.5f},
{-0.5f, 0.5f}
};
const std::vector<glm::vec3> 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<uint16_t> indices = {
@@ -58,15 +48,27 @@ private:
std::unique_ptr<Pipeline> graphicsPipeline;
std::unique_ptr<VertexBuffer> vertexBuffer;
std::unique_ptr<IndexBuffer> indexBuffer;
std::unique_ptr<UniformBuffer<ShaderUniform>> shaderUniformBuffer;
std::unique_ptr<UniformBuffer> shaderUniformBuffer;
std::unique_ptr<Sampler> sampler;
std::unique_ptr<DescriptorPool> descriptorPool;
std::unique_ptr<DescriptorSet> uniformDescriptorSet;
std::unique_ptr<DescriptorSet> samplerDescriptorSet;
std::vector<VkCommandBuffer> 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<Instance>("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<Sampler>(*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, &region);
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<UniformBuffer<ShaderUniform>>(*instance, *graphicsPipeline, 0, graphicsPipeline->GetVertexDescriptorSetLayout());
shaderUniformBuffer = std::make_unique<UniformBuffer>(*instance, sizeof(ShaderUniform));
}
void InitializeDescriptorSets()
{
descriptorPool = std::make_unique<DescriptorPool>(*instance);
uniformDescriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
uniformDescriptorSet->AddUniform(*shaderUniformBuffer, 0);
samplerDescriptorSet = std::make_unique<DescriptorSet>(*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<Pipeline>(*instance, creator);
@@ -171,6 +368,11 @@ private:
indexBuffer->Bind(commandBuffer);
shaderUniformBuffer->Bind(commandBuffer);
std::vector<VkDescriptorSet> 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);