Add Sampler
- Add DescriptorSet and DescriptorPool abstractions to support Samplers
This commit is contained in:
@@ -168,11 +168,13 @@
|
|||||||
<ClInclude Include="src\Buffer.h" />
|
<ClInclude Include="src\Buffer.h" />
|
||||||
<ClInclude Include="src\Common.h" />
|
<ClInclude Include="src\Common.h" />
|
||||||
<ClInclude Include="src\DebugMessenger.h" />
|
<ClInclude Include="src\DebugMessenger.h" />
|
||||||
|
<ClInclude Include="src\DescriptorSet.h" />
|
||||||
|
<ClInclude Include="src\DescriptorPool.h" />
|
||||||
<ClInclude Include="src\FileSystem.h" />
|
<ClInclude Include="src\FileSystem.h" />
|
||||||
<ClInclude Include="src\Framebuffer.h" />
|
|
||||||
<ClInclude Include="src\IndexBuffer.h" />
|
<ClInclude Include="src\IndexBuffer.h" />
|
||||||
<ClInclude Include="src\Pipeline.h" />
|
<ClInclude Include="src\Pipeline.h" />
|
||||||
<ClInclude Include="src\PipelineCreator.h" />
|
<ClInclude Include="src\PipelineCreator.h" />
|
||||||
|
<ClInclude Include="src\Sampler.h" />
|
||||||
<ClInclude Include="src\UniformBuffer.h" />
|
<ClInclude Include="src\UniformBuffer.h" />
|
||||||
<ClInclude Include="src\Instance.h" />
|
<ClInclude Include="src\Instance.h" />
|
||||||
<ClInclude Include="src\QueueFamilies.h" />
|
<ClInclude Include="src\QueueFamilies.h" />
|
||||||
|
|||||||
@@ -74,7 +74,13 @@
|
|||||||
<ClInclude Include="src\VertexDescriptor.h">
|
<ClInclude Include="src\VertexDescriptor.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</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>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -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.
@@ -1,8 +1,12 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform sampler2D texSampler;
|
||||||
|
|
||||||
layout(location = 0) in vec3 fragColor;
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
layout(location = 1) in vec2 fragTexCoord;
|
||||||
|
|
||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = vec4(fragColor, 1.0);
|
outColor = vec4(fragColor, 1.0) * texture(texSampler, fragTexCoord);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,13 @@ layout(set = 0, binding = 0) uniform SceneUniformBufferObject
|
|||||||
|
|
||||||
layout(location = 0) in vec2 inPosition;
|
layout(location = 0) in vec2 inPosition;
|
||||||
layout(location = 1) in vec3 inColor;
|
layout(location = 1) in vec3 inColor;
|
||||||
|
layout(location = 2) in vec2 inTexCoord;
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragColor;
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
layout(location = 1) out vec2 fragTexCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition.x, 0.0, inPosition.y, 1.0);
|
gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition.x, 0.0, inPosition.y, 1.0);
|
||||||
fragColor = inColor;
|
fragColor = inColor;
|
||||||
|
fragTexCoord = inTexCoord;
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 421 KiB |
+3
-15
@@ -36,7 +36,7 @@ public:
|
|||||||
VkMemoryAllocateInfo allocateInfo{};
|
VkMemoryAllocateInfo allocateInfo{};
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
allocateInfo.allocationSize = memoryRequirements.size;
|
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");
|
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);
|
CopyBuffer(instance, stagingBuffer, *this, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map()
|
void* Map()
|
||||||
{
|
{
|
||||||
CP_ASSERT(mappedData == nullptr, "Mapping an already mapped buffer");
|
CP_ASSERT(mappedData == nullptr, "Mapping an already mapped buffer");
|
||||||
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
|
vkMapMemory(instance.GetDevice(), memory, 0, size * count, 0, &mappedData);
|
||||||
|
return mappedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unmap()
|
void Unmap()
|
||||||
@@ -166,17 +167,4 @@ public:
|
|||||||
|
|
||||||
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), 1, &commandBuffer);
|
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");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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
@@ -157,6 +157,19 @@ public:
|
|||||||
return *swapChain;
|
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:
|
private:
|
||||||
void InitializeWindow(const std::string& applicationName)
|
void InitializeWindow(const std::string& applicationName)
|
||||||
{
|
{
|
||||||
@@ -277,6 +290,7 @@ private:
|
|||||||
std::vector<const char*> deviceExtensions = GetRequiredDeviceExtensions();
|
std::vector<const char*> deviceExtensions = GetRequiredDeviceExtensions();
|
||||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||||
deviceFeatures.fillModeNonSolid = VK_TRUE;
|
deviceFeatures.fillModeNonSolid = VK_TRUE;
|
||||||
|
deviceFeatures.samplerAnisotropy = VK_TRUE;
|
||||||
VkDeviceCreateInfo createInfo{};
|
VkDeviceCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||||
@@ -380,7 +394,7 @@ private:
|
|||||||
|
|
||||||
VkPhysicalDeviceFeatures deviceFeatures;
|
VkPhysicalDeviceFeatures deviceFeatures;
|
||||||
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
|
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
|
||||||
if (!deviceFeatures.fillModeNonSolid)
|
if (!deviceFeatures.fillModeNonSolid || !deviceFeatures.samplerAnisotropy)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QueueFamiliesQuery query{surface, device};
|
QueueFamiliesQuery query{surface, device};
|
||||||
|
|||||||
+29
-53
@@ -15,8 +15,7 @@ class Pipeline
|
|||||||
private:
|
private:
|
||||||
Instance& instance;
|
Instance& instance;
|
||||||
|
|
||||||
VkDescriptorSetLayout vertexDescriptorSetLayout;
|
std::vector<VkDescriptorSetLayout> descriptorSetLayouts{};
|
||||||
VkDescriptorSetLayout fragmentDescriptorSetLayout;
|
|
||||||
VkPipelineLayout pipelineLayout;
|
VkPipelineLayout pipelineLayout;
|
||||||
VkPipeline graphicsPipeline;
|
VkPipeline graphicsPipeline;
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ public:
|
|||||||
Pipeline(Instance& instance, PipelineCreator creator)
|
Pipeline(Instance& instance, PipelineCreator creator)
|
||||||
: instance{instance}
|
: instance{instance}
|
||||||
{
|
{
|
||||||
InitializeDescriptorSetLayouts(creator);
|
InitializeDescriptorSetLayout(creator);
|
||||||
InitializePipeline(creator);
|
InitializePipeline(creator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,8 +31,10 @@ public:
|
|||||||
{
|
{
|
||||||
vkDestroyPipeline(instance.GetDevice(), graphicsPipeline, nullptr);
|
vkDestroyPipeline(instance.GetDevice(), graphicsPipeline, nullptr);
|
||||||
vkDestroyPipelineLayout(instance.GetDevice(), pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(instance.GetDevice(), pipelineLayout, nullptr);
|
||||||
vkDestroyDescriptorSetLayout(instance.GetDevice(), vertexDescriptorSetLayout, nullptr);
|
for (auto&& descriptorSetLayout : descriptorSetLayouts)
|
||||||
vkDestroyDescriptorSetLayout(instance.GetDevice(), fragmentDescriptorSetLayout, nullptr);
|
{
|
||||||
|
vkDestroyDescriptorSetLayout(instance.GetDevice(), descriptorSetLayout, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bind(VkCommandBuffer commandBuffer)
|
void Bind(VkCommandBuffer commandBuffer)
|
||||||
@@ -59,21 +60,32 @@ public:
|
|||||||
return pipelineLayout;
|
return pipelineLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSetLayout GetVertexDescriptorSetLayout()
|
VkDescriptorSetLayout GetDescriptorSetLayout(uint32_t setIndex) const
|
||||||
{
|
{
|
||||||
return vertexDescriptorSetLayout;
|
return descriptorSetLayouts[setIndex];
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSetLayout GetFragmentDescriptorSetLayout()
|
|
||||||
{
|
|
||||||
return fragmentDescriptorSetLayout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitializeDescriptorSetLayouts(const PipelineCreator& creator)
|
void InitializeDescriptorSetLayout(const PipelineCreator& creator)
|
||||||
{
|
{
|
||||||
vertexDescriptorSetLayout = InitializeDescriptorSetLayouts(creator.vertexDescriptorSetLayouts, VK_SHADER_STAGE_VERTEX_BIT);
|
descriptorSetLayouts.resize(creator.descriptorSetLayouts.size());
|
||||||
fragmentDescriptorSetLayout = InitializeDescriptorSetLayouts(creator.fragmentDescriptorSetLayouts, VK_SHADER_STAGE_FRAGMENT_BIT);
|
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)
|
void InitializePipeline(const PipelineCreator& creator)
|
||||||
@@ -185,13 +197,10 @@ private:
|
|||||||
colorBlendCreateInfo.blendConstants[2] = 0.0f;
|
colorBlendCreateInfo.blendConstants[2] = 0.0f;
|
||||||
colorBlendCreateInfo.blendConstants[3] = 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{};
|
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{};
|
||||||
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
pipelineLayoutCreateInfo.setLayoutCount = layouts.size();
|
pipelineLayoutCreateInfo.setLayoutCount = descriptorSetLayouts.size();
|
||||||
pipelineLayoutCreateInfo.pSetLayouts = layouts.data();
|
pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts.data();
|
||||||
pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
|
pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
|
||||||
pipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
|
pipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
|
||||||
|
|
||||||
@@ -234,37 +243,4 @@ private:
|
|||||||
return shaderModule;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
@@ -6,10 +6,14 @@
|
|||||||
|
|
||||||
class PipelineCreator
|
class PipelineCreator
|
||||||
{
|
{
|
||||||
|
struct DescriptorSetLayout
|
||||||
|
{
|
||||||
|
VkDescriptorType type;
|
||||||
|
VkShaderStageFlags flags;
|
||||||
|
};
|
||||||
friend class Pipeline;
|
friend class Pipeline;
|
||||||
private:
|
private:
|
||||||
std::set<uint32_t> vertexDescriptorSetLayouts{};
|
std::map<uint32_t, DescriptorSetLayout> descriptorSetLayouts{};
|
||||||
std::set<uint32_t> fragmentDescriptorSetLayouts{};
|
|
||||||
|
|
||||||
std::string vertexShader;
|
std::string vertexShader;
|
||||||
std::string fragmentShader;
|
std::string fragmentShader;
|
||||||
@@ -29,15 +33,9 @@ public:
|
|||||||
vertexDescriptor = descriptor;
|
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");
|
descriptorSetLayouts.emplace(set, DescriptorSetLayout{type, stageFlags});
|
||||||
vertexDescriptorSetLayouts.emplace(binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddFragmentDescriptorSetLayoutBinding(uint32_t binding)
|
|
||||||
{
|
|
||||||
fragmentDescriptorSetLayouts.emplace(binding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPrimitiveTopology(VkPrimitiveTopology primitiveTopology)
|
void SetPrimitiveTopology(VkPrimitiveTopology primitiveTopology)
|
||||||
|
|||||||
@@ -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");
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -5,84 +5,28 @@
|
|||||||
#include "Pipeline.h"
|
#include "Pipeline.h"
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class UniformBuffer : public Buffer
|
class UniformBuffer : public Buffer
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(UniformBuffer);
|
CP_DELETE_COPY_AND_MOVE_CTOR(UniformBuffer);
|
||||||
private:
|
|
||||||
Pipeline& pipeline;
|
|
||||||
|
|
||||||
VkDescriptorPool descriptorPool;
|
|
||||||
std::vector<VkDescriptorSet> descriptorSets;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UniformBuffer(Instance& instance, Pipeline& pipeline, uint32_t binding, VkDescriptorSetLayout layout)
|
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, sizeof(T), instance.GetMaxFramesInFlight()}, pipeline{pipeline}
|
: Buffer{instance, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, size, instance.GetMaxFramesInFlight()}
|
||||||
{
|
{}
|
||||||
InitializeDescriptorPool();
|
|
||||||
InitializeDescriptorSet(binding, layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
~UniformBuffer() override
|
|
||||||
{
|
|
||||||
vkDestroyDescriptorPool(instance.GetDevice(), descriptorPool, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
void Update(const T& 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());
|
Buffer::Update((void*)&t, instance.GetFlightIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bind(VkCommandBuffer commandBuffer) const
|
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:
|
VkDescriptorBufferInfo GetDescriptorBufferInfo(int index) const
|
||||||
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 bufferInfo{};
|
VkDescriptorBufferInfo bufferInfo{};
|
||||||
bufferInfo.buffer = handle;
|
bufferInfo.buffer = handle;
|
||||||
|
|||||||
+2
-28
@@ -7,41 +7,15 @@
|
|||||||
struct Vertex {
|
struct Vertex {
|
||||||
glm::vec2 pos;
|
glm::vec2 pos;
|
||||||
glm::vec3 color;
|
glm::vec3 color;
|
||||||
|
glm::vec2 texCoord;
|
||||||
|
|
||||||
static VertexDescriptor GetDescriptor()
|
static VertexDescriptor GetDescriptor()
|
||||||
{
|
{
|
||||||
VertexDescriptor descriptor{};
|
VertexDescriptor descriptor{};
|
||||||
descriptor.AddAttribute<Vertex>(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, pos));
|
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, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color));
|
||||||
|
descriptor.AddAttribute<Vertex>(0, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, texCoord));
|
||||||
return descriptor;
|
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
@@ -5,8 +5,11 @@
|
|||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "UniformBuffer.h"
|
#include "UniformBuffer.h"
|
||||||
|
#include "Sampler.h"
|
||||||
#include "Vertex.h"
|
#include "Vertex.h"
|
||||||
#include "Pipeline.h"
|
#include "Pipeline.h"
|
||||||
|
#include "DescriptorPool.h"
|
||||||
|
#include "DescriptorSet.h"
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -14,29 +17,16 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include <stb/stb_image.h>
|
#include <stb/stb_image.h>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
const std::vector<Vertex> vertices = {
|
const std::vector<Vertex> vertices = {
|
||||||
Vertex{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.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}},
|
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}},
|
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}}
|
Vertex{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.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}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<uint16_t> indices = {
|
const std::vector<uint16_t> indices = {
|
||||||
@@ -58,15 +48,27 @@ private:
|
|||||||
std::unique_ptr<Pipeline> graphicsPipeline;
|
std::unique_ptr<Pipeline> graphicsPipeline;
|
||||||
std::unique_ptr<VertexBuffer> vertexBuffer;
|
std::unique_ptr<VertexBuffer> vertexBuffer;
|
||||||
std::unique_ptr<IndexBuffer> indexBuffer;
|
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;
|
std::vector<VkCommandBuffer> commandBuffers;
|
||||||
|
|
||||||
|
VkImage textureImage;
|
||||||
|
VkDeviceMemory textureImageMemory;
|
||||||
|
VkImageView textureImageView;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application()
|
Application()
|
||||||
{
|
{
|
||||||
InitializeInstance();
|
InitializeInstance();
|
||||||
InitializeGraphicsPipeline();
|
InitializeGraphicsPipeline();
|
||||||
|
InitializeTextureImage();
|
||||||
|
InitializeTextureImageView();
|
||||||
|
InitializeTextureSampler();
|
||||||
InitializeUniformBuffer();
|
InitializeUniformBuffer();
|
||||||
|
InitializeDescriptorSets();
|
||||||
InitializeVertexBuffer();
|
InitializeVertexBuffer();
|
||||||
InitializeIndexBuffer();
|
InitializeIndexBuffer();
|
||||||
InitializeCommandBuffers();
|
InitializeCommandBuffers();
|
||||||
@@ -75,6 +77,9 @@ public:
|
|||||||
~Application()
|
~Application()
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(instance->GetDevice());
|
vkDeviceWaitIdle(instance->GetDevice());
|
||||||
|
vkDestroyImage(instance->GetDevice(), textureImage, nullptr);
|
||||||
|
vkFreeMemory(instance->GetDevice(), textureImageMemory, nullptr);
|
||||||
|
vkDestroyImageView(instance->GetDevice(), textureImageView, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Application(Application&&) = delete;
|
Application(Application&&) = delete;
|
||||||
@@ -100,15 +105,207 @@ private:
|
|||||||
instance = std::make_unique<Instance>("Vulkan Tutorial");
|
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, ®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()
|
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()
|
void InitializeGraphicsPipeline()
|
||||||
{
|
{
|
||||||
PipelineCreator creator{"res/shaders/vert.spv", "res/shaders/frag.spv"};
|
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.SetVertexDescriptor(Vertex::GetDescriptor());
|
||||||
creator.SetCullMode(VK_CULL_MODE_NONE);
|
creator.SetCullMode(VK_CULL_MODE_NONE);
|
||||||
graphicsPipeline = std::make_unique<Pipeline>(*instance, creator);
|
graphicsPipeline = std::make_unique<Pipeline>(*instance, creator);
|
||||||
@@ -171,6 +368,11 @@ private:
|
|||||||
indexBuffer->Bind(commandBuffer);
|
indexBuffer->Bind(commandBuffer);
|
||||||
shaderUniformBuffer->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);
|
indexBuffer->Draw(commandBuffer);
|
||||||
|
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
|||||||
Reference in New Issue
Block a user