diff --git a/config/Sources.cmake b/config/Sources.cmake index a5b2ddae5e0a194e4ee887da5f37097821e41d0f..4f673e00d1e42e733534480d6085affd651a8c04 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -29,10 +29,14 @@ set(vkcv_sources ${vkcv_source}/vkcv/ImageManager.hpp ${vkcv_source}/vkcv/ImageManager.cpp + + ${vkcv_include}/vkcv/Logger.hpp ${vkcv_include}/vkcv/SwapChain.hpp ${vkcv_source}/vkcv/SwapChain.cpp - + + ${vkcv_include}/vkcv/ShaderStage.hpp + ${vkcv_include}/vkcv/ShaderProgram.hpp ${vkcv_source}/vkcv/ShaderProgram.cpp diff --git a/config/lib/SPIRV_Cross.cmake b/config/lib/SPIRV_Cross.cmake index 751ee883c47e0eab081a13e5805ced6f2daa7e30..2e705d7d5a006e3851d14d22a57fd667c61c79f5 100644 --- a/config/lib/SPIRV_Cross.cmake +++ b/config/lib/SPIRV_Cross.cmake @@ -6,9 +6,20 @@ if (spirv-cross_FOUND) message(${vkcv_config_msg} " SPIRV Cross - " ${SPIRV_CROSS_VERSION}) else() if (EXISTS "${vkcv_lib_path}/SPIRV-Cross") + set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS OFF CACHE INTERNAL "") + set(SPIRV_CROSS_SHARED OFF CACHE INTERNAL "") + set(SPIRV_CROSS_STATIC ON CACHE INTERNAL "") set(SPIRV_CROSS_CLI OFF CACHE INTERNAL "") set(SPIRV_CROSS_ENABLE_TESTS OFF CACHE INTERNAL "") + + set(SPIRV_CROSS_ENABLE_GLSL ON CACHE INTERNAL "") + set(SPIRV_CROSS_ENABLE_HLSL OFF CACHE INTERNAL "") + set(SPIRV_CROSS_ENABLE_MSL OFF CACHE INTERNAL "") + set(SPIRV_CROSS_ENABLE_CPP ON CACHE INTERNAL "") + set(SPIRV_CROSS_ENABLE_REFLECT OFF CACHE INTERNAL "") set(SPIRV_CROSS_ENABLE_C_API OFF CACHE INTERNAL "") + set(SPIRV_CROSS_ENABLE_UTIL OFF CACHE INTERNAL "") + set(SPIRV_CROSS_SKIP_INSTALL ON CACHE INTERNAL "") add_subdirectory(${vkcv_lib}/SPIRV-Cross) diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 8a165adf43561b1204490a12afa00d2a3fabdbf4..4a51b24f5c978daebc5116e20b527252c8063d61 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -157,6 +157,19 @@ namespace vkcv [[nodiscard]] PipelineHandle createGraphicsPipeline(const PipelineConfig &config); + /** + * Creates a basic vulkan compute pipeline using @p shader program and returns it using the @p handle. + * Fixed Functions for pipeline are set with standard values. + * + * @param shader program that hold the compiles compute shader + * @param handle a handle to return the created vulkan handle + * @return True if pipeline creation was successful, False if not + */ + [[nodiscard]] + PipelineHandle createComputePipeline( + const ShaderProgram &config, + const std::vector<vk::DescriptorSetLayout> &descriptorSetLayouts); + /** * Creates a basic vulkan render pass using @p config from the render pass config class and returns it using the @p handle. * Fixed Functions for pipeline are set with standard values. @@ -211,7 +224,7 @@ namespace vkcv */ [[nodiscard]] DescriptorSetHandle createDescriptorSet(const std::vector<DescriptorBinding> &bindings); - void writeResourceDescription(DescriptorSetHandle handle, size_t setIndex, const DescriptorWrites& writes); + void writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites& writes); DescriptorSet getDescriptorSet(const DescriptorSetHandle handle) const; @@ -228,6 +241,13 @@ namespace vkcv const std::vector<DrawcallInfo> &drawcalls, const std::vector<ImageHandle> &renderTargets); + void recordComputeDispatchToCmdStream( + CommandStreamHandle cmdStream, + PipelineHandle computePipeline, + const uint32_t dispatchCount[3], + const std::vector<DescriptorSetUsage> &descriptorSetUsages, + const PushConstantData& pushConstantData); + /** * @brief end recording and present image */ diff --git a/include/vkcv/DescriptorConfig.hpp b/include/vkcv/DescriptorConfig.hpp index 86c2e20eb37633e4519749bef507161133e57425..c6d0dfd1bc60988afb8b6a9326a8d50d8a4ea32e 100644 --- a/include/vkcv/DescriptorConfig.hpp +++ b/include/vkcv/DescriptorConfig.hpp @@ -1,8 +1,10 @@ #pragma once -#include <vkcv/ShaderProgram.hpp> -#include <vkcv/Handles.hpp> + #include <vulkan/vulkan.hpp> +#include "vkcv/Handles.hpp" +#include "vkcv/ShaderStage.hpp" + namespace vkcv { struct DescriptorSet @@ -33,11 +35,13 @@ namespace vkcv struct DescriptorBinding { DescriptorBinding( + uint32_t bindingID, DescriptorType descriptorType, uint32_t descriptorCount, ShaderStage shaderStage ) noexcept; - + + uint32_t bindingID; DescriptorType descriptorType; uint32_t descriptorCount; ShaderStage shaderStage; diff --git a/include/vkcv/Logger.hpp b/include/vkcv/Logger.hpp new file mode 100644 index 0000000000000000000000000000000000000000..251b6b528c45ea509dbfcd0cfb7135b77031f1ac --- /dev/null +++ b/include/vkcv/Logger.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include <iostream> + +namespace vkcv { + + enum class LogLevel { + INFO, + WARNING, + ERROR + }; + + constexpr auto getLogOutput(LogLevel level) { + switch (level) { + case LogLevel::INFO: + return stdout; + default: + return stderr; + } + } + + constexpr const char* getLogName(LogLevel level) { + switch (level) { + case LogLevel::INFO: + return "INFO"; + case LogLevel::WARNING: + return "WARNING"; + case LogLevel::ERROR: + return "ERROR"; + default: + return "UNKNOWN"; + } + } + +#ifndef NDEBUG +#ifndef VKCV_DEBUG_MESSAGE_LEN +#define VKCV_DEBUG_MESSAGE_LEN 1024 +#endif + +#ifdef _MSC_VER +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + +#define vkcv_log(level, ...) { \ + char output_message [ \ + VKCV_DEBUG_MESSAGE_LEN \ + ]; \ + std::snprintf( \ + output_message, \ + VKCV_DEBUG_MESSAGE_LEN, \ + __VA_ARGS__ \ + ); \ + std::fprintf( \ + getLogOutput(level), \ + "[%s]: %s [%s, line %d: %s]\n", \ + vkcv::getLogName(level), \ + output_message, \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__ \ + ); \ +} + +#else +#define vkcv_log(level, ...) {} +#endif + +} diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp index 459125bbd3208ffb40815e1e3fd4c9615ce21724..ce28cccf07e22dda21fd14d0bddd0ba6e9842328 100644 --- a/include/vkcv/ShaderProgram.hpp +++ b/include/vkcv/ShaderProgram.hpp @@ -8,23 +8,16 @@ #include <unordered_map> #include <fstream> #include <iostream> +#include <algorithm> #include <filesystem> #include <vulkan/vulkan.hpp> #include <spirv_cross.hpp> #include "vkcv/VertexLayout.hpp" +#include "vkcv/ShaderStage.hpp" +#include "vkcv/DescriptorConfig.hpp" namespace vkcv { - enum class ShaderStage - { - VERTEX, - TESS_CONTROL, - TESS_EVAL, - GEOMETRY, - FRAGMENT, - COMPUTE - }; - struct Shader { std::vector<char> shaderCode; @@ -60,10 +53,13 @@ namespace vkcv { const VertexLayout &getVertexLayout() const; size_t getPushConstantSize() const; + const std::vector<std::vector<DescriptorBinding>> getReflectedDescriptors() const; + private: std::unordered_map<ShaderStage, Shader> m_Shaders; VertexLayout m_VertexLayout; + std::vector<std::vector<DescriptorBinding>> m_DescriptorSets; size_t m_pushConstantSize = 0; }; } diff --git a/include/vkcv/ShaderStage.hpp b/include/vkcv/ShaderStage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dca395bdba82a2f1cb38bb0a25196cfd3dab8019 --- /dev/null +++ b/include/vkcv/ShaderStage.hpp @@ -0,0 +1,15 @@ +#pragma once + +namespace vkcv { + + enum class ShaderStage + { + VERTEX, + TESS_CONTROL, + TESS_EVAL, + GEOMETRY, + FRAGMENT, + COMPUTE + }; + +} diff --git a/include/vkcv/VertexLayout.hpp b/include/vkcv/VertexLayout.hpp index ee0ad8ef56d5284af2be4c81b7ea2f0d052d5a6f..aae43910a09f221874813733b2ef72d36467a750 100644 --- a/include/vkcv/VertexLayout.hpp +++ b/include/vkcv/VertexLayout.hpp @@ -3,6 +3,7 @@ #include <unordered_map> #include <vector> #include <iostream> +#include <string> namespace vkcv{ @@ -38,10 +39,11 @@ namespace vkcv{ struct VertexInputAttachment{ VertexInputAttachment() = delete; - VertexInputAttachment(uint32_t location, uint32_t binding, VertexFormat format, uint32_t offset) noexcept; + VertexInputAttachment(uint32_t location, uint32_t binding, std::string name, VertexFormat format, uint32_t offset) noexcept; uint32_t location; uint32_t binding; + std::string name; VertexFormat format; uint32_t offset; }; diff --git a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp index e660b442d0b9a0208f95c9d753ef19e926bcac44..f3823cc8f3fe54b53835f356dd14a086515118dd 100644 --- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp +++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp @@ -7,6 +7,8 @@ #define STBI_ONLY_JPEG #include <stb_image.h> +#include <vkcv/Logger.hpp> + namespace vkcv::asset { /** @@ -39,11 +41,12 @@ uint8_t convertTypeToInt(const fx::gltf::Accessor::Type type) { * @param path path to file that is responsible for error */ void print_what (const std::exception& e, const std::string &path) { - fprintf(stderr, "ERROR loading file %s: %s\n", path.c_str(), e.what()); + vkcv_log(LogLevel::ERROR, "Loading file %s: %s", + path.c_str(), e.what()); + try { std::rethrow_if_nested(e); } catch (const std::exception& nested) { - std::cerr << "nested: "; print_what(nested, path); } } @@ -121,7 +124,7 @@ int loadMesh(const std::string &path, Mesh &mesh) { const size_t off = indexBufferView.byteOffset; const void *const ptr = ((char*)indexBuffer.data.data()) + off; if (!memcpy(indexBufferData.data(), ptr, indexBufferView.byteLength)) { - std::cerr << "ERROR copying index buffer data.\n"; + vkcv_log(LogLevel::ERROR, "Copying index buffer data"); return 0; } } @@ -136,7 +139,7 @@ int loadMesh(const std::string &path, Mesh &mesh) { const size_t off = 0; const void *const ptr = ((char*)vertexBuffer.data.data()) + off; if (!memcpy(vertexBufferData.data(), ptr, vertexBuffer.byteLength)) { - std::cerr << "ERROR copying vertex buffer data.\n"; + vkcv_log(LogLevel::ERROR, "Copying vertex buffer data"); return 0; } } @@ -150,9 +153,8 @@ int loadMesh(const std::string &path, Mesh &mesh) { case fx::gltf::Accessor::ComponentType::UnsignedInt: indexType = UINT32; break; default: - std::cerr << "ERROR: Index type not supported: " << - static_cast<uint16_t>(indexAccessor.componentType) << - std::endl; + vkcv_log(LogLevel::ERROR, "Index type (%u) not supported", + static_cast<uint16_t>(indexAccessor.componentType)); return 0; } diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp index a0fb29fafe24a4ae1279161dc8814c0d8f52765f..2494793f3b4aff3dfa412ff9bbe27e4550ca8fe0 100644 --- a/projects/cmd_sync_test/src/main.cpp +++ b/projects/cmd_sync_test/src/main.cpp @@ -102,13 +102,8 @@ int main(int argc, const char** argv) { triangleShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); triangleShaderProgram.reflectShader(vkcv::ShaderStage::VERTEX); triangleShaderProgram.reflectShader(vkcv::ShaderStage::FRAGMENT); - - std::vector<vkcv::DescriptorBinding> descriptorBindings = { - vkcv::DescriptorBinding(vkcv::DescriptorType::IMAGE_SAMPLED, 1, vkcv::ShaderStage::FRAGMENT), - vkcv::DescriptorBinding(vkcv::DescriptorType::SAMPLER, 1, vkcv::ShaderStage::FRAGMENT), - vkcv::DescriptorBinding(vkcv::DescriptorType::UNIFORM_BUFFER, 1, vkcv::ShaderStage::FRAGMENT), - vkcv::DescriptorBinding(vkcv::DescriptorType::IMAGE_SAMPLED, 1, vkcv::ShaderStage::FRAGMENT) , - vkcv::DescriptorBinding(vkcv::DescriptorType::SAMPLER, 1, vkcv::ShaderStage::FRAGMENT) }; + + std::vector<vkcv::DescriptorBinding> descriptorBindings = { triangleShaderProgram.getReflectedDescriptors()[0] }; vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorBindings); const vkcv::PipelineConfig trianglePipelineDefinition( @@ -212,7 +207,7 @@ int main(int argc, const char** argv) { vkcv::SamplerDescriptorWrite(1, sampler), vkcv::SamplerDescriptorWrite(4, shadowSampler) }; setWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(2, lightBuffer.getHandle()) }; - core.writeResourceDescription(descriptorSet, 0, setWrites); + core.writeDescriptorSet(descriptorSet, setWrites); auto start = std::chrono::system_clock::now(); const auto appStartTime = start; diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 95c81ba0f3a44e1fc965e20e808c95b6b8b3f3e1..d585fa9606acb13795d299c1f4b47602c463a61a 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -95,9 +95,8 @@ int main(int argc, const char** argv) { return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); }); - std::vector<vkcv::DescriptorBinding> descriptorBindings = { - vkcv::DescriptorBinding(vkcv::DescriptorType::IMAGE_SAMPLED, 1, vkcv::ShaderStage::FRAGMENT), - vkcv::DescriptorBinding(vkcv::DescriptorType::SAMPLER, 1, vkcv::ShaderStage::FRAGMENT) }; + uint32_t setID = 0; + std::vector<vkcv::DescriptorBinding> descriptorBindings = { triangleShaderProgram.getReflectedDescriptors()[setID] }; vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorBindings); const vkcv::PipelineConfig trianglePipelineDefinition( @@ -133,9 +132,9 @@ int main(int argc, const char** argv) { }; vkcv::DescriptorWrites setWrites; - setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) }; - setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; - core.writeResourceDescription(descriptorSet, 0, setWrites); + setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) }; + setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; + core.writeDescriptorSet(descriptorSet, setWrites); vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle(); diff --git a/projects/first_triangle/shaders/comp.spv b/projects/first_triangle/shaders/comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..b414e36b2bea66dab00746298e536d029091e0fd Binary files /dev/null and b/projects/first_triangle/shaders/comp.spv differ diff --git a/projects/first_triangle/shaders/compile.bat b/projects/first_triangle/shaders/compile.bat index b4521235c40fe5fb163bab874560c2f219b7517f..17743a7c49cdfc6e091c43a42a0adb755a731682 100644 --- a/projects/first_triangle/shaders/compile.bat +++ b/projects/first_triangle/shaders/compile.bat @@ -1,3 +1,4 @@ %VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv %VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv +%VULKAN_SDK%\Bin32\glslc.exe shader.comp -o comp.spv pause \ No newline at end of file diff --git a/projects/first_triangle/shaders/shader.comp b/projects/first_triangle/shaders/shader.comp new file mode 100644 index 0000000000000000000000000000000000000000..fad6cd0815f2f09bf92dcc3171e2e3723f5466df --- /dev/null +++ b/projects/first_triangle/shaders/shader.comp @@ -0,0 +1,25 @@ +#version 440 + +layout(std430, binding = 0) buffer testBuffer +{ + float test1[10]; + float test2[10]; + float test3[10]; +}; + +layout( push_constant ) uniform constants{ + float pushConstant; +}; + +layout(local_size_x = 5) in; + +void main(){ + + if(gl_GlobalInvocationID.x >= 10){ + return; + } + + test1[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x; + test2[gl_GlobalInvocationID.x] = 69; // nice! + test3[gl_GlobalInvocationID.x] = pushConstant; +} \ No newline at end of file diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 2ede653ff98e19159e0155b282cab1b309a13816..ca10434bb9e486649411bcaac54c432744a914bb 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -92,6 +92,7 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } + // Graphics Pipeline vkcv::ShaderProgram triangleShaderProgram{}; triangleShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("shaders/vert.spv")); triangleShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("shaders/frag.spv")); @@ -115,6 +116,30 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } + // Compute Pipeline + vkcv::ShaderProgram computeShaderProgram{}; + computeShaderProgram.addShader(vkcv::ShaderStage::COMPUTE, std::filesystem::path("shaders/comp.spv")); + computeShaderProgram.reflectShader(vkcv::ShaderStage::COMPUTE); + + // take care, assuming shader has exactly one descriptor set + vkcv::DescriptorSetHandle computeDescriptorSet = core.createDescriptorSet(computeShaderProgram.getReflectedDescriptors()[0]); + + vkcv::PipelineHandle computePipeline = core.createComputePipeline( + computeShaderProgram, + { core.getDescriptorSet(computeDescriptorSet).layout }); + + struct ComputeTestBuffer { + float test1[10]; + float test2[10]; + float test3[10]; + }; + + vkcv::Buffer computeTestBuffer = core.createBuffer<ComputeTestBuffer>(vkcv::BufferType::STORAGE, 1); + + vkcv::DescriptorWrites computeDescriptorWrites; + computeDescriptorWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, computeTestBuffer.getHandle()) }; + core.writeDescriptorSet(computeDescriptorSet, computeDescriptorWrites); + /* * BufferHandle triangleVertices = core.createBuffer(vertices); * BufferHandle triangleIndices = core.createBuffer(indices); @@ -164,6 +189,17 @@ int main(int argc, const char** argv) { pushConstantData, { drawcall }, { swapchainInput }); + + const uint32_t dispatchSize[3] = { 2, 1, 1 }; + const float theMeaningOfLife = 42; + + core.recordComputeDispatchToCmdStream( + cmdStream, + computePipeline, + dispatchSize, + { vkcv::DescriptorSetUsage(0, core.getDescriptorSet(computeDescriptorSet).vulkanHandle) }, + vkcv::PushConstantData((void*)&theMeaningOfLife, sizeof(theMeaningOfLife))); + core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); diff --git a/src/vkcv/CommandResources.cpp b/src/vkcv/CommandResources.cpp index 71c990c3c222f2318c2f5744ff6295f667d9e6f8..a31e6967d85bd099fe5cbbc865b0e062212ca16e 100644 --- a/src/vkcv/CommandResources.cpp +++ b/src/vkcv/CommandResources.cpp @@ -1,6 +1,7 @@ #include "vkcv/CommandResources.hpp" #include <iostream> +#include "vkcv/Logger.hpp" namespace vkcv { @@ -62,7 +63,7 @@ namespace vkcv { return queueManager.getPresentQueue(); } else { - std::cerr << "getQueueForSubmit error: unknown queue type" << std::endl; + vkcv_log(LogLevel::ERROR, "Unknown queue type"); return queueManager.getGraphicsQueues().front(); // graphics is the most general queue } } diff --git a/src/vkcv/CommandStreamManager.cpp b/src/vkcv/CommandStreamManager.cpp index 9d0a236a4eaa5a166be77d143370a018b9ea7e73..5a5b359b912d9cef36e0b03379d7f0f6f0951381 100644 --- a/src/vkcv/CommandStreamManager.cpp +++ b/src/vkcv/CommandStreamManager.cpp @@ -1,6 +1,8 @@ #include "vkcv/CommandStreamManager.hpp" #include "vkcv/Core.hpp" +#include "vkcv/Logger.hpp" + namespace vkcv { CommandStreamManager::CommandStreamManager() noexcept : m_core(nullptr){} @@ -14,7 +16,7 @@ namespace vkcv { void CommandStreamManager::init(Core* core) { if (!core) { - std::cerr << "Error: CommandStreamManager::init requires valid core pointer" << std::endl; + vkcv_log(LogLevel::ERROR, "Requires valid core pointer"); } m_core = core; } @@ -57,7 +59,7 @@ namespace vkcv { const size_t id = handle.getId(); if (id >= m_commandStreams.size()) { - std::cerr << "Error: CommandStreamManager::recordCommandsToStream requires valid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Requires valid handle"); return; } @@ -71,7 +73,7 @@ namespace vkcv { const size_t id = handle.getId(); if (id >= m_commandStreams.size()) { - std::cerr << "Error: CommandStreamManager::addFinishCallbackToStream requires valid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Requires valid handle"); return; } @@ -86,7 +88,7 @@ namespace vkcv { const size_t id = handle.getId(); if (id >= m_commandStreams.size()) { - std::cerr << "Error: CommandStreamManager::submitCommandStreamSynchronous requires valid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Requires valid handle"); return; } CommandStream& stream = m_commandStreams[id]; @@ -111,7 +113,7 @@ namespace vkcv { vk::CommandBuffer CommandStreamManager::getStreamCommandBuffer(const CommandStreamHandle handle) { const size_t id = handle.getId(); if (id >= m_commandStreams.size()) { - std::cerr << "Error: CommandStreamManager::submitCommandStreamSynchronous requires valid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Requires valid handle"); return nullptr; } return m_commandStreams[id].cmdBuffer; diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 9ed83d2a224119bd20fcfc81c5720b425de06bb6..44e7111e1f4941ef2f0f8114ac788d7db4a13b5a 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -16,6 +16,8 @@ #include "ImageLayoutTransitions.hpp" #include "vkcv/CommandStreamManager.hpp" +#include "vkcv/Logger.hpp" + namespace vkcv { @@ -101,6 +103,13 @@ namespace vkcv return m_PipelineManager->createPipeline(config, *m_PassManager); } + PipelineHandle Core::createComputePipeline( + const ShaderProgram &shaderProgram, + const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts) + { + return m_PipelineManager->createComputePipeline(shaderProgram, descriptorSetLayouts); + } + PassHandle Core::createPass(const PassConfig &config) { @@ -125,7 +134,7 @@ namespace vkcv } if (result != vk::Result::eSuccess) { - std::cerr << vk::to_string(result) << std::endl; + vkcv_log(LogLevel::ERROR, "%s", vk::to_string(result).c_str()); return Result::ERROR; } @@ -149,7 +158,7 @@ namespace vkcv } if (acquireSwapchainImage() != Result::SUCCESS) { - std::cerr << "Acquire failed!" << std::endl; + vkcv_log(LogLevel::ERROR, "Acquire failed"); m_currentSwapchainImageIndex = std::numeric_limits<uint32_t>::max(); } @@ -234,7 +243,7 @@ namespace vkcv 1); if(m_Context.m_Device.createFramebuffer(&createInfo, nullptr, &framebuffer) != vk::Result::eSuccess) { - std::cout << "FAILED TO CREATE TEMPORARY FRAMEBUFFER!" << std::endl; + vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer"); return; } @@ -298,6 +307,40 @@ namespace vkcv recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction); } + void Core::recordComputeDispatchToCmdStream( + CommandStreamHandle cmdStreamHandle, + PipelineHandle computePipeline, + const uint32_t dispatchCount[3], + const std::vector<DescriptorSetUsage>& descriptorSetUsages, + const PushConstantData& pushConstantData) { + + auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { + + const auto pipelineLayout = m_PipelineManager->getVkPipelineLayout(computePipeline); + + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, m_PipelineManager->getVkPipeline(computePipeline)); + for (const auto& usage : descriptorSetUsages) { + cmdBuffer.bindDescriptorSets( + vk::PipelineBindPoint::eCompute, + pipelineLayout, + usage.setLocation, + { usage.vulkanHandle }, + {}); + } + if (pushConstantData.sizePerDrawcall > 0) { + cmdBuffer.pushConstants( + pipelineLayout, + vk::ShaderStageFlagBits::eCompute, + 0, + pushConstantData.sizePerDrawcall, + pushConstantData.data); + } + cmdBuffer.dispatch(dispatchCount[0], dispatchCount[1], dispatchCount[2]); + }; + + recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr); + } + void Core::endFrame() { if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { return; @@ -325,7 +368,7 @@ namespace vkcv } if (result != vk::Result::eSuccess) { - std::cout << "Error: swapchain present failed... " << vk::to_string(result) << std::endl; + vkcv_log(LogLevel::ERROR, "Swapchain present failed (%s)", vk::to_string(result).c_str()); } } @@ -402,10 +445,9 @@ namespace vkcv return m_DescriptorManager->createDescriptorSet(bindings); } - void Core::writeResourceDescription(DescriptorSetHandle handle, size_t setIndex, const DescriptorWrites &writes) { - m_DescriptorManager->writeResourceDescription( - handle, - setIndex, + void Core::writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites &writes) { + m_DescriptorManager->writeDescriptorSet( + handle, writes, *m_ImageManager, *m_BufferManager, diff --git a/src/vkcv/DescriptorConfig.cpp b/src/vkcv/DescriptorConfig.cpp index be6cfc9b40baad6636e6bc6a2b6e803aacd7ddc0..54e879ac7e6ec7825a4c003899e3c264454c547f 100644 --- a/src/vkcv/DescriptorConfig.cpp +++ b/src/vkcv/DescriptorConfig.cpp @@ -2,10 +2,12 @@ namespace vkcv { DescriptorBinding::DescriptorBinding( + uint32_t bindingID, DescriptorType descriptorType, uint32_t descriptorCount, ShaderStage shaderStage) noexcept : + bindingID(bindingID), descriptorType(descriptorType), descriptorCount(descriptorCount), shaderStage(shaderStage) {} diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp index a2efecbe7055122d28a864b7c722a5998be460e4..f591daf90b47b57a758b2b24c7fa87b5c33e3c46 100644 --- a/src/vkcv/DescriptorManager.cpp +++ b/src/vkcv/DescriptorManager.cpp @@ -1,5 +1,7 @@ #include "DescriptorManager.hpp" +#include "vkcv/Logger.hpp" + namespace vkcv { DescriptorManager::DescriptorManager(vk::Device device) noexcept: @@ -40,7 +42,7 @@ namespace vkcv //create each set's binding for (uint32_t i = 0; i < bindings.size(); i++) { vk::DescriptorSetLayoutBinding descriptorSetLayoutBinding( - i, + bindings[i].bindingID, convertDescriptorTypeFlag(bindings[i].descriptorType), bindings[i].descriptorCount, convertShaderStageFlag(bindings[i].shaderStage)); @@ -53,7 +55,7 @@ namespace vkcv vk::DescriptorSetLayoutCreateInfo layoutInfo({}, setBindings); if(m_Device.createDescriptorSetLayout(&layoutInfo, nullptr, &set.layout) != vk::Result::eSuccess) { - std::cout << "FAILED TO CREATE DESCRIPTOR SET LAYOUT" << std::endl; + vkcv_log(LogLevel::ERROR, "Failed to create descriptor set layout"); return DescriptorSetHandle(); }; @@ -69,10 +71,10 @@ namespace vkcv result = m_Device.allocateDescriptorSets(&allocInfo, &set.vulkanHandle); } if (result != vk::Result::eSuccess) { - std::cout << "FAILED TO ALLOCATE DESCRIPTOR SET" << std::endl; - std::cout << vk::to_string(result) << std::endl; + vkcv_log(LogLevel::ERROR, "Failed to create descriptor set (%s)", + vk::to_string(result).c_str()); + m_Device.destroy(set.layout); - return DescriptorSetHandle(); } }; @@ -90,9 +92,8 @@ namespace vkcv vk::DescriptorType type; }; - void DescriptorManager::writeResourceDescription( + void DescriptorManager::writeDescriptorSet( const DescriptorSetHandle &handle, - size_t setIndex, const DescriptorWrites &writes, const ImageManager &imageManager, const BufferManager &bufferManager, @@ -239,7 +240,7 @@ namespace vkcv case DescriptorType::IMAGE_STORAGE: return vk::DescriptorType::eStorageImage; default: - std::cerr << "Error: DescriptorManager::convertDescriptorTypeFlag, unknown DescriptorType" << std::endl; + vkcv_log(LogLevel::ERROR, "Unknown DescriptorType"); return vk::DescriptorType::eUniformBuffer; } } @@ -266,7 +267,7 @@ namespace vkcv void DescriptorManager::destroyDescriptorSetById(uint64_t id) { if (id >= m_DescriptorSets.size()) { - std::cerr << "Error: DescriptorManager::destroyResourceDescriptionById invalid id" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid id"); return; } @@ -282,7 +283,7 @@ namespace vkcv vk::DescriptorPool pool; if (m_Device.createDescriptorPool(&m_PoolInfo, nullptr, &pool) != vk::Result::eSuccess) { - std::cout << "FAILED TO ALLOCATE DESCRIPTOR POOL." << std::endl; + vkcv_log(LogLevel::WARNING, "Failed to allocate descriptor pool"); pool = nullptr; }; m_Pools.push_back(pool); diff --git a/src/vkcv/DescriptorManager.hpp b/src/vkcv/DescriptorManager.hpp index d8607b9312b25e71c7eb4af009efd92b834b40ec..d18be64f3b069af68cecce68f6fa623c81f8dfa4 100644 --- a/src/vkcv/DescriptorManager.hpp +++ b/src/vkcv/DescriptorManager.hpp @@ -23,9 +23,8 @@ namespace vkcv DescriptorSetHandle createDescriptorSet(const std::vector<DescriptorBinding> &descriptorBindings); - void writeResourceDescription( + void writeDescriptorSet( const DescriptorSetHandle &handle, - size_t setIndex, const DescriptorWrites &writes, const ImageManager &imageManager, const BufferManager &bufferManager, diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index cdfd32b009a8007b606c86bf087b3f921b2bb89f..1e3d19d02d7e86546d142bb64440364407e81824 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -6,6 +6,7 @@ #include "ImageManager.hpp" #include "vkcv/Core.hpp" #include "ImageLayoutTransitions.hpp" +#include "vkcv/Logger.hpp" #include <algorithm> @@ -206,7 +207,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::getVulkanImage invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return nullptr; } @@ -219,7 +220,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::getVulkanDeviceMemory invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return nullptr; } @@ -232,7 +233,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::getVulkanImageView invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return nullptr; } @@ -245,7 +246,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::switchImageLayout invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return; } @@ -280,7 +281,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::switchImageLayout invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return; } @@ -295,7 +296,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::fillImage invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return; } @@ -369,7 +370,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::getImageWidth invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return 0; } @@ -382,7 +383,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::getImageHeight invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return 0; } @@ -395,7 +396,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::getImageDepth invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return 0; } @@ -407,7 +408,7 @@ namespace vkcv { void ImageManager::destroyImageById(uint64_t id) { if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::destroyImageById invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return; } @@ -436,7 +437,7 @@ namespace vkcv { const uint64_t id = handle.getId(); if (id >= m_images.size()) { - std::cerr << "Error: ImageManager::destroyImageById invalid handle" << std::endl; + vkcv_log(LogLevel::ERROR, "Invalid handle"); return vk::Format::eUndefined; } diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp index 28a64a243b9a7a8fc9372409ef3783901219c868..24ac7970d739d46ab7cecca7bb783bb0037c43cb 100644 --- a/src/vkcv/PipelineManager.cpp +++ b/src/vkcv/PipelineManager.cpp @@ -1,5 +1,6 @@ #include "PipelineManager.hpp" #include "vkcv/Image.hpp" +#include "vkcv/Logger.hpp" namespace vkcv { @@ -20,15 +21,25 @@ namespace vkcv // currently assuming default 32 bit formats, no lower precision or normalized variants supported vk::Format vertexFormatToVulkanFormat(const VertexFormat format) { switch (format) { - case VertexFormat::FLOAT: return vk::Format::eR32Sfloat; - case VertexFormat::FLOAT2: return vk::Format::eR32G32Sfloat; - case VertexFormat::FLOAT3: return vk::Format::eR32G32B32Sfloat; - case VertexFormat::FLOAT4: return vk::Format::eR32G32B32A32Sfloat; - case VertexFormat::INT: return vk::Format::eR32Sint; - case VertexFormat::INT2: return vk::Format::eR32G32Sint; - case VertexFormat::INT3: return vk::Format::eR32G32B32Sint; - case VertexFormat::INT4: return vk::Format::eR32G32B32A32Sint; - default: std::cerr << "Warning: Unknown vertex format" << std::endl; return vk::Format::eUndefined; + case VertexFormat::FLOAT: + return vk::Format::eR32Sfloat; + case VertexFormat::FLOAT2: + return vk::Format::eR32G32Sfloat; + case VertexFormat::FLOAT3: + return vk::Format::eR32G32B32Sfloat; + case VertexFormat::FLOAT4: + return vk::Format::eR32G32B32A32Sfloat; + case VertexFormat::INT: + return vk::Format::eR32Sint; + case VertexFormat::INT2: + return vk::Format::eR32G32Sint; + case VertexFormat::INT3: + return vk::Format::eR32G32B32Sint; + case VertexFormat::INT4: + return vk::Format::eR32G32B32A32Sint; + default: + vkcv_log(LogLevel::WARNING, "Unknown vertex format"); + return vk::Format::eUndefined; } } @@ -40,7 +51,7 @@ namespace vkcv const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT); if (!(existsVertexShader && existsFragmentShader)) { - std::cout << "Core::createGraphicsPipeline requires vertex and fragment shader code" << std::endl; + vkcv_log(LogLevel::ERROR, "Requires vertex and fragment shader code"); return PipelineHandle(); } @@ -182,6 +193,7 @@ namespace vkcv {}, (config.m_DescriptorLayouts), (pushConstantRange)); + vk::PipelineLayout vkPipelineLayout{}; if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess) { @@ -314,4 +326,65 @@ namespace vkcv return m_Configs.at(id); } + PipelineHandle PipelineManager::createComputePipeline( + const ShaderProgram &shaderProgram, + const std::vector<vk::DescriptorSetLayout> &descriptorSetLayouts) { + + // Temporally handing over the Shader Program instead of a pipeline config + vk::ShaderModule computeModule{}; + if (createShaderModule(computeModule, shaderProgram, ShaderStage::COMPUTE) != vk::Result::eSuccess) + return PipelineHandle(); + + vk::PipelineShaderStageCreateInfo pipelineComputeShaderStageInfo( + {}, + vk::ShaderStageFlagBits::eCompute, + computeModule, + "main", + nullptr + ); + + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo({}, descriptorSetLayouts); + + const size_t pushConstantSize = shaderProgram.getPushConstantSize(); + vk::PushConstantRange pushConstantRange(vk::ShaderStageFlagBits::eCompute, 0, pushConstantSize); + if (pushConstantSize > 0) { + pipelineLayoutCreateInfo.setPushConstantRangeCount(1); + pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstantRange); + } + + vk::PipelineLayout vkPipelineLayout{}; + if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess) + { + m_Device.destroy(computeModule); + return PipelineHandle(); + } + + vk::ComputePipelineCreateInfo computePipelineCreateInfo{}; + computePipelineCreateInfo.stage = pipelineComputeShaderStageInfo; + computePipelineCreateInfo.layout = vkPipelineLayout; + + vk::Pipeline vkPipeline; + if (m_Device.createComputePipelines(nullptr, 1, &computePipelineCreateInfo, nullptr, &vkPipeline)!= vk::Result::eSuccess) + { + m_Device.destroy(computeModule); + return PipelineHandle(); + } + + m_Device.destroy(computeModule); + + const uint64_t id = m_Pipelines.size(); + m_Pipelines.push_back({ vkPipeline, vkPipelineLayout }); + + return PipelineHandle(id, [&](uint64_t id) { destroyPipelineById(id); }); + } + + // There is an issue for refactoring the Pipeline Manager. + // While including Compute Pipeline Creation, some private helper functions where introduced: + + vk::Result PipelineManager::createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, const ShaderStage stage) + { + std::vector<char> code = shaderProgram.getShader(stage).shaderCode; + vk::ShaderModuleCreateInfo moduleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data())); + return m_Device.createShaderModule(&moduleInfo, nullptr, &module); + } } \ No newline at end of file diff --git a/src/vkcv/PipelineManager.hpp b/src/vkcv/PipelineManager.hpp index e243151f7248c07fa0287bb2eaf698e5080f7f61..634f5f4e6464532306e35fd10d9a1623df6ace16 100644 --- a/src/vkcv/PipelineManager.hpp +++ b/src/vkcv/PipelineManager.hpp @@ -21,7 +21,9 @@ namespace vkcv std::vector<PipelineConfig> m_Configs; void destroyPipelineById(uint64_t id); - + + vk::Result createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, ShaderStage stage); + public: PipelineManager() = delete; // no default ctor explicit PipelineManager(vk::Device device) noexcept; // ctor @@ -35,6 +37,10 @@ namespace vkcv PipelineHandle createPipeline(const PipelineConfig &config, PassManager& passManager); + PipelineHandle createComputePipeline( + const ShaderProgram& shaderProgram, + const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts); + [[nodiscard]] vk::Pipeline getVkPipeline(const PipelineHandle &handle) const; diff --git a/src/vkcv/QueueManager.cpp b/src/vkcv/QueueManager.cpp index e4d1a2d3a3302fc435c4c278322c08f51f19be6b..df6c74cccf6c4652adc6a4c78802f282ea6ae293 100644 --- a/src/vkcv/QueueManager.cpp +++ b/src/vkcv/QueueManager.cpp @@ -4,7 +4,7 @@ #include <iostream> #include "vkcv/QueueManager.hpp" - +#include "vkcv/Logger.hpp" namespace vkcv { @@ -95,7 +95,8 @@ namespace vkcv { found = true; } } - std::cerr << "Warning: not enough \"" << vk::to_string(qFlag) << "\"-Queues." << std::endl; + + vkcv_log(LogLevel::WARNING, "Not enough %s queues", vk::to_string(qFlag).c_str()); } break; case vk::QueueFlagBits::eCompute: @@ -116,7 +117,8 @@ namespace vkcv { found = true; } } - std::cerr << "Warning: not enough \"" << vk::to_string(qFlag) << "\"-Queues." << std::endl; + + vkcv_log(LogLevel::WARNING, "Not enough %s queues", vk::to_string(qFlag).c_str()); } break; case vk::QueueFlagBits::eTransfer: @@ -137,7 +139,8 @@ namespace vkcv { found = true; } } - std::cerr << "Warning: not enough \"" << vk::to_string(qFlag) << "\"-Queues." << std::endl; + + vkcv_log(LogLevel::WARNING, "Not enough %s queues", vk::to_string(qFlag).c_str()); } break; default: diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp index 3eea7ed21d99af2768d48e62af47cbdef94c7ef1..7c54c301d1301127273303128b0c10a9c2c53942 100644 --- a/src/vkcv/ShaderProgram.cpp +++ b/src/vkcv/ShaderProgram.cpp @@ -5,7 +5,7 @@ */ #include "vkcv/ShaderProgram.hpp" -#include <algorithm> +#include "vkcv/Logger.hpp" namespace vkcv { /** @@ -18,7 +18,7 @@ namespace vkcv { { std::ifstream file(shaderPath.string(), std::ios::ate | std::ios::binary); if (!file.is_open()) { - std::cout << "The file could not be opened." << std::endl; + vkcv_log(LogLevel::ERROR, "The file could not be opened"); return std::vector<char>{}; } size_t fileSize = (size_t)file.tellg(); @@ -61,25 +61,28 @@ namespace vkcv { default: break; } - std::cout << "Shader Program Reflection: unknown Vertex Format" << std::endl; + + vkcv_log(LogLevel::WARNING, "Unknown vertex format"); return VertexFormat::FLOAT; } ShaderProgram::ShaderProgram() noexcept : m_Shaders{}, - m_VertexLayout{} + m_VertexLayout{}, + m_DescriptorSets{} {} bool ShaderProgram::addShader(ShaderStage shaderStage, const std::filesystem::path &shaderPath) { - if(m_Shaders.find(shaderStage) != m_Shaders.end()) - std::cout << "Found existing shader stage. Overwriting." << std::endl; + if(m_Shaders.find(shaderStage) != m_Shaders.end()) { + vkcv_log(LogLevel::WARNING, "Overwriting existing shader stage"); + } const std::vector<char> shaderCode = readShaderCode(shaderPath); - if (shaderCode.empty()) - return false; - else - { + + if (shaderCode.empty()) { + return false; + } else { Shader shader{shaderCode, shaderStage}; m_Shaders.insert(std::make_pair(shaderStage, shader)); return true; @@ -111,6 +114,7 @@ namespace vkcv { spirv_cross::Compiler comp(move(shaderCode)); spirv_cross::ShaderResources resources = comp.get_shader_resources(); + //reflect vertex input if (shaderStage == ShaderStage::VERTEX) { std::vector<VertexInputAttachment> inputVec; uint32_t offset = 0; @@ -118,17 +122,77 @@ namespace vkcv { for (uint32_t i = 0; i < resources.stage_inputs.size(); i++) { auto& u = resources.stage_inputs[i]; const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id); - VertexInputAttachment input = VertexInputAttachment(comp.get_decoration(u.id, spv::DecorationLocation), 0, + u.name, convertFormat(base_type.basetype, base_type.vecsize), offset); inputVec.push_back(input); offset += base_type.vecsize * base_type.width / 8; } - m_VertexLayout = VertexLayout(inputVec); } + + //reflect descriptor sets (uniform buffer, storage buffer, sampler, sampled image, storage image) + std::vector<std::pair<uint32_t, DescriptorBinding>> bindings; + int32_t maxSetID = -1; + for (uint32_t i = 0; i < resources.uniform_buffers.size(); i++) { + auto& u = resources.uniform_buffers[i]; + const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id); + std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet), + DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::UNIFORM_BUFFER, base_type.vecsize, shaderStage)); + bindings.push_back(descriptor); + if (comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID) maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet); + } + + for (uint32_t i = 0; i < resources.storage_buffers.size(); i++) { + auto& u = resources.storage_buffers[i]; + const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id); + std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet), + DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::STORAGE_BUFFER, base_type.vecsize, shaderStage)); + bindings.push_back(descriptor); + if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID) + maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet); + } + + for (uint32_t i = 0; i < resources.separate_samplers.size(); i++) { + auto& u = resources.separate_samplers[i]; + const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id); + std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet), + DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::SAMPLER, base_type.vecsize, shaderStage)); + bindings.push_back(descriptor); + if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID) + maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet); + } + + for (uint32_t i = 0; i < resources.separate_images.size(); i++) { + auto& u = resources.separate_images[i]; + const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id); + std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet), + DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::IMAGE_SAMPLED, base_type.vecsize, shaderStage)); + bindings.push_back(descriptor); + if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID) + maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet); + + } + + for (uint32_t i = 0; i < resources.storage_images.size(); i++) { + auto& u = resources.storage_images[i]; + const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id); + std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet), + DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::IMAGE_STORAGE, base_type.vecsize, shaderStage)); + bindings.push_back(descriptor); + if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID) + maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet); + } + if (maxSetID != -1) { + if((int32_t)m_DescriptorSets.size() <= maxSetID) m_DescriptorSets.resize(maxSetID + 1); + for (const auto &binding : bindings) { + m_DescriptorSets[binding.first].push_back(binding.second); + } + } + + //reflect push constants for (const auto &pushConstantBuffer : resources.push_constant_buffers) { for (const auto &range : comp.get_active_buffer_ranges(pushConstantBuffer.id)) { const size_t size = range.range + range.offset; @@ -141,6 +205,9 @@ namespace vkcv { return m_VertexLayout; } + const std::vector<std::vector<DescriptorBinding>> ShaderProgram::getReflectedDescriptors() const { + return m_DescriptorSets; + } size_t ShaderProgram::getPushConstantSize() const { return m_pushConstantSize; } diff --git a/src/vkcv/VertexLayout.cpp b/src/vkcv/VertexLayout.cpp index b06c6743e1e19a5e282af248ab6b590eb97529fd..3c39ad0d39c4b458526ceed54422d320ee6d0e0d 100644 --- a/src/vkcv/VertexLayout.cpp +++ b/src/vkcv/VertexLayout.cpp @@ -3,6 +3,7 @@ // #include "vkcv/VertexLayout.hpp" +#include "vkcv/Logger.hpp" namespace vkcv { uint32_t getFormatSize(VertexFormat format) { @@ -24,15 +25,15 @@ namespace vkcv { case VertexFormat::INT4: return 16; default: - break; + vkcv_log(LogLevel::WARNING, "No format given"); + return 0; } - std::cout << "VertexLayout: No format given" << std::endl; - return 0; } - VertexInputAttachment::VertexInputAttachment(uint32_t location, uint32_t binding, VertexFormat format, uint32_t offset) noexcept: + VertexInputAttachment::VertexInputAttachment(uint32_t location, uint32_t binding, std::string name, VertexFormat format, uint32_t offset) noexcept: location{location}, binding{binding}, + name{name}, format{format}, offset{offset} {}