I’m building a video game engine using C++ as the coding language and Vulkan for graphics. I am trying to set up a generic renderer using Vulkan that is flexible and will render objects based on a vector that is supplied to it. The renderer will also handle the creation of the window using GLFW and use GLM for all relevant math calls. I am using the ASSIMP library to load 3d models and animations.

I am in the process of converting the code to make use of vulkan.hpp and RAII. I have recently made updates to the following code for the Material class:

Material.h:

#pragma once

#include <vulkan/vulkan.hpp>
#include "Texture.h"
#include "Shader.h"
#include <stdexcept>
#include <memory> // Don’t forget to include <memory>
#include <array>

// Add this struct outside the Material class, possibly at the top of Material.cpp
struct ShaderDeleter {
	void operator()(Shader* shaderPtr) {
		if (shaderPtr != nullptr) {
			Shader::cleanup(shaderPtr);
		}
	}
};

class Material
{
public:
	Material() = default;
	~Material();

	void Initialize(const std::string& vertShaderPath, const std::string& fragShaderPath, const std::string& texturePath, vk::Device device, vk::DescriptorSetLayout descriptorSetLayout, vk::DescriptorPool descriptorPool, vk::PhysicalDevice physicalDevice, vk::CommandPool commandPool, vk::Queue graphicsQueue);
	void Cleanup();

	void LoadTexture(const std::string& filename, vk::Device device, vk::PhysicalDevice physicalDevice, vk::CommandPool commandPool, vk::Queue graphicsQueue);
	void LoadShaders(const std::string& vertFilename, const std::string& fragFilename, vk::Device device);

	void UpdateBufferBinding(VkBuffer newBuffer, vk::Device device, vk::DeviceSize devicesize);
	vk::DescriptorSet GetDescriptorSet() const;
	vk::PipelineLayout GetPipelineLayout() const;

	std::shared_ptr <Shader> GetvertexShader();
	std::shared_ptr <Shader> GetfragmentShader();
	void CreateDescriptorSet(VkBuffer uniformBuffer, vk::DeviceSize bufferSize);

private:
	vk::Device device;
	std::shared_ptr <Shader> vertexShader;
	std::shared_ptr <Shader> fragmentShader;
	std::shared_ptr<Texture> texture;


	void CreatePipelineLayout(vk::DescriptorSetLayout descriptorSetLayout);


	vk::DescriptorSet descriptorSet;
	vk::PipelineLayout pipelineLayout;

	vk::DescriptorSetLayout descriptorSetLayout;// = VK_NULL_HANDLE;

	vk::UniqueDescriptorPool descriptorPool;

	void CleanupDescriptorSetLayout();
};


Material.cpp:

#include "Material.h"

Material::~Material()
{
	Cleanup();
}

void Material::Initialize(const std::string& vertShaderPath, const std::string& fragShaderPath, const std::string& texturePath, vk::Device device, vk::DescriptorSetLayout descriptorSetLayout, vk::DescriptorPool descriptorPool, vk::PhysicalDevice physicalDevice, vk::CommandPool commandPool, vk::Queue graphicsQueue)
{
	this->device = device;

	this->descriptorSetLayout = descriptorSetLayout;

	// Load shaders and texture
	LoadTexture(texturePath, device, physicalDevice, commandPool, graphicsQueue);
	LoadShaders(vertShaderPath, fragShaderPath, device);

	// Create descriptor set and pipeline layout
	CreatePipelineLayout(descriptorSetLayout);
}

void Material::CreateDescriptorSet(VkBuffer uniformBuffer, vk::DeviceSize bufferSize)
{
	vk::DescriptorSetAllocateInfo allocInfo{};
	allocInfo.setDescriptorPool(descriptorPool);
	allocInfo.setDescriptorSetCount(1);
	allocInfo.setPSetLayouts(&descriptorSetLayout);

	descriptorSet = device.allocateDescriptorSetsUnique(allocInfo)[0].get();

	vk::DescriptorBufferInfo bufferInfo{};
	bufferInfo.buffer = uniformBuffer;
	bufferInfo.offset = 0;
	bufferInfo.range = bufferSize;

	vk::DescriptorImageInfo imageInfo{};
	imageInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
	imageInfo.imageView = texture->GetImageView();
	imageInfo.sampler = texture->GetSampler();

	std::array<vk::WriteDescriptorSet, 2> descriptorWrites{};

	descriptorWrites[0].setDstSet(descriptorSet);
	descriptorWrites[0].setDstBinding(0);
	descriptorWrites[0].setDstArrayElement(0);
	descriptorWrites[0].setDescriptorType(vk::DescriptorType::eUniformBuffer);
	descriptorWrites[0].setDescriptorCount(1);
	descriptorWrites[0].setPBufferInfo(&bufferInfo);

	descriptorWrites[1].setDstSet(descriptorSet);
	descriptorWrites[1].setDstBinding(1);
	descriptorWrites[1].setDstArrayElement(0);
	descriptorWrites[1].setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
	descriptorWrites[1].setDescriptorCount(1);
	descriptorWrites[1].setPImageInfo(&imageInfo);

	device.updateDescriptorSets(static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}

void Material::CreatePipelineLayout(vk::DescriptorSetLayout descriptorSetLayout)
{
	vk::PipelineLayoutCreateInfo pipelineLayoutInfo{};
	pipelineLayoutInfo.setSetLayouts(descriptorSetLayout);

	pipelineLayout = device.createPipelineLayoutUnique(pipelineLayoutInfo);
}

void Material::Cleanup()
{
	if (vertexShader) {
		Shader::cleanup(vertexShader.get());
	}

	if (fragmentShader) {
		Shader::cleanup(fragmentShader.get());
	}

	if (texture) {
		texture->Cleanup();
		texture.reset();
	}

	CleanupDescriptorSetLayout();
	// Be sure to destroy the descriptor set if necessary
	// Note: If the descriptor pool is being destroyed, you don’t need to free individual descriptor sets
}

vk::DescriptorSet Material::GetDescriptorSet() const
{
	return descriptorSet;
}

vk::PipelineLayout Material::GetPipelineLayout() const
{
	return pipelineLayout.get();
}

std::shared_ptr <Shader> Material::GetvertexShader()
{
	return vertexShader;
}

std::shared_ptr <Shader> Material::GetfragmentShader()
{
	return fragmentShader;
}

void Material::LoadTexture(const std::string& filename, vk::Device device, vk::PhysicalDevice physicalDevice, vk::CommandPool commandPool, vk::Queue graphicsQueue)
{
	texture = std::make_shared<Texture>(device, physicalDevice);
	texture->LoadFromFile(filename, device, physicalDevice, commandPool, graphicsQueue);
}

void Material::LoadShaders(const std::string& vertFilename, const std::string& fragFilename, vk::Device device)
{
	vertexShader = std::make_shared<Shader>();
	fragmentShader = std::make_shared<Shader>();
	vertexShader->loadFromFile(vertFilename, device, vk::ShaderStageFlagBits::eVertex);
	fragmentShader->loadFromFile(fragFilename, device, vk::ShaderStageFlagBits::eFragment);
}

void Material::UpdateBufferBinding(VkBuffer newBuffer, vk::Device device, vk::DeviceSize devicesize)
{
	vk::DescriptorBufferInfo bufferInfo{};
	bufferInfo.buffer = newBuffer;
	bufferInfo.offset = 0;
	bufferInfo.range = devicesize;

	vk::DescriptorImageInfo imageInfo{};
	imageInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
	imageInfo.imageView = texture->GetImageView();
	imageInfo.sampler = texture->GetSampler();

	std::array<vk::WriteDescriptorSet, 2> descriptorWrites{};
	descriptorWrites[0].setDstSet(descriptorSet);
	descriptorWrites[0].setDstBinding(0);
	descriptorWrites[0].setDstArrayElement(0);
	descriptorWrites[0].setDescriptorType(vk::DescriptorType::eUniformBuffer);
	descriptorWrites[0].setDescriptorCount(1);
	descriptorWrites[0].setPBufferInfo(&bufferInfo);

	descriptorWrites[1].setDstSet(descriptorSet);
	descriptorWrites[1].setDstBinding(1);
	descriptorWrites[1].setDstArrayElement(0);
	descriptorWrites[1].setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
	descriptorWrites[1].setDescriptorCount(1);
	descriptorWrites[1].setPImageInfo(&imageInfo);

	device.updateDescriptorSets(static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
}

void Material::CleanupDescriptorSetLayout()
{
	if (descriptorSetLayout != vk::DescriptorSetLayout{}) {
		device.destroyDescriptorSetLayout(descriptorSetLayout, nullptr);
		descriptorSetLayout = vk::DescriptorSetLayout{};
	}
}


However, I am now getting the following errors. Can you help modify the code to fix them?

allocInfo.setDescriptorPool(descriptorPool)

No suitable conversion from vk::UniqueDescriptorPool to vk::DescriptorPool exists

pipelineLayout = device.createPipelineLayoutUnique(pipelineLayoutInfo)

No operator "=" matches these operands

return pipelineLayout.get()

vk::PipelineLayout has no member "get"