0% found this document useful (0 votes)
4 views13 pages

Pipeline

The document outlines the implementation of a graphics rendering pipeline using Vulkan, including the initialization and deinitialization of resources such as buffers, images, and shader modules. It details the creation of a graphics pipeline, including shader stages, vertex input state, and rasterization settings. Additionally, the document includes functions for handling texture images and memory management within the Vulkan framework.

Uploaded by

AlbertCG93
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views13 pages

Pipeline

The document outlines the implementation of a graphics rendering pipeline using Vulkan, including the initialization and deinitialization of resources such as buffers, images, and shader modules. It details the creation of a graphics pipeline, including shader stages, vertex input state, and rasterization settings. Additionally, the document includes functions for handling texture images and memory management within the Vulkan framework.

Uploaded by

AlbertCG93
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 13

#include <renderer/Pipeline.

hpp>

#include <array>
#include <fstream>
#include <filesystem>
#include <renderer/Renderer.hpp>
#include <renderer/RenderPass.hpp>
#include <renderer/SwapChain.hpp>
#include <renderer/VulkanHandler.hpp>
// The following define ensures that the implementation gets added
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>

Pipeline::Pipeline()
: _vulkanHandler (nullptr), _pipelineLayout (VK_NULL_HANDLE), _vertexBuffer
(VK_NULL_HANDLE), _vertexBufferMemory (VK_NULL_HANDLE), _indexBuffer
(VK_NULL_HANDLE), _indexBufferMemory(VK_NULL_HANDLE), _textureImage
(VK_NULL_HANDLE), _textureImageMemory (VK_NULL_HANDLE), _textureImageView
(VK_NULL_HANDLE), _textureSampler (VK_NULL_HANDLE), _descriptorSetLayout
(VK_NULL_HANDLE), _descriptorPool (VK_NULL_HANDLE) {

void Pipeline::init(VulkanHandler* vulkanHandler, SwapChain* swapChain, RenderPass*


renderPass) {
_vulkanHandler = vulkanHandler;

createDescriptorSetLayout();
createGraphicsPipeline(swapChain, renderPass);

// createTextureImage();
// createTextureImageView();
// createTextureSampler();

createUniformBuffers();
createDescriptorPool();
createDescriptorSets();
}

void Pipeline::deinit() {
vkDestroyPipeline(_vulkanHandler->_logicalDevice, _pipeline, nullptr);
vkDestroyPipelineLayout(_vulkanHandler->_logicalDevice, _pipelineLayout,
nullptr);

for (size_t i = 0; i < Renderer::MAX_FRAMES_IN_FLIGHT; ++i) {


vkDestroyBuffer(_vulkanHandler->_logicalDevice, _uniformBuffers[i],
nullptr);
vkFreeMemory(_vulkanHandler->_logicalDevice, _uniformBuffersMemory[i],
nullptr);
}

vkDestroyDescriptorPool(_vulkanHandler->_logicalDevice, _descriptorPool,
nullptr);

vkDestroyImage(_vulkanHandler->_logicalDevice, _textureImage, nullptr);


vkFreeMemory(_vulkanHandler->_logicalDevice, _textureImageMemory, nullptr);

vkDestroyDescriptorSetLayout(_vulkanHandler->_logicalDevice,
_descriptorSetLayout, nullptr);

vkDestroyBuffer(_vulkanHandler->_logicalDevice, _indexBuffer, nullptr);


vkFreeMemory(_vulkanHandler->_logicalDevice, _indexBufferMemory, nullptr);

vkDestroyBuffer(_vulkanHandler->_logicalDevice, _vertexBuffer, nullptr);


vkFreeMemory(_vulkanHandler->_logicalDevice, _vertexBufferMemory, nullptr);
}

void Pipeline::createGraphicsPipeline(SwapChain* swapChain, RenderPass* renderPass)


{
std::vector<char> vertShaderCode = readFile("../shaders/vert.spv");
std::vector<char> fragShaderCode = readFile("../shaders/frag.spv");

VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);


VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);

VkPipelineShaderStageCreateInfo vertShaderStageInfo {};


vertShaderStageInfo.sType =
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertShaderStageInfo.module = vertShaderModule;
vertShaderStageInfo.pName = "main";

VkPipelineShaderStageCreateInfo fragShaderStageInfo {};


fragShaderStageInfo.sType =
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragShaderStageInfo.module = fragShaderModule;
fragShaderStageInfo.pName = "main";

VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo,


fragShaderStageInfo};

VkPipelineVertexInputStateCreateInfo vertexInputInfo {};


vertexInputInfo.sType =
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;

VkVertexInputBindingDescription bindingDescription =
Vertex::getBindingDescription();
Vertex::AttributeDescriptions attributeDescriptions =
Vertex::getAttributeDescriptions();

vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.vertexAttributeDescriptionCount =
static_cast<uint32_t>(attributeDescriptions.size());
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();

VkPipelineInputAssemblyStateCreateInfo inputAssembly {};


inputAssembly.sType =
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
inputAssembly.primitiveRestartEnable = VK_FALSE;

VkViewport viewport {};


viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float) swapChain->_extent.width;
viewport.height = (float) swapChain->_extent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;

VkRect2D scissor {};


scissor.offset = {0, 0};
scissor.extent = swapChain->_extent;

VkPipelineViewportStateCreateInfo viewportState {};


viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;

VkPipelineRasterizationStateCreateInfo rasterizer {};


rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;

rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;

rasterizer.depthBiasEnable = VK_FALSE;
rasterizer.depthBiasConstantFactor = 0.0f;
rasterizer.depthBiasClamp = 0.0f;
rasterizer.depthBiasSlopeFactor = 0.0f;

VkPipelineMultisampleStateCreateInfo multisampling {};


multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisampling.minSampleShading = 1.0f;
multisampling.pSampleMask = nullptr;
multisampling.alphaToCoverageEnable = VK_FALSE;
multisampling.alphaToOneEnable = VK_FALSE;

VkPipelineColorBlendAttachmentState colorBlendAttachment {};


colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
colorBlendAttachment.blendEnable = VK_TRUE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;

VkPipelineColorBlendStateCreateInfo colorBlending {};


colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = VK_LOGIC_OP_COPY;
colorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment;
colorBlending.blendConstants[0] = 0.0f;
colorBlending.blendConstants[1] = 0.0f;
colorBlending.blendConstants[2] = 0.0f;
colorBlending.blendConstants[3] = 0.0f;

VkPipelineLayoutCreateInfo pipelineLayoutInfo {};


pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &_descriptorSetLayout;
pipelineLayoutInfo.pushConstantRangeCount = 0;
pipelineLayoutInfo.pPushConstantRanges = nullptr;

if (vkCreatePipelineLayout(_vulkanHandler->_logicalDevice, &pipelineLayoutInfo,
nullptr, &_pipelineLayout) != VK_SUCCESS) {
throw std::runtime_error("Failed to create pipeline layout!");
}

VkGraphicsPipelineCreateInfo pipelineInfo {};


pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages;

pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = nullptr;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr;

pipelineInfo.layout = _pipelineLayout;

pipelineInfo.renderPass = renderPass->_renderPass;
pipelineInfo.subpass = 0;

if (vkCreateGraphicsPipelines(_vulkanHandler->_logicalDevice, VK_NULL_HANDLE,
1, &pipelineInfo, nullptr, &_pipeline) != VK_SUCCESS) {
throw std::runtime_error("Failed to create graphics pipeline!");
}

vkDestroyShaderModule(_vulkanHandler->_logicalDevice, fragShaderModule,
nullptr);
vkDestroyShaderModule(_vulkanHandler->_logicalDevice, vertShaderModule,
nullptr);
}

std::vector<char> Pipeline::readFile(const std::string& filename) {


std::ifstream file {filename, std::ios::ate | std::ios::binary};

if (!file.is_open()) {
throw std::runtime_error("Failed to open file '" + filename + " with
current path '" + std::filesystem::current_path().string() + "'!");
}

size_t fileSize = (size_t) file.tellg();


std::vector<char> buffer(fileSize);

file.seekg(0);
file.read(buffer.data(), fileSize);

file.close();
return buffer;
}

VkShaderModule Pipeline::createShaderModule(const std::vector<char>& code) const {


VkShaderModuleCreateInfo createInfo {};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());

VkShaderModule shaderModule;
if (vkCreateShaderModule(_vulkanHandler->_logicalDevice, &createInfo, nullptr,
&shaderModule) != VK_SUCCESS) {
throw std::runtime_error("failed to create shader module!");
}

return shaderModule;
}

void Pipeline::createTextureImage() {
int texWidth, texHeight, texChannels;
stbi_uc* pixels = stbi_load("textures/arial_a.png", &texWidth, &texHeight,
&texChannels, STBI_rgb_alpha);
VkDeviceSize imageSize = texWidth * texHeight * 4;

if (!pixels) {
throw std::runtime_error("Failed to load texture image!");
}

VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;

createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
stagingBuffer, stagingBufferMemory);

void* data;
vkMapMemory(_vulkanHandler->_logicalDevice, stagingBufferMemory, 0, imageSize,
0, &data);
memcpy(data, pixels, static_cast<size_t>(imageSize));
vkUnmapMemory(_vulkanHandler->_logicalDevice, stagingBufferMemory);

stbi_image_free(pixels);

createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM,


VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, _textureImage,
_textureImageMemory);

transitionImageLayout(_textureImage, VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
copyBufferToImage(stagingBuffer, _textureImage,
static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
transitionImageLayout(_textureImage, VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);

transitionImageLayout(_textureImage, VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkDestroyBuffer(_vulkanHandler->_logicalDevice, stagingBuffer, nullptr);
vkFreeMemory(_vulkanHandler->_logicalDevice, stagingBufferMemory, nullptr);
}

void Pipeline::createImage(uint32_t width, uint32_t height, VkFormat format,


VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties,
VkImage& image, VkDeviceMemory& imageMemory) {
VkImageCreateInfo imageInfo {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = width;
imageInfo.extent.height = height;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = format;
imageInfo.tiling = tiling;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = usage;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.flags = 0;

if (vkCreateImage(_vulkanHandler->_logicalDevice, &imageInfo, nullptr,


&image) != VK_SUCCESS) {
throw std::runtime_error("Failed to create image!");
}

VkMemoryRequirements memoryRequirements;
vkGetImageMemoryRequirements(_vulkanHandler->_logicalDevice, image,
&memoryRequirements);

VkMemoryAllocateInfo allocInfo {};


allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memoryRequirements.size;
allocInfo.memoryTypeIndex = _vulkanHandler-
>findMemoryType(memoryRequirements.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

if (vkAllocateMemory(_vulkanHandler->_logicalDevice, &allocInfo, nullptr,


&imageMemory) != VK_SUCCESS) {
throw std::runtime_error("Failed to allocate image memory!");
}

vkBindImageMemory(_vulkanHandler->_logicalDevice, _textureImage, imageMemory,


0);
}

void Pipeline::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout


oldLayout, VkImageLayout newLayout) const {
VkCommandBuffer commandBuffer = _vulkanHandler->beginSingleTimeCommands();

VkImageMemoryBarrier barrier {};


barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;

// Indicate no queue family ownership transfer


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;

VkPipelineStageFlags sourceStage;
VkPipelineStageFlags destinationStage;

if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout ==


VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;

sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destinationStage = 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;

sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else {
throw std::invalid_argument("Unsupported layout transition!");
}

vkCmdPipelineBarrier(
commandBuffer,
sourceStage, destinationStage,
0,
0, nullptr,
0, nullptr,
1, &barrier
);

_vulkanHandler->endSingleTimeCommands(commandBuffer);
}

void Pipeline::copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width,


uint32_t height) const {
VkCommandBuffer commandBuffer = _vulkanHandler->beginSingleTimeCommands();

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,
image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&region
);

_vulkanHandler->endSingleTimeCommands(commandBuffer);
}

void Pipeline::createTextureImageView() {
_textureImageView = _vulkanHandler->createImageView(_textureImage,
VK_FORMAT_R8G8B8A8_UNORM);
}

void Pipeline::createTextureSampler() {
VkSamplerCreateInfo samplerInfo {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;

samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;

VkPhysicalDeviceProperties properties {};


vkGetPhysicalDeviceProperties(_vulkanHandler->_physicalDevice, &properties);

samplerInfo.anisotropyEnable = VK_TRUE;
samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;

samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;

samplerInfo.unnormalizedCoordinates = VK_FALSE;

samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;

samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.mipLodBias = 0.0f;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0f;

if (vkCreateSampler(_vulkanHandler->_logicalDevice, &samplerInfo, nullptr,


&_textureSampler) != VK_SUCCESS) {
throw std::runtime_error("Failed to create texture sampler!");
}
}

void Pipeline::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,


VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory)
const {
VkBufferCreateInfo bufferInfo {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;

if (vkCreateBuffer(_vulkanHandler->_logicalDevice, &bufferInfo, nullptr,


&buffer) != VK_SUCCESS) {
throw std::runtime_error("Failed to create vertex buffer!");
}

VkMemoryRequirements memoryRequirements;
vkGetBufferMemoryRequirements(_vulkanHandler->_logicalDevice, buffer,
&memoryRequirements);

VkMemoryAllocateInfo allocInfo {};


allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memoryRequirements.size;
allocInfo.memoryTypeIndex = _vulkanHandler-
>findMemoryType(memoryRequirements.memoryTypeBits, properties);

if (vkAllocateMemory(_vulkanHandler->_logicalDevice, &allocInfo, nullptr,


&bufferMemory) != VK_SUCCESS) {
throw std::runtime_error("Failed to allocate vertex buffer memory!");
}

vkBindBufferMemory(_vulkanHandler->_logicalDevice, buffer, bufferMemory, 0);


}

void Pipeline::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize


size) const {
VkCommandBuffer commandBuffer = _vulkanHandler->beginSingleTimeCommands();

VkBufferCopy copyRegion{};
copyRegion.size = size;
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);

_vulkanHandler->endSingleTimeCommands(commandBuffer);
}

void Pipeline::createVertexBuffer() {
VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
createBuffer(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
_vertexBuffer, _vertexBufferMemory);

VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
stagingBuffer, stagingBufferMemory);

void* data;
vkMapMemory(_vulkanHandler->_logicalDevice, stagingBufferMemory, 0, bufferSize,
0, &data);
memcpy(data, vertices.data(), (size_t) bufferSize);
vkUnmapMemory(_vulkanHandler->_logicalDevice, stagingBufferMemory);

createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
_vertexBuffer, _vertexBufferMemory);

copyBuffer(stagingBuffer, _vertexBuffer, bufferSize);


vkDestroyBuffer(_vulkanHandler->_logicalDevice, stagingBuffer, nullptr);
vkFreeMemory(_vulkanHandler->_logicalDevice, stagingBufferMemory, nullptr);
}

void Pipeline::createIndexBuffer() {
VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();

VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
stagingBuffer, stagingBufferMemory);

void* data;
vkMapMemory(_vulkanHandler->_logicalDevice, stagingBufferMemory, 0, bufferSize,
0, &data);
memcpy(data, indices.data(), (size_t) bufferSize);
vkUnmapMemory(_vulkanHandler->_logicalDevice, stagingBufferMemory);

createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
_indexBuffer, _indexBufferMemory);

copyBuffer(stagingBuffer, _indexBuffer, bufferSize);

vkDestroyBuffer(_vulkanHandler->_logicalDevice, stagingBuffer, nullptr);


vkFreeMemory(_vulkanHandler->_logicalDevice, stagingBufferMemory, nullptr);
}

void Pipeline::createUniformBuffers() {
VkDeviceSize bufferSize = sizeof(UniformBufferObject);

_uniformBuffers.resize(Renderer::MAX_FRAMES_IN_FLIGHT);
_uniformBuffersMemory.resize(Renderer::MAX_FRAMES_IN_FLIGHT);

for (size_t i = 0; i < Renderer::MAX_FRAMES_IN_FLIGHT; ++i) {


createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
_uniformBuffers[i], _uniformBuffersMemory[i]);
}
}

void Pipeline::updateUniformBuffer(uint32_t currentImage) {


UniformBufferObject ubo {};
ubo.model = glm::mat4(1.0);
ubo.view = glm::mat4(1.0);
ubo.proj = glm::mat4(1.0);

void* data;
vkMapMemory(_vulkanHandler->_logicalDevice,
_uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
memcpy(data, &ubo, sizeof(ubo));
vkUnmapMemory(_vulkanHandler->_logicalDevice,
_uniformBuffersMemory[currentImage]);
}

void Pipeline::createShaderStorageBuffers() {
_shaderStorageBuffers.resize(Renderer::MAX_FRAMES_IN_FLIGHT);
_shaderStorageBuffersMemory.resize(Renderer::MAX_FRAMES_IN_FLIGHT);
}

void Pipeline::updateShaderStorageBuffer(uint32_t currentImage, glm::vec4 color) {


VkDeviceSize bufferSize = sizeof(StorageBufferObject);

createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
_shaderStorageBuffers[currentImage], _shaderStorageBuffersMemory[currentImage]);

void* data;
vkMapMemory(_vulkanHandler->_logicalDevice,
_uniformBuffersMemory[currentImage], 0, sizeof(color), 0, &data);
memcpy(data, &color, sizeof(color));
vkUnmapMemory(_vulkanHandler->_logicalDevice,
_uniformBuffersMemory[currentImage]);
}

void Pipeline::createDescriptorPool() {
std::array<VkDescriptorPoolSize, 2> poolSizes {};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSizes[0].descriptorCount =
static_cast<uint32_t>(Renderer::MAX_FRAMES_IN_FLIGHT);
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSizes[1].descriptorCount =
static_cast<uint32_t>(Renderer::MAX_FRAMES_IN_FLIGHT);

VkDescriptorPoolCreateInfo poolInfo {};


poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
poolInfo.pPoolSizes = poolSizes.data();

poolInfo.maxSets = static_cast<uint32_t>(Renderer::MAX_FRAMES_IN_FLIGHT);

if (vkCreateDescriptorPool(_vulkanHandler->_logicalDevice, &poolInfo, nullptr,


&_descriptorPool) != VK_SUCCESS) {
throw std::runtime_error("Failed to create descriptor pool!");
}
}

void Pipeline::createDescriptorSetLayout() {
VkDescriptorSetLayoutBinding uboLayoutBinding {};
uboLayoutBinding.binding = 0;
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uboLayoutBinding.descriptorCount = 1;
uboLayoutBinding.pImmutableSamplers = nullptr;
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;

VkDescriptorSetLayoutBinding samplerLayoutBinding {};


samplerLayoutBinding.binding = 1;
samplerLayoutBinding.descriptorCount = 1;
samplerLayoutBinding.descriptorType =
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
samplerLayoutBinding.pImmutableSamplers = nullptr;
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;

std::array<VkDescriptorSetLayoutBinding, 2> bindings = {uboLayoutBinding,


samplerLayoutBinding};
VkDescriptorSetLayoutCreateInfo layoutInfo {};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
layoutInfo.pBindings = bindings.data();

if (vkCreateDescriptorSetLayout(_vulkanHandler->_logicalDevice, &layoutInfo,
nullptr, &_descriptorSetLayout) != VK_SUCCESS) {
throw std::runtime_error("Failed to create descriptor set layout!");
}
}

void Pipeline::createDescriptorSets() {
std::vector<VkDescriptorSetLayout> layouts(Renderer::MAX_FRAMES_IN_FLIGHT,
_descriptorSetLayout);

VkDescriptorSetAllocateInfo allocInfo {};


allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = _descriptorPool;
allocInfo.descriptorSetCount =
static_cast<uint32_t>(Renderer::MAX_FRAMES_IN_FLIGHT);
allocInfo.pSetLayouts = layouts.data();

_descriptorSets.resize(Renderer::MAX_FRAMES_IN_FLIGHT);
if (vkAllocateDescriptorSets(_vulkanHandler->_logicalDevice, &allocInfo,
_descriptorSets.data()) != VK_SUCCESS) {
throw std::runtime_error("Failed to allocate descriptor sets!");
}

for (size_t i = 0; i < Renderer::MAX_FRAMES_IN_FLIGHT; ++i) {


VkDescriptorBufferInfo bufferInfo {};
bufferInfo.buffer = _uniformBuffers[i];
bufferInfo.offset = 0;
bufferInfo.range = sizeof(UniformBufferObject);

VkDescriptorImageInfo imageInfo {};


imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.imageView = _textureImageView;
imageInfo.sampler = _textureSampler;

std::array<VkWriteDescriptorSet, 2> descriptorWrites {};

descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].dstSet = _descriptorSets[i];
descriptorWrites[0].dstBinding = 0;
descriptorWrites[0].dstArrayElement = 0;

descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrites[0].descriptorCount = 1;

descriptorWrites[0].pBufferInfo = &bufferInfo;
descriptorWrites[0].pImageInfo = nullptr;
descriptorWrites[0].pTexelBufferView = nullptr;

descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[1].dstSet = _descriptorSets[i];
descriptorWrites[1].dstBinding = 1;
descriptorWrites[1].dstArrayElement = 0;

descriptorWrites[1].descriptorType =
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrites[1].descriptorCount = 1;

descriptorWrites[1].pBufferInfo = nullptr;
descriptorWrites[1].pImageInfo = &imageInfo;
descriptorWrites[1].pTexelBufferView = nullptr;

vkUpdateDescriptorSets(_vulkanHandler->_logicalDevice,
static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0,
nullptr);
}
}

void Pipeline::clearVertexData() {
vertices.clear();
indices.clear();
}

void Pipeline::createRectangle(float x, float y, float width, float height) {


float xx = 2.0 * x - 1.0;
float yy = 2.0 * y - 1.0;

Vertex topLeft = {{xx, yy}, TOP_LEFT_TEXTURE_COORDINATES};


Vertex bottomLeft = {{xx, yy + 2.0 * height}, BOTTOM_LEFT_TEXTURE_COORDINATES};
Vertex topRight = {{xx + 2.0 * width, yy}, TOP_RIGHT_TEXTURE_COORDINATES};
Vertex bottomRight = {{xx + 2.0 * width, yy + 2.0 * height},
BOTTOM_RIGHT_TEXTURE_COORDINATES};

uint16_t index = static_cast<uint16_t>(vertices.size());

vertices.push_back(topLeft);
vertices.push_back(bottomLeft);
vertices.push_back(topRight);
vertices.push_back(bottomRight);

indices.push_back(index);
indices.push_back(index + 2);
indices.push_back(index + 3);

indices.push_back(index);
indices.push_back(index + 3);
indices.push_back(index + 1);
}

You might also like