diff --git a/.idea/sonarlint.xml b/.idea/sonarlint.xml index 29837d2..20dac8f 100644 --- a/.idea/sonarlint.xml +++ b/.idea/sonarlint.xml @@ -3,6 +3,6 @@ \ No newline at end of file diff --git a/src/engine/vk/CMakeLists.txt b/src/engine/vk/CMakeLists.txt index 4650323..59d7f9f 100644 --- a/src/engine/vk/CMakeLists.txt +++ b/src/engine/vk/CMakeLists.txt @@ -53,6 +53,10 @@ add_library( VkImageView.h VkSemaphore.cpp VkSemaphore.h + VkDescriptorPool.cpp + VkDescriptorPool.h + VkDescriptorSetLayout.cpp + VkDescriptorSetLayout.h ) target_link_libraries( VkVixen diff --git a/src/engine/vk/VkCommandBuffer.h b/src/engine/vk/VkCommandBuffer.h index 37d16db..f43dd49 100644 --- a/src/engine/vk/VkCommandBuffer.h +++ b/src/engine/vk/VkCommandBuffer.h @@ -17,16 +17,16 @@ namespace Vixen::Vk { }; private: - ::VkDevice device; + VkDevice device; - ::VkCommandPool commandPool; + VkCommandPool commandPool; ::VkCommandBuffer commandBuffer; VkFence fence; public: - VkCommandBuffer(::VkDevice device, ::VkCommandPool commandPool, ::VkCommandBuffer commandBuffer); + VkCommandBuffer(VkDevice device, VkCommandPool commandPool, ::VkCommandBuffer commandBuffer); VkCommandBuffer(VkCommandBuffer &) = delete; diff --git a/src/engine/vk/VkDescriptorPool.cpp b/src/engine/vk/VkDescriptorPool.cpp new file mode 100644 index 0000000..fef2d66 --- /dev/null +++ b/src/engine/vk/VkDescriptorPool.cpp @@ -0,0 +1,28 @@ +#include "VkDescriptorPool.h" + +namespace Vixen::Vk { + VkDescriptorPool::VkDescriptorPool( + const std::shared_ptr& device, + const std::vector& sizes, + const uint32_t maxSets + ) : device(device), + pool(VK_NULL_HANDLE) { + const VkDescriptorPoolCreateInfo info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .maxSets = maxSets, + .poolSizeCount = static_cast(sizes.size()), + .pPoolSizes = sizes.data() + }; + + checkVulkanResult( + vkCreateDescriptorPool(device->getDevice(), &info, nullptr, &pool), + "Failed to create descriptor pool" + ); + } + + VkDescriptorPool::~VkDescriptorPool() { + vkDestroyDescriptorPool(device->getDevice(), pool, nullptr); + } +} diff --git a/src/engine/vk/VkDescriptorPool.h b/src/engine/vk/VkDescriptorPool.h new file mode 100644 index 0000000..33ead08 --- /dev/null +++ b/src/engine/vk/VkDescriptorPool.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Device.h" + +namespace Vixen::Vk { + class VkDescriptorPool { + std::shared_ptr device; + + ::VkDescriptorPool pool; + + public: + VkDescriptorPool( + const std::shared_ptr& device, + const std::vector& sizes, + uint32_t maxSets + ); + + VkDescriptorPool(const VkDescriptorPool& other) = delete; + + VkDescriptorPool(VkDescriptorPool&& other) noexcept = delete; + + VkDescriptorPool& operator=(VkDescriptorPool other) = delete; + + ~VkDescriptorPool(); + }; +} diff --git a/src/engine/vk/VkDescriptorSetLayout.cpp b/src/engine/vk/VkDescriptorSetLayout.cpp new file mode 100644 index 0000000..03e169f --- /dev/null +++ b/src/engine/vk/VkDescriptorSetLayout.cpp @@ -0,0 +1,5 @@ +#include "VkDescriptorSetLayout.h" + +namespace Vixen::Vk { + +} diff --git a/src/engine/vk/VkDescriptorSetLayout.h b/src/engine/vk/VkDescriptorSetLayout.h new file mode 100644 index 0000000..62e5042 --- /dev/null +++ b/src/engine/vk/VkDescriptorSetLayout.h @@ -0,0 +1,10 @@ +#pragma once + +#include "Device.h" + +namespace Vixen::Vk { + class VkDescriptorSetLayout { + public: + + }; +} diff --git a/src/engine/vk/VkShaderModule.cpp b/src/engine/vk/VkShaderModule.cpp index 6933f75..50b80f1 100644 --- a/src/engine/vk/VkShaderModule.cpp +++ b/src/engine/vk/VkShaderModule.cpp @@ -2,24 +2,24 @@ namespace Vixen::Vk { VkShaderModule::VkShaderModule( - const std::shared_ptr &device, - Stage stage, - const std::vector &binary, - const std::vector &bindings, - const std::vector &inputs, - const std::string &entrypoint + const std::shared_ptr& device, + const Stage stage, + const std::vector& binary, + const std::vector& bindings, + const std::vector& inputs, + const std::string& entrypoint ) : ShaderModule(stage, entrypoint, bindings, inputs), device(device), module(VK_NULL_HANDLE) { - VkShaderModuleCreateInfo info{ - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = binary.size() * sizeof(uint32_t), - .pCode = binary.data() + const VkShaderModuleCreateInfo info{ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = binary.size() * sizeof(uint32_t), + .pCode = binary.data() }; checkVulkanResult( - vkCreateShaderModule(device->getDevice(), &info, nullptr, &module), - "Failed to create shader module" + vkCreateShaderModule(device->getDevice(), &info, nullptr, &module), + "Failed to create shader module" ); } @@ -27,15 +27,37 @@ namespace Vixen::Vk { vkDestroyShaderModule(device->getDevice(), module, nullptr); } - VkPipelineShaderStageCreateInfo VkShaderModule::createInfo() { + VkPipelineShaderStageCreateInfo VkShaderModule::createInfo() const { return { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .pNext = VK_NULL_HANDLE, - .flags = 0, - .stage = getVulkanShaderStage(getStage()), - .module = module, - .pName = getEntrypoint().c_str(), - .pSpecializationInfo = VK_NULL_HANDLE + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = VK_NULL_HANDLE, + .flags = 0, + .stage = getVulkanShaderStage(getStage()), + .module = module, + .pName = getEntrypoint().c_str(), + .pSpecializationInfo = VK_NULL_HANDLE }; } + + std::vector VkShaderModule::createBindings() const { + const auto& bindings = getBindings(); + + std::vector b{bindings.size()}; + for (const auto& [binding, stride, rate] : bindings) { + const VkShaderStageFlags& stage = getVulkanShaderStage(getStage()); + + b.push_back( + VkDescriptorSetLayoutBinding{ + .binding = binding, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + // TODO: This count value is used for array bindings + .descriptorCount = 1, + .stageFlags = stage, + .pImmutableSamplers = nullptr + } + ); + } + + return b; + } } diff --git a/src/engine/vk/VkShaderModule.h b/src/engine/vk/VkShaderModule.h index 5f97e21..60c2d8d 100644 --- a/src/engine/vk/VkShaderModule.h +++ b/src/engine/vk/VkShaderModule.h @@ -28,28 +28,29 @@ namespace Vixen::Vk { public: VkShaderModule( - const std::shared_ptr &device, - Stage stage, - const std::vector &binary, - const std::vector &bindings, - const std::vector &inputs, - const std::string &entrypoint = "main" + const std::shared_ptr& device, + Stage stage, + const std::vector& binary, + const std::vector& bindings, + const std::vector& inputs, + const std::string& entrypoint = "main" ); - VkShaderModule(const VkShaderModule &) = delete; + VkShaderModule(const VkShaderModule&) = delete; - VkShaderModule &operator=(const VkShaderModule &) = delete; + VkShaderModule& operator=(const VkShaderModule&) = delete; ~VkShaderModule(); - VkPipelineShaderStageCreateInfo createInfo(); + [[nodiscard]] VkPipelineShaderStageCreateInfo createInfo() const; + + [[nodiscard]] std::vector createBindings() const; class Builder { // TODO: This builder has slightly confusing API, you can compile before setting the stage meaning its possible to mistakenly have the wrong stage set at compile time - private: Stage stage; - std::vector binary; + std::vector binary{}; std::string entrypoint = "main"; @@ -59,129 +60,46 @@ namespace Vixen::Vk { std::vector uniformBuffers{}; - static uint32_t getTypeSize(const glslang::TType *type) { - uint32_t size; - - switch (type->getBasicType()) { - case glslang::EbtVoid: - size = 0; - break; - case glslang::EbtFloat: - size = sizeof(float); - break; - case glslang::EbtDouble: - size = sizeof(double); - break; - case glslang::EbtFloat16: - size = sizeof(long); - break; - case glslang::EbtInt8: - size = sizeof(int8_t); - break; - case glslang::EbtUint8: - size = sizeof(uint8_t); - break; - case glslang::EbtInt16: - size = sizeof(int16_t); - break; - case glslang::EbtUint16: - size = sizeof(uint16_t); - break; - case glslang::EbtInt: - size = sizeof(int32_t); - break; - case glslang::EbtUint: - size = sizeof(uint32_t); - break; - case glslang::EbtInt64: - size = sizeof(int64_t); - break; - case glslang::EbtUint64: - size = sizeof(uint64_t); - break; - case glslang::EbtBool: - size = sizeof(bool); - break; - case glslang::EbtAtomicUint: - // TODO - size = 0; - break; - case glslang::EbtSampler: - size = 0; - break; - case glslang::EbtStruct: - size = 0; - break; - case glslang::EbtBlock: - size = 0; - break; - case glslang::EbtAccStruct: - size = 0; - break; - case glslang::EbtReference: - size = 0; - break; - case glslang::EbtRayQuery: - size = 0; - break; - case glslang::EbtSpirvType: - size = 0; - break; - case glslang::EbtString: - size = 0; - break; - case glslang::EbtNumTypes: - size = 0; - break; - default: - size = 0; - break; - } - - if (type->isVector()) - size *= type->getVectorSize(); - - return size; - } - public: - Builder &setStage(Stage s) { + explicit Builder(const Stage stage) : stage(stage) {} + + Builder& setStage(const Stage s) { stage = s; return *this; } - Builder &setBinary(const std::vector &data) { + Builder& setBinary(const std::vector& data) { binary = data; return *this; } - Builder &setEntrypoint(const std::string &entry) { + Builder& setEntrypoint(const std::string& entry) { entrypoint = entry; return *this; } - Builder &addBinding(Binding binding) { + Builder& addBinding(const Binding& binding) { bindings.push_back(binding); return *this; } - Builder &addInput(const IO &input) { + Builder& addInput(const IO& input) { inputs.push_back(input); return *this; } - std::shared_ptr compile(const std::shared_ptr &d, const std::vector &source) { + std::shared_ptr compile(const std::shared_ptr& d, const std::vector& source) { EShLanguage s; switch (stage) { - case Stage::VERTEX: - s = EShLanguage::EShLangVertex; - break; - case Stage::FRAGMENT: - s = EShLanguage::EShLangFragment; - break; - default: - spdlog::error("Unsupported stage for shader module"); - throw std::runtime_error("Unsupported stage for shader module"); + case Stage::VERTEX: + s = EShLangVertex; + break; + case Stage::FRAGMENT: + s = EShLangFragment; + break; + default: + spdlog::error("Unsupported stage for shader module"); + throw std::runtime_error("Unsupported stage for shader module"); } spdlog::trace("Passed in shader source\n{}", source.data()); @@ -200,7 +118,7 @@ namespace Vixen::Vk { shader.setEntryPoint(entrypoint.c_str()); shader.setSourceEntryPoint(entrypoint.c_str()); - auto messages = (EShMessages) (EShMsgSpvRules | EShMsgVulkanRules); + auto messages = static_cast(EShMsgSpvRules | EShMsgVulkanRules); // TODO: Add actual includer glslang::TShader::ForbidIncluder includer; @@ -214,23 +132,23 @@ namespace Vixen::Vk { glslang::SpvOptions options{ #ifdef DEBUG - .generateDebugInfo = true, - .stripDebugInfo = false, - .disableOptimizer = true, - .optimizeSize = false, - .disassemble = true, + .generateDebugInfo = true, + .stripDebugInfo = false, + .disableOptimizer = true, + .optimizeSize = false, + .disassemble = true, #else - .generateDebugInfo = false, - .stripDebugInfo = true, - .disableOptimizer = false, - .optimizeSize = true, - .disassemble = false, + .generateDebugInfo = false, + .stripDebugInfo = true, + .disableOptimizer = false, + .optimizeSize = true, + .disassemble = false, #endif - .validate = true, + .validate = true, }; spv::SpvBuildLogger logger; - glslang::GlslangToSpv(*program.getIntermediate(s), binary, &logger, &options); + GlslangToSpv(*program.getIntermediate(s), binary, &logger, &options); #ifdef DEBUG std::stringstream stream; @@ -240,19 +158,19 @@ namespace Vixen::Vk { #endif spirv_cross::CompilerReflection c{binary}; - auto resources = c.get_shader_resources(); - for (const auto &uniformBuffer: resources.uniform_buffers) { - uint32_t binding = c.get_decoration(uniformBuffer.id, spv::DecorationBinding); - uint32_t location = c.get_decoration(uniformBuffer.id, spv::DecorationLocation); + for (auto resources = c.get_shader_resources(); + const auto& [id, type_id, base_type_id, name] : resources.uniform_buffers) { + uint32_t binding = c.get_decoration(id, spv::DecorationBinding); + uint32_t location = c.get_decoration(id, spv::DecorationLocation); uniformBuffers.push_back({ - .binding = binding, - .location = location, - .size = 0, - .offset = 0, - }); + .binding = binding, + .location = location, + .size = 0, + .offset = 0, + }); } if (!logger.getAllMessages().empty()) @@ -265,16 +183,16 @@ namespace Vixen::Vk { return std::make_shared(d, stage, binary, bindings, inputs, entrypoint); } - std::shared_ptr compile(const std::shared_ptr &d, const std::string &source) { + std::shared_ptr compile(const std::shared_ptr& d, const std::string& source) { return compile(d, std::vector(source.begin(), source.end())); } - std::shared_ptr compileFromFile(const std::shared_ptr &d, const std::string &path) { + std::shared_ptr compileFromFile(const std::shared_ptr& d, const std::string& path) { std::ifstream file(path, std::ios::ate); if (!file.is_open()) throw std::runtime_error("Failed to read from file"); - std::streamsize size = file.tellg(); + const std::streamsize size = file.tellg(); std::vector buffer(size); file.seekg(0, std::ios_base::beg); file.read(buffer.data(), size); diff --git a/src/engine/vk/Vulkan.h b/src/engine/vk/Vulkan.h index 0715e91..f4e6527 100644 --- a/src/engine/vk/Vulkan.h +++ b/src/engine/vk/Vulkan.h @@ -16,20 +16,20 @@ namespace Vixen::Vk { template - static inline void checkVulkanResult(VkResult result, const std::string &message) { + static void checkVulkanResult(VkResult result, const std::string &message) { if (result != VK_SUCCESS) error("{} ({})", message, string_VkResult(result)); } - static inline std::string getVersionString(glm::ivec3 version) { + static std::string getVersionString(glm::ivec3 version) { return fmt::format("{}.{}.{}", version.x, version.y, version.z); } - static inline std::string getVersionString(uint32_t version) { + static std::string getVersionString(const uint32_t version) { return fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(version), VK_API_VERSION_MINOR(version), VK_API_VERSION_PATCH(version)); } - static inline VkShaderStageFlagBits getVulkanShaderStage(ShaderModule::Stage stage) { + static VkShaderStageFlagBits getVulkanShaderStage(const ShaderModule::Stage stage) { switch (stage) { case ShaderModule::Stage::VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; diff --git a/src/engine/vk/test/main.cpp b/src/engine/vk/test/main.cpp index 182ed76..a98937e 100644 --- a/src/engine/vk/test/main.cpp +++ b/src/engine/vk/test/main.cpp @@ -9,6 +9,7 @@ #include "VkVixen.h" #include "VkPipeline.h" #include "VkRenderer.h" +#include "VkDescriptorPool.h" struct Vertex { glm::vec3 position; @@ -26,8 +27,7 @@ int main() { auto vixen = Vixen::Vk::VkVixen("Vixen Vulkan Test", {1, 0, 0}); - const auto vertex = Vixen::Vk::VkShaderModule::Builder() - .setStage(Vixen::ShaderModule::Stage::VERTEX) + const auto vertex = Vixen::Vk::VkShaderModule::Builder(Vixen::ShaderModule::Stage::VERTEX) .addBinding({ .binding = 0, .stride = sizeof(Vertex), @@ -44,8 +44,7 @@ int main() { .offset = offsetof(Vertex, color), }) .compileFromFile(vixen.device, "../../src/editor/shaders/triangle.vert"); - const auto fragment = Vixen::Vk::VkShaderModule::Builder() - .setStage(Vixen::ShaderModule::Stage::FRAGMENT) + const auto fragment = Vixen::Vk::VkShaderModule::Builder(Vixen::ShaderModule::Stage::FRAGMENT) .compileFromFile(vixen.device, "../../src/editor/shaders/triangle.frag"); const auto program = Vixen::Vk::VkShaderProgram(vertex, fragment); @@ -93,6 +92,14 @@ int main() { } ); + const std::vector sizes{ + { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1 + } + }; + const auto pool = Vixen::Vk::VkDescriptorPool(vixen.device, sizes, 1); + double old = glfwGetTime(); uint32_t fps = 0; while (!vixen.window.shouldClose()) {