diff --git a/CMakeLists.txt b/CMakeLists.txt index dfafe1cd084d4b324c233d502e301c24a5ee95e1..da150fcbeafec3be555d4bbefdab37dbdedf277f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ add_library(vkcv STATIC ${vkcv_sources}) if(MSVC) #enable multicore compilation on visual studio - target_compile_options(vkcv PRIVATE "/MP" "/openmp") + target_compile_options(vkcv PRIVATE "/MP" "/openmp" "/Zc:offsetof-") #set source groups to create proper filters in visual studio source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${vkcv_sources}) diff --git a/config/Sources.cmake b/config/Sources.cmake index 66068e64cb3bd15cdaeab0c3c35515888223ca5f..3c2e903a2047b689fe7f328244cb280d47ce7011 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -1,6 +1,12 @@ # adding all source files and header files of the framework: set(vkcv_sources + ${vkcv_include}/vkcv/Features.hpp + ${vkcv_source}/vkcv/Features.cpp + + ${vkcv_include}/vkcv/FeatureManager.hpp + ${vkcv_source}/vkcv/FeatureManager.cpp + ${vkcv_include}/vkcv/Context.hpp ${vkcv_source}/vkcv/Context.cpp diff --git a/include/vkcv/Context.hpp b/include/vkcv/Context.hpp index 824713fd1e29cbb8b7e60b22768c0019daaa9938..1160857cb2cdbbb0815390ff1f8405dda0f83796 100644 --- a/include/vkcv/Context.hpp +++ b/include/vkcv/Context.hpp @@ -5,6 +5,7 @@ #include "QueueManager.hpp" #include "DrawcallRecording.hpp" +#include "Features.hpp" namespace vkcv { @@ -32,6 +33,9 @@ namespace vkcv [[nodiscard]] const vk::Device &getDevice() const; + [[nodiscard]] + const FeatureManager& getFeatureManager() const; + [[nodiscard]] const QueueManager& getQueueManager() const; @@ -41,8 +45,8 @@ namespace vkcv static Context create(const char *applicationName, uint32_t applicationVersion, const std::vector<vk::QueueFlagBits>& queueFlags, - const std::vector<const char *>& instanceExtensions, - const std::vector<const char *>& deviceExtensions); + const Features& features, + const std::vector<const char*>& instanceExtensions = {}); private: /** @@ -53,11 +57,12 @@ namespace vkcv * @param device Vulkan-Device */ Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device, - QueueManager&& queueManager, vma::Allocator&& allocator) noexcept; + FeatureManager&& featureManager, QueueManager&& queueManager, vma::Allocator&& allocator) noexcept; vk::Instance m_Instance; vk::PhysicalDevice m_PhysicalDevice; vk::Device m_Device; + FeatureManager m_FeatureManager; QueueManager m_QueueManager; vma::Allocator m_Allocator; diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 33bcc97c8bd6fd98c1d75a300a85731bd1545232..f9d52110bae8b87f2e16b46755372b7877cb48d8 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -7,14 +7,14 @@ #include <memory> #include <vulkan/vulkan.hpp> -#include "vkcv/Context.hpp" -#include "vkcv/Swapchain.hpp" -#include "vkcv/Window.hpp" -#include "vkcv/PassConfig.hpp" -#include "vkcv/Handles.hpp" -#include "vkcv/Buffer.hpp" -#include "vkcv/Image.hpp" -#include "vkcv/PipelineConfig.hpp" +#include "Context.hpp" +#include "Swapchain.hpp" +#include "Window.hpp" +#include "PassConfig.hpp" +#include "Handles.hpp" +#include "Buffer.hpp" +#include "Image.hpp" +#include "PipelineConfig.hpp" #include "CommandResources.hpp" #include "SyncResources.hpp" #include "Result.hpp" @@ -146,8 +146,8 @@ namespace vkcv static Core create(const char *applicationName, uint32_t applicationVersion, const std::vector<vk::QueueFlagBits>& queueFlags = {}, - const std::vector<const char*>& instanceExtensions = {}, - const std::vector<const char*>& deviceExtensions = {}); + const Features& features = {}, + const std::vector<const char *>& instanceExtensions = {}); /** * Creates a basic vulkan graphics pipeline using @p config from the pipeline config class and returns it using the @p handle. @@ -275,16 +275,16 @@ namespace vkcv bool beginFrame(uint32_t& width, uint32_t& height); void recordDrawcallsToCmdStream( - const CommandStreamHandle cmdStreamHandle, - const PassHandle renderpassHandle, + const CommandStreamHandle& cmdStreamHandle, + const PassHandle& renderpassHandle, const PipelineHandle pipelineHandle, const PushConstants &pushConstants, const std::vector<DrawcallInfo> &drawcalls, const std::vector<ImageHandle> &renderTargets); void recordMeshShaderDrawcalls( - const CommandStreamHandle cmdStreamHandle, - const PassHandle renderpassHandle, + const CommandStreamHandle& cmdStreamHandle, + const PassHandle& renderpassHandle, const PipelineHandle pipelineHandle, const PushConstants& pushConstantData, const std::vector<MeshShaderDrawcall>& drawcalls, @@ -296,6 +296,12 @@ namespace vkcv const uint32_t dispatchCount[3], const std::vector<DescriptorSetUsage> &descriptorSetUsages, const PushConstants& pushConstants); + + void recordBeginDebugLabel(const CommandStreamHandle &cmdStream, + const std::string& label, + const std::array<float, 4>& color); + + void recordEndDebugLabel(const CommandStreamHandle &cmdStream); void recordComputeIndirectDispatchToCmdStream( const CommandStreamHandle cmdStream, @@ -346,6 +352,14 @@ namespace vkcv void recordBlitImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst, SamplerFilterType filterType); + + void setDebugLabel(const BufferHandle &handle, const std::string &label); + void setDebugLabel(const PassHandle &handle, const std::string &label); + void setDebugLabel(const PipelineHandle &handle, const std::string &label); + void setDebugLabel(const DescriptorSetHandle &handle, const std::string &label); + void setDebugLabel(const SamplerHandle &handle, const std::string &label); + void setDebugLabel(const ImageHandle &handle, const std::string &label); + void setDebugLabel(const CommandStreamHandle &handle, const std::string &label); }; } diff --git a/include/vkcv/FeatureManager.hpp b/include/vkcv/FeatureManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cf945d7498fec83f0b128294caa3ba267b69a6b3 --- /dev/null +++ b/include/vkcv/FeatureManager.hpp @@ -0,0 +1,150 @@ +#pragma once + +#include "Logger.hpp" + +#include <functional> +#include <unordered_set> +#include <vector> +#include <vulkan/vulkan.hpp> + +namespace vkcv { + + class FeatureManager { + private: + vk::PhysicalDevice& m_physicalDevice; + + std::vector<const char*> m_supportedExtensions; + std::vector<const char*> m_activeExtensions; + + vk::PhysicalDeviceFeatures2 m_featuresBase; + std::vector<vk::BaseOutStructure*> m_featuresExtensions; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceFeatures& features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDevice16BitStorageFeatures& features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDevice8BitStorageFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceBufferDeviceAddressFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceDescriptorIndexingFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceHostQueryResetFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceImagelessFramebufferFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceMultiviewFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceProtectedMemoryFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceSamplerYcbcrConversionFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceScalarBlockLayoutFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceSeparateDepthStencilLayoutsFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceShaderAtomicInt64Features &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceShaderFloat16Int8Features& features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceTimelineSemaphoreFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceUniformBufferStandardLayoutFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceVariablePointersFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceVulkanMemoryModelFeatures &features, bool required) const; + + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceMeshShaderFeaturesNV& features, bool required) const; + + vk::BaseOutStructure* findFeatureStructure(vk::StructureType type) const; + + public: + explicit FeatureManager(vk::PhysicalDevice& physicalDevice); + + FeatureManager(const FeatureManager& other) = delete; + FeatureManager(FeatureManager&& other) noexcept; + + ~FeatureManager(); + + FeatureManager& operator=(const FeatureManager& other) = delete; + FeatureManager& operator=(FeatureManager&& other) noexcept; + + [[nodiscard]] + bool isExtensionSupported(const std::string& extension) const; + + bool useExtension(const std::string& extension, bool required = true); + + [[nodiscard]] + bool isExtensionActive(const std::string& extension) const; + + [[nodiscard]] + const std::vector<const char*>& getActiveExtensions() const; + + bool useFeatures(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction, bool required = true); + + template<typename T> + bool useFeatures(const std::function<void(T&)>& featureFunction, bool required = true) { + T features; + T* features_ptr = reinterpret_cast<T*>(findFeatureStructure(features.sType)); + + if (features_ptr) { + features = *features_ptr; + } + + featureFunction(features); + + if (!checkSupport(features, required)) { + return false; + } + + if (features_ptr) { + *features_ptr = features; + return true; + } + + features_ptr = new T(features); + + if (m_featuresExtensions.empty()) { + m_featuresBase.setPNext(features_ptr); + } else { + m_featuresExtensions.back()->setPNext( + reinterpret_cast<vk::BaseOutStructure*>(features_ptr) + ); + } + + m_featuresExtensions.push_back( + reinterpret_cast<vk::BaseOutStructure*>(features_ptr) + ); + + return true; + } + + [[nodiscard]] + const vk::PhysicalDeviceFeatures2& getFeatures() const; + + }; + +} diff --git a/include/vkcv/Features.hpp b/include/vkcv/Features.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6ef3fa28be912627b4495c66427336dfaa51beff --- /dev/null +++ b/include/vkcv/Features.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include <functional> +#include <vector> +#include <initializer_list> + +#include "FeatureManager.hpp" + +namespace vkcv { + + typedef std::function<bool(FeatureManager&)> Feature; + + class Features { + private: + std::vector<Feature> m_features; + + public: + Features() = default; + + Features(const std::initializer_list<std::string>& list); + + Features(const Features& other) = default; + Features(Features&& other) = default; + + ~Features() = default; + + Features& operator=(const Features& other) = default; + Features& operator=(Features&& other) = default; + + void requireExtension(const std::string& extension); + + void requireExtensionFeature(const std::string& extension, + const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction); + + template<typename T> + void requireExtensionFeature(const std::string& extension, const std::function<void(T&)>& featureFunction) { + m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) { + if (featureManager.useExtension(extension, true)) { + return featureManager.template useFeatures<T>(featureFunction, true); + } else { + return false; + } + }); + } + + void requireFeature(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction); + + template<typename T> + void requireFeature(const std::function<void(T&)>& featureFunction) { + m_features.emplace_back([featureFunction](FeatureManager& featureManager) { + return featureManager.template useFeatures<T>(featureFunction, true); + }); + } + + void tryExtension(const std::string& extension); + + void tryExtensionFeature(const std::string& extension, + const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction); + + template<typename T> + void tryExtensionFeature(const std::string& extension, const std::function<void(T&)>& featureFunction) { + m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) { + if (featureManager.useExtension(extension, false)) { + return featureManager.template useFeatures<T>(featureFunction, false); + } else { + return false; + } + }); + } + + void tryFeature(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction); + + template<typename T> + void tryFeature(const std::function<void(T&)>& featureFunction) { + m_features.emplace_back([featureFunction](FeatureManager& featureManager) { + return featureManager.template useFeatures<T>(featureFunction, false); + }); + } + + [[nodiscard]] + const std::vector<Feature>& getList() const; + + }; + +} diff --git a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp index 571d965a400de7197b6fb46f163c4099a5b353f1..2ca35bdab791ea18a67f33e53ab17fc485cbad02 100644 --- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp +++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp @@ -107,7 +107,7 @@ namespace vkcv::asset { const std::vector<fx::gltf::BufferView> &bufferViews, std::vector<VertexAttribute> &dst) { for (const auto &attrib : src) { - VertexAttribute att; + VertexAttribute att {}; if (attrib.first == "POSITION") { att.type = PrimitiveType::POSITION; @@ -282,7 +282,7 @@ namespace vkcv::asset { * modes, default is repeat, the other modes aren't available. */ static vkcv::asset::Sampler loadSampler(const fx::gltf::Sampler &src) { - Sampler dst; + Sampler dst {}; dst.minLOD = 0; dst.maxLOD = VK_LOD_CLAMP_NONE; @@ -414,13 +414,13 @@ namespace vkcv::asset { } if (posAccessor.bufferView >= sceneObjects.bufferViews.size()) { - vkcv_log(LogLevel::ERROR, "Access to bufferView out of bounds: %lu", + vkcv_log(LogLevel::ERROR, "Access to bufferView out of bounds: %d", posAccessor.bufferView); return ASSET_ERROR; } const fx::gltf::BufferView& vertexBufferView = sceneObjects.bufferViews[posAccessor.bufferView]; if (vertexBufferView.buffer >= sceneObjects.buffers.size()) { - vkcv_log(LogLevel::ERROR, "Access to buffer out of bounds: %lu", + vkcv_log(LogLevel::ERROR, "Access to buffer out of bounds: %d", vertexBufferView.buffer); return ASSET_ERROR; } @@ -571,7 +571,7 @@ namespace vkcv::asset { texture.sampler = -1; } else if (static_cast<size_t>(textureObject.sampler) >= scene.samplers.size()) { - vkcv_log(LogLevel::ERROR, "Sampler of texture '%s' missing (%s) %d", + vkcv_log(LogLevel::ERROR, "Sampler of texture '%s' missing (%s)", textureObject.name.c_str(), path.c_str()); return ASSET_ERROR; } else { diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp index d6fa2a40a494ef57386e52a306e962a460c66dd6..c0065af5928d9ad2e2c9afd1a1ea44c35d94d799 100644 --- a/modules/scene/src/vkcv/scene/Scene.cpp +++ b/modules/scene/src/vkcv/scene/Scene.cpp @@ -116,6 +116,10 @@ namespace vkcv::scene { size_t pushConstantsSizePerDrawcall, const RecordMeshDrawcallFunction &record, const std::vector<ImageHandle> &renderTargets) { + m_core->recordBeginDebugLabel(cmdStream, "vkcv::scene::Scene", { + 0.0f, 1.0f, 0.0f, 1.0f + }); + PushConstants pushConstants (pushConstantsSizePerDrawcall); std::vector<DrawcallInfo> drawcalls; size_t count = 0; @@ -137,6 +141,8 @@ namespace vkcv::scene { drawcalls, renderTargets ); + + m_core->recordEndDebugLabel(cmdStream); } Scene Scene::create(Core& core) { diff --git a/modules/upscaling/src/vkcv/upscaling/BilinearUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/BilinearUpscaling.cpp index 9c36acf5d050e3f4f19223020357b6c32534a2de..54df1829006964b30cc1831dc7115e9d5d222a51 100644 --- a/modules/upscaling/src/vkcv/upscaling/BilinearUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/BilinearUpscaling.cpp @@ -7,7 +7,13 @@ namespace vkcv::upscaling { void BilinearUpscaling::recordUpscaling(const CommandStreamHandle &cmdStream, const ImageHandle &input, const ImageHandle &output) { + m_core.recordBeginDebugLabel(cmdStream, "vkcv::upscaling::BilinearUpscaling", { + 0.0f, 0.0f, 1.0f, 1.0f + }); + m_core.recordBlitImage(cmdStream, input, output, SamplerFilterType::LINEAR); + + m_core.recordEndDebugLabel(cmdStream); } } diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp index 460a6d0b459fe7d1d2a917a62138fea2e5a40908..b11051273ba6f9e56d3a537931f9d33fff657e43 100644 --- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp @@ -177,7 +177,7 @@ namespace vkcv::upscaling { vkcv::shader::GLSLCompiler easuCompiler; vkcv::shader::GLSLCompiler rcasCompiler; - const auto& features = m_core.getContext().getPhysicalDevice().getFeatures2(); + const auto& features = m_core.getContext().getFeatureManager().getFeatures(); const bool float16Support = ( checkFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>( reinterpret_cast<const vk::BaseInStructure*>(&features), @@ -189,7 +189,7 @@ namespace vkcv::upscaling { vk::StructureType::ePhysicalDevice16BitStorageFeaturesKHR, check16Storage ) - ) || (true); // check doesn't work because chain is empty + ); if (!float16Support) { easuCompiler.setDefine("SAMPLE_SLOW_FALLBACK", "1"); @@ -245,6 +245,10 @@ namespace vkcv::upscaling { void FSRUpscaling::recordUpscaling(const CommandStreamHandle& cmdStream, const ImageHandle& input, const ImageHandle& output) { + m_core.recordBeginDebugLabel(cmdStream, "vkcv::upscaling::FSRUpscaling", { + 1.0f, 0.0f, 0.0f, 1.0f + }); + const uint32_t inputWidth = m_core.getImageWidth(input); const uint32_t inputHeight = m_core.getImageHeight(input); @@ -361,6 +365,8 @@ namespace vkcv::upscaling { PushConstants(0) ); } + + m_core.recordEndDebugLabel(cmdStream); } bool FSRUpscaling::isHdrEnabled() const { diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 130b6e6138a03bcc380273438c173d2bf9ca915a..feb2153f5b5274a168fb49bd7087a8b4092dcc47 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -15,8 +15,7 @@ int main(int argc, const char** argv) { applicationName, VK_MAKE_VERSION(0, 0, 1), { vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer }, - {}, - { "VK_KHR_swapchain" } + { VK_KHR_SWAPCHAIN_EXTENSION_NAME } ); vkcv::asset::Scene mesh; diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index 4a485cdeb1293fe394278a7338be129b4e126447..6741a26c9f484d94241aa8ffd368101390d9c5f6 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -28,14 +28,13 @@ int main(int argc, const char** argv) { cameraManager.getCamera(camIndex0).setNearFar(0.1f, 30.0f); cameraManager.getCamera(camIndex1).setNearFar(0.1f, 30.0f); - + vkcv::Core core = vkcv::Core::create( window, applicationName, VK_MAKE_VERSION(0, 0, 1), { vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer }, - {}, - { "VK_KHR_swapchain" } + { VK_KHR_SWAPCHAIN_EXTENSION_NAME } ); vkcv::scene::Scene scene = vkcv::scene::Scene::load(core, std::filesystem::path( diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 713c844a2f7c904a05f49332d88c4fd01d9dc7e2..79bdd67b085338072094b7a8948b0e8a523b33cd 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -15,20 +15,21 @@ int main(int argc, const char** argv) { windowWidth, windowHeight ); - + vkcv::Core core = vkcv::Core::create( window, applicationName, VK_MAKE_VERSION(0, 0, 1), { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, - {}, - { "VK_KHR_swapchain" } + { VK_KHR_SWAPCHAIN_EXTENSION_NAME } ); auto triangleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, vkcv::BufferMemoryType::DEVICE_LOCAL); uint16_t indices[3] = { 0, 1, 2 }; triangleIndexBuffer.fill(&indices[0], sizeof(indices)); + core.setDebugLabel(triangleIndexBuffer.getHandle(), "Triangle Index Buffer"); + // an example attachment for passes that output to the window const vkcv::AttachmentDescription present_color_attachment( vkcv::AttachmentOperation::STORE, @@ -43,6 +44,8 @@ int main(int argc, const char** argv) { std::cout << "Error. Could not create renderpass. Exiting." << std::endl; return EXIT_FAILURE; } + + core.setDebugLabel(trianglePass, "Triangle Pass"); vkcv::ShaderProgram triangleShaderProgram; vkcv::shader::GLSLCompiler compiler; @@ -75,12 +78,15 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } + core.setDebugLabel(trianglePipeline, "Triangle Pipeline"); + auto start = std::chrono::system_clock::now(); const vkcv::Mesh renderMesh({}, triangleIndexBuffer.getVulkanHandle(), 3); vkcv::DrawcallInfo drawcall(renderMesh, {},1); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + core.setDebugLabel(swapchainInput, "Swapchain Image"); vkcv::camera::CameraManager cameraManager(window); uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); @@ -110,6 +116,7 @@ int main(int argc, const char** argv) { pushConstants.appendDrawcall(mvp); auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + core.setDebugLabel(cmdStream, "Render Commands"); core.recordDrawcallsToCmdStream( cmdStream, diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp index 92d548acde9c5a27e69c6daf4d92ca1da9d50a2c..5927970333d63d7e0c3bbbda4b7ccbf321c48a48 100644 --- a/projects/indirect_dispatch/src/App.cpp +++ b/projects/indirect_dispatch/src/App.cpp @@ -18,8 +18,7 @@ App::App() : m_applicationName, VK_MAKE_VERSION(0, 0, 1), { vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer }, - {}, - { "VK_KHR_swapchain" })), + { VK_KHR_SWAPCHAIN_EXTENSION_NAME })), m_cameraManager(m_window){} bool App::initialize() { diff --git a/projects/mesh_shader/.gitignore b/projects/mesh_shader/.gitignore index 54601c357bf3fb97b914a6e657c042a5c6a985d7..fd009a6281f4b2b6716e193d23829907f4bb5f33 100644 --- a/projects/mesh_shader/.gitignore +++ b/projects/mesh_shader/.gitignore @@ -1 +1 @@ -mesh_shader +mesh_shader \ No newline at end of file diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp index 242be45f897fd7a765b748b0f91168a3c3996fea..0f602b8d7a9580480f5b59fba71b3677cf740ea2 100644 --- a/projects/mesh_shader/src/main.cpp +++ b/projects/mesh_shader/src/main.cpp @@ -85,14 +85,21 @@ int main(int argc, const char** argv) { windowWidth, windowHeight ); + + vkcv::Features features; + features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + features.requireExtensionFeature<vk::PhysicalDeviceMeshShaderFeaturesNV>( + VK_NV_MESH_SHADER_EXTENSION_NAME, [](vk::PhysicalDeviceMeshShaderFeaturesNV& features) { + features.setTaskShader(true); + features.setMeshShader(true); + }); vkcv::Core core = vkcv::Core::create( window, applicationName, VK_MAKE_VERSION(0, 0, 1), { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, - {}, - { "VK_KHR_swapchain", VK_NV_MESH_SHADER_EXTENSION_NAME } + features ); vkcv::gui::GUI gui (core, window); diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp index 05befa54a03ee7d1357771d15c51d166b1474229..9550cdd7b33ec31a5a4d9ea13ae0dd97f5bdb93d 100644 --- a/projects/particle_simulation/src/main.cpp +++ b/projects/particle_simulation/src/main.cpp @@ -23,14 +23,13 @@ int main(int argc, const char **argv) { ); vkcv::camera::CameraManager cameraManager(window); - + vkcv::Core core = vkcv::Core::create( window, applicationName, VK_MAKE_VERSION(0, 0, 1), {vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute}, - {}, - {"VK_KHR_swapchain"} + { VK_KHR_SWAPCHAIN_EXTENSION_NAME } ); auto particleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index af0ca5fa9a2aeb37cb6e201bb197b3ad776ea607..ad1cc4556d82d23a29c06adfd74e05a0b7cdbc69 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -80,14 +80,18 @@ int main(int argc, const char** argv) { cameraManager.getCamera(camIndex).setFov(glm::radians(37.8)); // fov of a 35mm lens cameraManager.getCamera(camIndex2).setNearFar(0.1f, 30.0f); - + + vkcv::Features features; + features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + features.requireExtension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); + features.requireExtension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME); + vkcv::Core core = vkcv::Core::create( window, applicationName, VK_MAKE_VERSION(0, 0, 1), { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, - {}, - { "VK_KHR_swapchain", "VK_KHR_shader_float16_int8", "VK_KHR_16bit_storage" } + features ); vkcv::asset::Scene mesh; diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index 2e30fb961d0b0931e4ff8796dd92b2cbd0b5f734..f48fad1a9022cbf99f6452c319d629060befbd98 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -9,8 +9,9 @@ namespace vkcv m_Instance(other.m_Instance), m_PhysicalDevice(other.m_PhysicalDevice), m_Device(other.m_Device), - m_QueueManager(other.m_QueueManager), - m_Allocator(other.m_Allocator) + m_FeatureManager(std::move(other.m_FeatureManager)), + m_QueueManager(std::move(other.m_QueueManager)), + m_Allocator(other.m_Allocator) { other.m_Instance = nullptr; other.m_PhysicalDevice = nullptr; @@ -23,7 +24,8 @@ namespace vkcv m_Instance = other.m_Instance; m_PhysicalDevice = other.m_PhysicalDevice; m_Device = other.m_Device; - m_QueueManager = other.m_QueueManager; + m_FeatureManager = std::move(other.m_FeatureManager); + m_QueueManager = std::move(other.m_QueueManager); m_Allocator = other.m_Allocator; other.m_Instance = nullptr; @@ -37,12 +39,14 @@ namespace vkcv Context::Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device, + FeatureManager&& featureManager, QueueManager&& queueManager, vma::Allocator&& allocator) noexcept : m_Instance(instance), m_PhysicalDevice(physicalDevice), m_Device(device), - m_QueueManager(queueManager), + m_FeatureManager(std::move(featureManager)), + m_QueueManager(std::move(queueManager)), m_Allocator(allocator) {} @@ -68,6 +72,10 @@ namespace vkcv return m_Device; } + const FeatureManager& Context::getFeatureManager() const { + return m_FeatureManager; + } + const QueueManager& Context::getQueueManager() const { return m_QueueManager; } @@ -167,7 +175,6 @@ namespace vkcv return true; } - std::vector<const char*> getRequiredExtensions() { uint32_t glfwExtensionCount = 0; const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); @@ -180,20 +187,11 @@ namespace vkcv return extensions; } - bool isPresentInCharPtrVector(const std::vector<const char*>& v, const char* term){ - for (const auto& entry : v) { - if (strcmp(entry, term) != 0) { - return true; - } - } - return false; - } - Context Context::create(const char *applicationName, uint32_t applicationVersion, const std::vector<vk::QueueFlagBits>& queueFlags, - const std::vector<const char *>& instanceExtensions, - const std::vector<const char *>& deviceExtensions) { + const Features& features, + const std::vector<const char*>& instanceExtensions) { // check for layer support const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties(); @@ -226,14 +224,14 @@ namespace vkcv supportedExtensions.push_back(elem.extensionName); } - if (!checkSupport(supportedExtensions, instanceExtensions)) { - throw std::runtime_error("The requested instance extensions are not supported!"); - } - // for GLFW: get all required extensions std::vector<const char*> requiredExtensions = getRequiredExtensions(); requiredExtensions.insert(requiredExtensions.end(), instanceExtensions.begin(), instanceExtensions.end()); + if (!checkSupport(supportedExtensions, requiredExtensions)) { + throw std::runtime_error("The requested instance extensions are not supported!"); + } + const vk::ApplicationInfo applicationInfo( applicationName, applicationVersion, @@ -261,16 +259,35 @@ namespace vkcv std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices(); vk::PhysicalDevice physicalDevice = pickPhysicalDevice(instance); - // check for physical device extension support - std::vector<vk::ExtensionProperties> deviceExtensionProperties = physicalDevice.enumerateDeviceExtensionProperties(); - supportedExtensions.clear(); - for (auto& elem : deviceExtensionProperties) { - supportedExtensions.push_back(elem.extensionName); + FeatureManager featureManager (physicalDevice); + + if (featureManager.useExtension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false)) { + featureManager.useFeatures<vk::PhysicalDeviceShaderFloat16Int8Features>( + [](vk::PhysicalDeviceShaderFloat16Int8Features& features) { + features.setShaderFloat16(true); + }, false); } - if (!checkSupport(supportedExtensions, deviceExtensions)) { - throw std::runtime_error("The requested device extensions are not supported by the physical device!"); + + if (featureManager.useExtension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, false)) { + featureManager.useFeatures<vk::PhysicalDevice16BitStorageFeatures>( + [](vk::PhysicalDevice16BitStorageFeatures& features) { + features.setStorageBuffer16BitAccess(true); + }, false); } + featureManager.useFeatures([](vk::PhysicalDeviceFeatures& features) { + features.setFragmentStoresAndAtomics(true); + features.setGeometryShader(true); + features.setDepthClamp(true); + features.setShaderInt16(true); + }); + + for (const auto& feature : features.getList()) { + feature(featureManager); + } + + const auto& extensions = featureManager.getActiveExtensions(); + std::vector<vk::DeviceQueueCreateInfo> qCreateInfos; // create required queues @@ -286,58 +303,21 @@ namespace vkcv qCreateInfos.data(), 0, nullptr, - deviceExtensions.size(), - deviceExtensions.data(), - nullptr // Should our device use some features??? If yes: TODO + extensions.size(), + extensions.data(), + nullptr ); #ifndef NDEBUG deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); deviceCreateInfo.ppEnabledLayerNames = validationLayers.data(); #endif - const bool shaderFloat16 = checkSupport(deviceExtensions, { "VK_KHR_shader_float16_int8" }); - const bool storage16bit = checkSupport(deviceExtensions, { "VK_KHR_16bit_storage" }); - - // FIXME: check if device feature is supported - vk::PhysicalDeviceShaderFloat16Int8Features deviceShaderFloat16Int8Features; - deviceShaderFloat16Int8Features.shaderFloat16 = shaderFloat16; - - vk::PhysicalDevice16BitStorageFeatures device16BitStorageFeatures; - device16BitStorageFeatures.storageBuffer16BitAccess = storage16bit; - - vk::PhysicalDeviceFeatures2 deviceFeatures2; - deviceFeatures2.features.fragmentStoresAndAtomics = true; - deviceFeatures2.features.geometryShader = true; - deviceFeatures2.features.depthClamp = true; - deviceFeatures2.features.shaderInt16 = true; - - const bool usingMeshShaders = isPresentInCharPtrVector(deviceExtensions, VK_NV_MESH_SHADER_EXTENSION_NAME); - vk::PhysicalDeviceMeshShaderFeaturesNV meshShadingFeatures; - if (usingMeshShaders) { - meshShadingFeatures.taskShader = true; - meshShadingFeatures.meshShader = true; - deviceFeatures2.setPNext(&meshShadingFeatures); - } - - if (shaderFloat16) { - deviceFeatures2.setPNext(&deviceShaderFloat16Int8Features); - } - if (storage16bit) { - deviceShaderFloat16Int8Features.setPNext(&device16BitStorageFeatures); - } - - deviceCreateInfo.setPNext(&deviceFeatures2); - - // Ablauf - // qCreateInfos erstellen --> braucht das Device - // device erstellen - // jetzt koennen wir mit dem device die queues erstellen + deviceCreateInfo.setPNext(&(featureManager.getFeatures())); vk::Device device = physicalDevice.createDevice(deviceCreateInfo); - if (usingMeshShaders) - { + if (featureManager.isExtensionActive(VK_NV_MESH_SHADER_EXTENSION_NAME)) { InitMeshShaderDrawFunctions(device); } @@ -376,6 +356,7 @@ namespace vkcv instance, physicalDevice, device, + std::move(featureManager), std::move(queueManager), std::move(allocator) ); diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index ecf4de6934e2115be73992babf8a61cfd7ec1223..886a20b1dbbb7dd88b303d97ec6281ec81b2e375 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -24,14 +24,14 @@ namespace vkcv Core Core::create(const char *applicationName, uint32_t applicationVersion, const std::vector<vk::QueueFlagBits>& queueFlags, - const std::vector<const char *>& instanceExtensions, - const std::vector<const char *>& deviceExtensions) + const Features& features, + const std::vector<const char *>& instanceExtensions) { Context context = Context::create( applicationName, applicationVersion, queueFlags, - instanceExtensions, - deviceExtensions + features, + instanceExtensions ); const auto& queueManager = context.getQueueManager(); @@ -205,9 +205,8 @@ namespace vkcv vk::Device device) { std::vector<vk::ImageView> attachmentsViews; - for (const ImageHandle handle : renderTargets) { - vk::ImageView targetHandle = imageManager.getVulkanImageView(handle); - attachmentsViews.push_back(targetHandle); + for (const ImageHandle& handle : renderTargets) { + attachmentsViews.push_back(imageManager.getVulkanImageView(handle)); } const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, swapchain, imageManager); @@ -229,8 +228,7 @@ namespace vkcv ImageManager& imageManager, const vk::CommandBuffer cmdBuffer) { - for (const ImageHandle handle : renderTargets) { - vk::ImageView targetHandle = imageManager.getVulkanImageView(handle); + for (const ImageHandle& handle : renderTargets) { const bool isDepthImage = isDepthFormat(imageManager.getImageFormat(handle)); const vk::ImageLayout targetLayout = isDepthImage ? vk::ImageLayout::eDepthStencilAttachmentOptimal : vk::ImageLayout::eColorAttachmentOptimal; @@ -273,8 +271,8 @@ namespace vkcv } void Core::recordDrawcallsToCmdStream( - const CommandStreamHandle cmdStreamHandle, - const PassHandle renderpassHandle, + const CommandStreamHandle& cmdStreamHandle, + const PassHandle& renderpassHandle, const PipelineHandle pipelineHandle, const PushConstants &pushConstantData, const std::vector<DrawcallInfo> &drawcalls, @@ -310,7 +308,6 @@ namespace vkcv submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { - const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments); const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data()); @@ -319,16 +316,14 @@ namespace vkcv cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); const PipelineConfig &pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); - if(pipeConfig.m_UseDynamicViewport) - { + if (pipeConfig.m_UseDynamicViewport) { recordDynamicViewport(cmdBuffer, width, height); } - for (int i = 0; i < drawcalls.size(); i++) { + for (size_t i = 0; i < drawcalls.size(); i++) { recordDrawcall(drawcalls[i], cmdBuffer, pipelineLayout, pushConstantData, i); } - vk::Rect2D dynamicScissor({0, 0}, {width, height}); cmdBuffer.endRenderPass(); }; @@ -341,8 +336,8 @@ namespace vkcv } void Core::recordMeshShaderDrawcalls( - const CommandStreamHandle cmdStreamHandle, - const PassHandle renderpassHandle, + const CommandStreamHandle& cmdStreamHandle, + const PassHandle& renderpassHandle, const PipelineHandle pipelineHandle, const PushConstants& pushConstantData, const std::vector<MeshShaderDrawcall>& drawcalls, @@ -378,7 +373,6 @@ namespace vkcv submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { - const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments); const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data()); @@ -387,12 +381,11 @@ namespace vkcv cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); const PipelineConfig& pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); - if (pipeConfig.m_UseDynamicViewport) - { + if (pipeConfig.m_UseDynamicViewport) { recordDynamicViewport(cmdBuffer, width, height); } - for (int i = 0; i < drawcalls.size(); i++) { + for (size_t i = 0; i < drawcalls.size(); i++) { const uint32_t pushConstantOffset = i * pushConstantData.getSizePerDrawcall(); recordMeshShaderDrawcall( cmdBuffer, @@ -400,14 +393,14 @@ namespace vkcv pushConstantData, pushConstantOffset, drawcalls[i], - 0); + 0 + ); } cmdBuffer.endRenderPass(); }; - auto finishFunction = [framebuffer, this]() - { + auto finishFunction = [framebuffer, this]() { m_Context.m_Device.destroy(framebuffer); }; @@ -448,7 +441,50 @@ namespace vkcv recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr); } + + void Core::recordBeginDebugLabel(const CommandStreamHandle &cmdStream, + const std::string& label, + const std::array<float, 4>& color) { +#ifndef NDEBUG + static PFN_vkCmdBeginDebugUtilsLabelEXT beginDebugLabel = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>( + m_Context.getDevice().getProcAddr("vkCmdBeginDebugUtilsLabelEXT") + ); + + if (!beginDebugLabel) { + return; + } + + auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { + const vk::DebugUtilsLabelEXT debug ( + label.c_str(), + color + ); + + beginDebugLabel(cmdBuffer, &(static_cast<const VkDebugUtilsLabelEXT&>(debug))); + }; + + recordCommandsToStream(cmdStream, submitFunction, nullptr); +#endif + } + + void Core::recordEndDebugLabel(const CommandStreamHandle &cmdStream) { +#ifndef NDEBUG + static PFN_vkCmdEndDebugUtilsLabelEXT endDebugLabel = reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>( + m_Context.getDevice().getProcAddr("vkCmdEndDebugUtilsLabelEXT") + ); + + if (!endDebugLabel) { + return; + } + + auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { + endDebugLabel(cmdBuffer); + }; + recordCommandsToStream(cmdStream, submitFunction, nullptr); +#endif + } + void Core::recordComputeIndirectDispatchToCmdStream( const CommandStreamHandle cmdStream, const PipelineHandle computePipeline, @@ -801,4 +837,142 @@ namespace vkcv swapchain.getFormat() ); } + + static void setDebugObjectLabel(const vk::Device& device, const vk::ObjectType& type, + uint64_t handle, const std::string& label) { +#ifndef NDEBUG + static PFN_vkSetDebugUtilsObjectNameEXT setDebugLabel = reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>( + device.getProcAddr("vkSetDebugUtilsObjectNameEXT") + ); + + if (!setDebugLabel) { + return; + } + + const vk::DebugUtilsObjectNameInfoEXT debug ( + type, + handle, + label.c_str() + ); + + setDebugLabel(device, &(static_cast<const VkDebugUtilsObjectNameInfoEXT&>(debug))); +#endif + } + + void Core::setDebugLabel(const BufferHandle &handle, const std::string &label) { + if (!handle) { + vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle"); + return; + } + + setDebugObjectLabel( + m_Context.getDevice(), + vk::ObjectType::eBuffer, + reinterpret_cast<uint64_t>(static_cast<VkBuffer>( + m_BufferManager->getBuffer(handle) + )), + label + ); + } + + void Core::setDebugLabel(const PassHandle &handle, const std::string &label) { + if (!handle) { + vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle"); + return; + } + + setDebugObjectLabel( + m_Context.getDevice(), + vk::ObjectType::eRenderPass, + reinterpret_cast<uint64_t>(static_cast<VkRenderPass>( + m_PassManager->getVkPass(handle) + )), + label + ); + } + + void Core::setDebugLabel(const PipelineHandle &handle, const std::string &label) { + if (!handle) { + vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle"); + return; + } + + setDebugObjectLabel( + m_Context.getDevice(), + vk::ObjectType::ePipeline, + reinterpret_cast<uint64_t>(static_cast<VkPipeline>( + m_PipelineManager->getVkPipeline(handle) + )), + label + ); + } + + void Core::setDebugLabel(const DescriptorSetHandle &handle, const std::string &label) { + if (!handle) { + vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle"); + return; + } + + setDebugObjectLabel( + m_Context.getDevice(), + vk::ObjectType::eDescriptorSet, + reinterpret_cast<uint64_t>(static_cast<VkDescriptorSet>( + m_DescriptorManager->getDescriptorSet(handle).vulkanHandle + )), + label + ); + } + + void Core::setDebugLabel(const SamplerHandle &handle, const std::string &label) { + if (!handle) { + vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle"); + return; + } + + setDebugObjectLabel( + m_Context.getDevice(), + vk::ObjectType::eSampler, + reinterpret_cast<uint64_t>(static_cast<VkSampler>( + m_SamplerManager->getVulkanSampler(handle) + )), + label + ); + } + + void Core::setDebugLabel(const ImageHandle &handle, const std::string &label) { + if (!handle) { + vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle"); + return; + } else + if (handle.isSwapchainImage()) { + vkcv_log(LogLevel::WARNING, "Can't set debug label to swapchain image"); + return; + } + + setDebugObjectLabel( + m_Context.getDevice(), + vk::ObjectType::eImage, + reinterpret_cast<uint64_t>(static_cast<VkImage>( + m_ImageManager->getVulkanImage(handle) + )), + label + ); + } + + void Core::setDebugLabel(const CommandStreamHandle &handle, const std::string &label) { + if (!handle) { + vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle"); + return; + } + + setDebugObjectLabel( + m_Context.getDevice(), + vk::ObjectType::eCommandBuffer, + reinterpret_cast<uint64_t>(static_cast<VkCommandBuffer>( + m_CommandStreamManager->getStreamCommandBuffer(handle) + )), + label + ); + } + } diff --git a/src/vkcv/DrawcallRecording.cpp b/src/vkcv/DrawcallRecording.cpp index d89ace3859717f753534402507a713a78bfb6876..ca8b248a06d06c7aed6f8d0e9760645b727a5993 100644 --- a/src/vkcv/DrawcallRecording.cpp +++ b/src/vkcv/DrawcallRecording.cpp @@ -52,8 +52,6 @@ namespace vkcv { } } - - struct MeshShaderFunctions { PFN_vkCmdDrawMeshTasksNV cmdDrawMeshTasks = nullptr; diff --git a/src/vkcv/FeatureManager.cpp b/src/vkcv/FeatureManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18307999bb28ed60791a801b952619eeeba51a53 --- /dev/null +++ b/src/vkcv/FeatureManager.cpp @@ -0,0 +1,437 @@ + +#include "vkcv/FeatureManager.hpp" + +#include <stddef.h> +#include <string.h> +#include <type_traits> + +namespace vkcv { + +#ifdef _MSVC_LANG +#define typeof(var) std::decay<decltype((var))>::type +#endif + +#define vkcv_check_init_features2(type)\ +type supported; \ +vk::PhysicalDeviceFeatures2 query; \ +query.setPNext(&supported); \ +m_physicalDevice.getFeatures2(&query) + +#define vkcv_check_feature(attribute) { \ + const char *f = reinterpret_cast<const char*>(&(features)); \ + const char *s = reinterpret_cast<const char*>(&(supported)); \ + const vk::Bool32* fb = reinterpret_cast<const vk::Bool32*>(f + offsetof(typeof((features)), attribute)); \ + const vk::Bool32* sb = reinterpret_cast<const vk::Bool32*>(s + offsetof(typeof((features)), attribute)); \ + if ((*fb) && (!*sb)) { \ + vkcv_log(((required)? LogLevel::ERROR : LogLevel::WARNING), \ + "Feature '" #attribute "' is not supported"); \ + return false; \ + } \ +} + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceFeatures &features, bool required) const { + const auto& supported = m_physicalDevice.getFeatures(); + + vkcv_check_feature(alphaToOne); + vkcv_check_feature(depthBiasClamp); + vkcv_check_feature(depthBounds); + vkcv_check_feature(depthClamp); + vkcv_check_feature(drawIndirectFirstInstance); + vkcv_check_feature(dualSrcBlend); + vkcv_check_feature(fillModeNonSolid); + vkcv_check_feature(fragmentStoresAndAtomics); + vkcv_check_feature(fullDrawIndexUint32); + vkcv_check_feature(geometryShader); + vkcv_check_feature(imageCubeArray); + vkcv_check_feature(independentBlend); + vkcv_check_feature(inheritedQueries); + vkcv_check_feature(largePoints); + vkcv_check_feature(logicOp); + vkcv_check_feature(multiDrawIndirect); + vkcv_check_feature(multiViewport); + vkcv_check_feature(occlusionQueryPrecise); + vkcv_check_feature(pipelineStatisticsQuery); + vkcv_check_feature(robustBufferAccess); + vkcv_check_feature(sampleRateShading); + vkcv_check_feature(samplerAnisotropy); + vkcv_check_feature(shaderClipDistance); + vkcv_check_feature(shaderCullDistance); + vkcv_check_feature(shaderFloat64); + vkcv_check_feature(shaderImageGatherExtended); + vkcv_check_feature(shaderInt16); + vkcv_check_feature(shaderInt64); + vkcv_check_feature(shaderResourceMinLod); + vkcv_check_feature(shaderResourceResidency); + vkcv_check_feature(shaderSampledImageArrayDynamicIndexing); + vkcv_check_feature(shaderStorageBufferArrayDynamicIndexing); + vkcv_check_feature(shaderStorageImageArrayDynamicIndexing); + vkcv_check_feature(shaderStorageImageExtendedFormats); + vkcv_check_feature(shaderStorageImageMultisample); + vkcv_check_feature(shaderStorageImageReadWithoutFormat); + vkcv_check_feature(shaderStorageImageWriteWithoutFormat); + vkcv_check_feature(shaderTessellationAndGeometryPointSize); + vkcv_check_feature(shaderUniformBufferArrayDynamicIndexing); + vkcv_check_feature(sparseBinding); + vkcv_check_feature(sparseResidency2Samples); + vkcv_check_feature(sparseResidency4Samples); + vkcv_check_feature(sparseResidency8Samples); + vkcv_check_feature(sparseResidency16Samples); + vkcv_check_feature(sparseResidencyAliased); + vkcv_check_feature(sparseResidencyBuffer); + vkcv_check_feature(sparseResidencyImage2D); + vkcv_check_feature(sparseResidencyImage3D); + vkcv_check_feature(tessellationShader); + vkcv_check_feature(textureCompressionASTC_LDR); + vkcv_check_feature(textureCompressionBC); + vkcv_check_feature(textureCompressionETC2); + vkcv_check_feature(variableMultisampleRate); + vkcv_check_feature(vertexPipelineStoresAndAtomics); + vkcv_check_feature(wideLines); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDevice16BitStorageFeatures &features, bool required) const { + vkcv_check_init_features2(vk::PhysicalDevice16BitStorageFeatures); + + vkcv_check_feature(storageBuffer16BitAccess); + vkcv_check_feature(storageInputOutput16); + vkcv_check_feature(storagePushConstant16); + vkcv_check_feature(uniformAndStorageBuffer16BitAccess); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDevice8BitStorageFeatures &features, bool required) const { + vkcv_check_init_features2(vk::PhysicalDevice8BitStorageFeatures); + + vkcv_check_feature(storageBuffer8BitAccess); + vkcv_check_feature(storagePushConstant8); + vkcv_check_feature(uniformAndStorageBuffer8BitAccess); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceBufferDeviceAddressFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceBufferDeviceAddressFeatures); + + vkcv_check_feature(bufferDeviceAddress); + vkcv_check_feature(bufferDeviceAddressCaptureReplay); + vkcv_check_feature(bufferDeviceAddressMultiDevice); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceDescriptorIndexingFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceDescriptorIndexingFeatures); + + vkcv_check_feature(shaderInputAttachmentArrayDynamicIndexing); + vkcv_check_feature(shaderInputAttachmentArrayNonUniformIndexing); + vkcv_check_feature(shaderSampledImageArrayNonUniformIndexing); + vkcv_check_feature(shaderStorageBufferArrayNonUniformIndexing); + vkcv_check_feature(shaderStorageImageArrayNonUniformIndexing); + vkcv_check_feature(shaderStorageTexelBufferArrayDynamicIndexing); + vkcv_check_feature(shaderStorageTexelBufferArrayNonUniformIndexing); + vkcv_check_feature(shaderUniformBufferArrayNonUniformIndexing); + vkcv_check_feature(shaderUniformTexelBufferArrayDynamicIndexing); + vkcv_check_feature(shaderUniformTexelBufferArrayNonUniformIndexing); + vkcv_check_feature(descriptorBindingPartiallyBound); + vkcv_check_feature(descriptorBindingSampledImageUpdateAfterBind); + vkcv_check_feature(descriptorBindingStorageBufferUpdateAfterBind); + vkcv_check_feature(descriptorBindingStorageImageUpdateAfterBind); + vkcv_check_feature(descriptorBindingStorageTexelBufferUpdateAfterBind); + vkcv_check_feature(descriptorBindingUniformBufferUpdateAfterBind); + vkcv_check_feature(descriptorBindingUniformTexelBufferUpdateAfterBind); + vkcv_check_feature(descriptorBindingUpdateUnusedWhilePending); + vkcv_check_feature(descriptorBindingVariableDescriptorCount); + vkcv_check_feature(runtimeDescriptorArray); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceHostQueryResetFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceHostQueryResetFeatures); + + vkcv_check_feature(hostQueryReset); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceImagelessFramebufferFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceImagelessFramebufferFeatures); + + vkcv_check_feature(imagelessFramebuffer); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceMultiviewFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceMultiviewFeatures); + + vkcv_check_feature(multiview); + vkcv_check_feature(multiviewGeometryShader); + vkcv_check_feature(multiviewTessellationShader); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceProtectedMemoryFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceProtectedMemoryFeatures); + + vkcv_check_feature(protectedMemory); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceSamplerYcbcrConversionFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceSamplerYcbcrConversionFeatures); + + vkcv_check_feature(samplerYcbcrConversion); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceScalarBlockLayoutFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceScalarBlockLayoutFeatures); + + vkcv_check_feature(scalarBlockLayout); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceSeparateDepthStencilLayoutsFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceSeparateDepthStencilLayoutsFeatures); + + vkcv_check_feature(separateDepthStencilLayouts); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceShaderAtomicInt64Features &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceShaderAtomicInt64Features); + + vkcv_check_feature(shaderBufferInt64Atomics); + vkcv_check_feature(shaderSharedInt64Atomics); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceShaderFloat16Int8Features &features, bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceShaderFloat16Int8Features); + + vkcv_check_feature(shaderFloat16); + vkcv_check_feature(shaderInt8); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures); + + vkcv_check_feature(shaderSubgroupExtendedTypes); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceTimelineSemaphoreFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceTimelineSemaphoreFeatures); + + vkcv_check_feature(timelineSemaphore); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceUniformBufferStandardLayoutFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceUniformBufferStandardLayoutFeatures); + + vkcv_check_feature(uniformBufferStandardLayout); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceVariablePointersFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceVariablePointersFeatures); + + vkcv_check_feature(variablePointers); + vkcv_check_feature(variablePointersStorageBuffer); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceVulkanMemoryModelFeatures &features, + bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceVulkanMemoryModelFeatures); + + vkcv_check_feature(vulkanMemoryModel); + vkcv_check_feature(vulkanMemoryModelDeviceScope); + vkcv_check_feature(vulkanMemoryModelAvailabilityVisibilityChains); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceMeshShaderFeaturesNV &features, bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceMeshShaderFeaturesNV); + + vkcv_check_feature(taskShader); + vkcv_check_feature(meshShader); + + return true; + } + + vk::BaseOutStructure* FeatureManager::findFeatureStructure(vk::StructureType type) const { + for (auto& base : m_featuresExtensions) { + if (base->sType == type) { + return base; + } + } + + return nullptr; + } + + const char* strclone(const char* str) { + if (!str) { + return nullptr; + } + + const size_t length = strlen(str) + 1; + + if (length <= 1) { + return nullptr; + } + + char* clone = new char[length]; + strcpy(clone, str); + return clone; + } + + FeatureManager::FeatureManager(vk::PhysicalDevice &physicalDevice) : + m_physicalDevice(physicalDevice), + m_supportedExtensions(), + m_activeExtensions(), + m_featuresBase(), + m_featuresExtensions() { + for (const auto& extension : m_physicalDevice.enumerateDeviceExtensionProperties()) { + const char* clone = strclone(extension.extensionName); + + if (clone) { + m_supportedExtensions.push_back(clone); + } + } + } + + FeatureManager::FeatureManager(FeatureManager &&other) noexcept : + m_physicalDevice(other.m_physicalDevice), + m_supportedExtensions(std::move(other.m_supportedExtensions)), + m_activeExtensions(std::move(other.m_activeExtensions)), + m_featuresBase(other.m_featuresBase), + m_featuresExtensions(std::move(other.m_featuresExtensions)) { + other.m_featuresExtensions.clear(); + other.m_activeExtensions.clear(); + other.m_supportedExtensions.clear(); + } + + FeatureManager::~FeatureManager() { + for (auto& features : m_featuresExtensions) { + delete features; + } + + for (auto& extension : m_activeExtensions) { + delete[] extension; + } + + for (auto& extension : m_supportedExtensions) { + delete[] extension; + } + } + + FeatureManager &FeatureManager::operator=(FeatureManager &&other) noexcept { + m_physicalDevice = other.m_physicalDevice; + m_supportedExtensions = std::move(other.m_supportedExtensions); + m_activeExtensions = std::move(other.m_activeExtensions); + m_featuresBase = other.m_featuresBase; + m_featuresExtensions = std::move(other.m_featuresExtensions); + + other.m_featuresExtensions.clear(); + other.m_activeExtensions.clear(); + other.m_supportedExtensions.clear(); + + return *this; + } + + bool FeatureManager::isExtensionSupported(const std::string& extension) const { + for (const auto& supported : m_supportedExtensions) { + if (0 == strcmp(supported, extension.c_str())) { + return true; + } + } + + return false; + } + + bool FeatureManager::useExtension(const std::string& extension, bool required) { + const char* clone = strclone(extension.c_str()); + + if (!clone) { + vkcv_log(LogLevel::WARNING, "Extension '%s' is not valid", extension.c_str()); + return false; + } + + if (!isExtensionSupported(extension)) { + vkcv_log((required? LogLevel::ERROR : LogLevel::WARNING), "Extension '%s' is not supported", + extension.c_str()); + + delete[] clone; + return false; + } + + m_activeExtensions.push_back(clone); + return true; + } + + bool FeatureManager::isExtensionActive(const std::string& extension) const { + for (const auto& supported : m_activeExtensions) { + if (0 == strcmp(supported, extension.c_str())) { + return true; + } + } + + return false; + } + + const std::vector<const char*>& FeatureManager::getActiveExtensions() const { + return m_activeExtensions; + } + + bool FeatureManager::useFeatures(const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction, + bool required) { + vk::PhysicalDeviceFeatures features = m_featuresBase.features; + + featureFunction(features); + + if (!checkSupport(features, required)) { + return false; + } + + m_featuresBase.features = features; + return true; + } + + const vk::PhysicalDeviceFeatures2& FeatureManager::getFeatures() const { + return m_featuresBase; + } + +} diff --git a/src/vkcv/Features.cpp b/src/vkcv/Features.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60616685f67084b6875ce14bf09f524a9127688f --- /dev/null +++ b/src/vkcv/Features.cpp @@ -0,0 +1,62 @@ + +#include "vkcv/Features.hpp" + +namespace vkcv { + + Features::Features(const std::initializer_list<std::string>& list) : m_features() { + for (const auto& extension : list) { + requireExtension(extension); + } + } + + void Features::requireExtension(const std::string& extension) { + m_features.emplace_back([extension](FeatureManager& featureManager) { + return featureManager.useExtension(extension, true); + }); + } + + void Features::requireExtensionFeature(const std::string &extension, + const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) { + m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) { + if (featureManager.useExtension(extension, true)) { + return featureManager.useFeatures(featureFunction, true); + } else { + return false; + } + }); + } + + void Features::requireFeature(const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) { + m_features.emplace_back([featureFunction](FeatureManager& featureManager) { + return featureManager.useFeatures(featureFunction, true); + }); + } + + void Features::tryExtension(const std::string& extension) { + m_features.emplace_back([extension](FeatureManager& featureManager) { + return featureManager.useExtension(extension, false); + }); + } + + void Features::tryExtensionFeature(const std::string &extension, + const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) { + m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) { + if (featureManager.useExtension(extension, false)) { + return featureManager.useFeatures(featureFunction, false); + } else { + return false; + } + }); + } + + void Features::tryFeature(const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) { + m_features.emplace_back([featureFunction](FeatureManager& featureManager) { + return featureManager.useFeatures(featureFunction, false); + }); + } + + const std::vector<Feature>& Features::getList() const { + return m_features; + } + +} diff --git a/src/vkcv/QueueManager.cpp b/src/vkcv/QueueManager.cpp index 15e958b0de929e53170324ade27a9b3663a15d6a..79e15c9b00e4c67fb956bdcd0e8b1ff05261b2f1 100644 --- a/src/vkcv/QueueManager.cpp +++ b/src/vkcv/QueueManager.cpp @@ -44,7 +44,7 @@ namespace vkcv { std::vector<int> prios; for(auto flag: queueFlags) { int prioCount = 0; - for (int i = 0; i < qFamilyProperties.size(); i++) { + for (size_t i = 0; i < qFamilyProperties.size(); i++) { prioCount += (static_cast<uint32_t>(flag & qFamilyProperties[i].queueFlags) != 0) * qFamilyProperties[i].queueCount; } prios.push_back(prioCount); @@ -65,10 +65,14 @@ namespace vkcv { std::vector<std::vector<int>> queueFamilyStatus, initialQueueFamilyStatus; for (auto qFamily : qFamilyProperties) { - int graphicsCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0) * qFamily.queueCount; - int computeCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0) * qFamily.queueCount; - int transferCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0) * qFamily.queueCount; - queueFamilyStatus.push_back({graphicsCount, computeCount, transferCount}); + auto graphicsCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0? qFamily.queueCount : 0; + auto computeCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0? qFamily.queueCount : 0; + auto transferCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0? qFamily.queueCount : 0; + queueFamilyStatus.push_back({ + static_cast<int>(graphicsCount), + static_cast<int>(computeCount), + static_cast<int>(transferCount) + }); } initialQueueFamilyStatus = queueFamilyStatus;