From 220d58d836e826693c3d1eb14e7ebfe176bf488c Mon Sep 17 00:00:00 2001 From: Alexander Gauggel <agauggel@uni-koblenz.de> Date: Tue, 3 Aug 2021 15:48:59 +0200 Subject: [PATCH] [#106] Initial project --- include/vkcv/DrawcallRecording.hpp | 15 +- projects/CMakeLists.txt | 1 + projects/indirect_dispatch/CMakeLists.txt | 37 +++++ .../resources/models/Sphere.bin | 3 + .../resources/models/Sphere.gltf | 3 + .../resources/shaders/shader.frag | 10 ++ .../resources/shaders/shader.vert | 16 +++ projects/indirect_dispatch/src/App.cpp | 99 +++++++++++++ projects/indirect_dispatch/src/App.hpp | 26 ++++ projects/indirect_dispatch/src/AppConfig.hpp | 8 ++ projects/indirect_dispatch/src/AppSetup.cpp | 130 ++++++++++++++++++ projects/indirect_dispatch/src/AppSetup.hpp | 22 +++ projects/indirect_dispatch/src/main.cpp | 12 ++ 13 files changed, 380 insertions(+), 2 deletions(-) create mode 100644 projects/indirect_dispatch/CMakeLists.txt create mode 100644 projects/indirect_dispatch/resources/models/Sphere.bin create mode 100644 projects/indirect_dispatch/resources/models/Sphere.gltf create mode 100644 projects/indirect_dispatch/resources/shaders/shader.frag create mode 100644 projects/indirect_dispatch/resources/shaders/shader.vert create mode 100644 projects/indirect_dispatch/src/App.cpp create mode 100644 projects/indirect_dispatch/src/App.hpp create mode 100644 projects/indirect_dispatch/src/AppConfig.hpp create mode 100644 projects/indirect_dispatch/src/AppSetup.cpp create mode 100644 projects/indirect_dispatch/src/AppSetup.hpp create mode 100644 projects/indirect_dispatch/src/main.cpp diff --git a/include/vkcv/DrawcallRecording.hpp b/include/vkcv/DrawcallRecording.hpp index 260fbbc6..37cf02d9 100644 --- a/include/vkcv/DrawcallRecording.hpp +++ b/include/vkcv/DrawcallRecording.hpp @@ -29,8 +29,19 @@ namespace vkcv { }; struct Mesh { - inline Mesh(std::vector<VertexBufferBinding> vertexBufferBindings, vk::Buffer indexBuffer, size_t indexCount, IndexBitCount indexBitCount = IndexBitCount::Bit16) noexcept - : vertexBufferBindings(vertexBufferBindings), indexBuffer(indexBuffer), indexCount(indexCount), indexBitCount(indexBitCount){} + + inline Mesh(){} + + inline Mesh( + std::vector<VertexBufferBinding> vertexBufferBindings, + vk::Buffer indexBuffer, + size_t indexCount, + IndexBitCount indexBitCount = IndexBitCount::Bit16) noexcept + : + vertexBufferBindings(vertexBufferBindings), + indexBuffer(indexBuffer), + indexCount(indexCount), + indexBitCount(indexBitCount) {} std::vector<VertexBufferBinding> vertexBufferBindings; vk::Buffer indexBuffer; diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index c4fde454..80107184 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory(first_scene) add_subdirectory(particle_simulation) add_subdirectory(voxelization) add_subdirectory(mesh_shader) +add_subdirectory(indirect_dispatch) diff --git a/projects/indirect_dispatch/CMakeLists.txt b/projects/indirect_dispatch/CMakeLists.txt new file mode 100644 index 00000000..b54a3186 --- /dev/null +++ b/projects/indirect_dispatch/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.16) +project(indirect_dispatch) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(indirect_dispatch src/main.cpp) + +target_sources(indirect_dispatch PRIVATE + src/App.hpp + src/App.cpp + + src/AppConfig.hpp + + src/AppSetup.hpp + src/AppSetup.cpp) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(indirect_dispatch PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(indirect_dispatch PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(indirect_dispatch PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(indirect_dispatch SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(indirect_dispatch vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_testing vkcv_camera vkcv_shader_compiler vkcv_gui) \ No newline at end of file diff --git a/projects/indirect_dispatch/resources/models/Sphere.bin b/projects/indirect_dispatch/resources/models/Sphere.bin new file mode 100644 index 00000000..786ec34b --- /dev/null +++ b/projects/indirect_dispatch/resources/models/Sphere.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a1c5fefa4a07401791a2af9318665bca3b328cf11736b307e129ae8ba4c8931d +size 17328 diff --git a/projects/indirect_dispatch/resources/models/Sphere.gltf b/projects/indirect_dispatch/resources/models/Sphere.gltf new file mode 100644 index 00000000..0b380598 --- /dev/null +++ b/projects/indirect_dispatch/resources/models/Sphere.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19b29ddffaeecfa15f19dc943c0ecc9cb3c22d47adb35c19e8727edd7e29c565 +size 1847 diff --git a/projects/indirect_dispatch/resources/shaders/shader.frag b/projects/indirect_dispatch/resources/shaders/shader.frag new file mode 100644 index 00000000..8d032cab --- /dev/null +++ b/projects/indirect_dispatch/resources/shaders/shader.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 passNormal; + +layout(location = 0) out vec3 outColor; + +void main() { + outColor = passNormal * 0.5 + 0.5; +} \ No newline at end of file diff --git a/projects/indirect_dispatch/resources/shaders/shader.vert b/projects/indirect_dispatch/resources/shaders/shader.vert new file mode 100644 index 00000000..5e1f72dc --- /dev/null +++ b/projects/indirect_dispatch/resources/shaders/shader.vert @@ -0,0 +1,16 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; + +layout(location = 0) out vec3 passNormal; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +void main() { + gl_Position = mvp * vec4(inPosition, 1.0); + passNormal = inNormal; +} \ No newline at end of file diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp new file mode 100644 index 00000000..b95c0f36 --- /dev/null +++ b/projects/indirect_dispatch/src/App.cpp @@ -0,0 +1,99 @@ +#include "App.hpp" +#include "AppConfig.hpp" +#include <chrono> + +App::App() : + m_applicationName("Indirect Dispatch"), + m_windowWidth(AppConfig::defaultWindowWidth), + m_windowHeight(AppConfig::defaultWindowHeight), + m_window(vkcv::Window::create( + m_applicationName, + m_windowWidth, + m_windowHeight, + true)), + m_core(vkcv::Core::create( + m_window, + m_applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer }, + {}, + { "VK_KHR_swapchain" })), + m_cameraManager(m_window){ + + m_isInitialized = false; +} + +bool App::initialize() { + + if (!loadMeshGraphicPass(m_core, &m_meshPassHandles)) + return false; + + if (!loadSphereMesh(m_core, &m_sphereMesh)) + return false; + + m_renderTargets = createRenderTargets(m_core, m_windowWidth, m_windowHeight); + + const int cameraIndex = m_cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + m_cameraManager.getCamera(cameraIndex).setPosition(glm::vec3(0, 0, -3)); + + m_isInitialized = true; +} + +void App::run() { + + if (!m_isInitialized) { + vkcv_log(vkcv::LogLevel::WARNING, "Application is not initialized, app should be initialized explicitly to check for errors"); + if (!initialize()) { + vkcv_log(vkcv::LogLevel::ERROR, "Emergency initialization failed, exiting"); + return; + } + } + + auto frameStartTime = std::chrono::system_clock::now(); + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + const vkcv::DrawcallInfo sphereDrawcall(m_sphereMesh.mesh, {}, 1); + + while (m_window.isWindowOpen()) { + vkcv::Window::pollEvents(); + + if (m_window.getHeight() == 0 || m_window.getWidth() == 0) + continue; + + uint32_t swapchainWidth, swapchainHeight; + if (!m_core.beginFrame(swapchainWidth, swapchainHeight)) + continue; + + const bool hasResolutionChanged = (swapchainWidth != m_windowWidth) || (swapchainHeight != m_windowHeight); + if (hasResolutionChanged) { + m_windowWidth = swapchainWidth; + m_windowHeight = swapchainHeight; + + m_renderTargets = createRenderTargets(m_core, m_windowWidth, m_windowHeight); + } + + auto frameEndTime = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(frameEndTime - frameStartTime); + frameStartTime = frameEndTime; + + m_cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + const glm::mat4 mvp = m_cameraManager.getActiveCamera().getMVP(); + + vkcv::PushConstants pushConstants(sizeof(glm::mat4)); + pushConstants.appendDrawcall(mvp); + + const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, m_renderTargets.depthBuffer }; + const vkcv::CommandStreamHandle cmdStream = m_core.createCommandStream(vkcv::QueueType::Graphics); + + m_core.recordDrawcallsToCmdStream( + cmdStream, + m_meshPassHandles.renderPass, + m_meshPassHandles.pipeline, + pushConstants, + { sphereDrawcall }, + renderTargets); + + m_core.prepareSwapchainImageForPresent(cmdStream); + m_core.submitCommandStream(cmdStream); + m_core.endFrame(); + } +} \ No newline at end of file diff --git a/projects/indirect_dispatch/src/App.hpp b/projects/indirect_dispatch/src/App.hpp new file mode 100644 index 00000000..d4b5387f --- /dev/null +++ b/projects/indirect_dispatch/src/App.hpp @@ -0,0 +1,26 @@ +#pragma once +#include <vkcv/Core.hpp> +#include <vkcv/camera/CameraManager.hpp> +#include "AppSetup.hpp" + +class App { +public: + App(); + bool initialize(); + void run(); +private: + const char* m_applicationName; + bool m_isInitialized; + + int m_windowWidth; + int m_windowHeight; + + vkcv::Window m_window; + vkcv::Core m_core; + vkcv::camera::CameraManager m_cameraManager; + + MeshResources m_sphereMesh; + GraphicPassHandles m_meshPassHandles; + + RenderTargets m_renderTargets; +}; \ No newline at end of file diff --git a/projects/indirect_dispatch/src/AppConfig.hpp b/projects/indirect_dispatch/src/AppConfig.hpp new file mode 100644 index 00000000..71993ebd --- /dev/null +++ b/projects/indirect_dispatch/src/AppConfig.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "vulkan/vulkan.hpp" + +namespace AppConfig{ + const int defaultWindowWidth = 1280; + const int defaultWindowHeight = 720; + const vk::Format depthBufferFormat = vk::Format::eD32Sfloat; +} \ No newline at end of file diff --git a/projects/indirect_dispatch/src/AppSetup.cpp b/projects/indirect_dispatch/src/AppSetup.cpp new file mode 100644 index 00000000..ab14c181 --- /dev/null +++ b/projects/indirect_dispatch/src/AppSetup.cpp @@ -0,0 +1,130 @@ +#include "AppSetup.hpp" +#include "AppConfig.hpp" +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> + +bool loadSphereMesh(vkcv::Core& core, MeshResources* outMesh) { + assert(outMesh); + + vkcv::asset::Scene sphereScene; + const int meshLoadResult = vkcv::asset::loadScene("resources/models/Sphere.gltf", sphereScene); + + if (meshLoadResult != 1) { + vkcv_log(vkcv::LogLevel::ERROR, "Mesh loading failed"); + return false; + } + + if (sphereScene.meshes.size() < 1) { + vkcv_log(vkcv::LogLevel::ERROR, "Sphere mesh scene does not contain any vertex groups"); + return false; + } + assert(!sphereScene.vertexGroups.empty()); + + auto& sphereVertexData = sphereScene.vertexGroups[0].vertexBuffer; + auto& sphereIndexData = sphereScene.vertexGroups[0].indexBuffer; + + vkcv::Buffer vertexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::VERTEX, + sphereVertexData.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL); + + vkcv::Buffer indexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::INDEX, + sphereIndexData.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL); + + vertexBuffer.fill(sphereVertexData.data); + indexBuffer.fill(sphereIndexData.data); + + outMesh->vertexBuffer = vertexBuffer.getHandle(); + outMesh->indexBuffer = indexBuffer.getHandle(); + + auto& attributes = sphereVertexData.attributes; + + std::sort(attributes.begin(), attributes.end(), + [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { + return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); + }); + + const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { + vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()), + vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()) }; + + outMesh->mesh = vkcv::Mesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), sphereScene.vertexGroups[0].numIndices); + + return true; +} + +bool loadMeshGraphicPass(vkcv::Core& core, GraphicPassHandles* outPassHandles) { + assert(outPassHandles); + + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchain().getFormat()); + + const vkcv::AttachmentDescription depth_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + AppConfig::depthBufferFormat); + + vkcv::PassConfig meshPassDefinition({ present_color_attachment, depth_attachment }); + outPassHandles->renderPass = core.createPass(meshPassDefinition); + + if (!outPassHandles->renderPass) { + vkcv_log(vkcv::LogLevel::ERROR, "Error: Could not create renderpass"); + return false; + } + + vkcv::ShaderProgram meshProgram; + vkcv::shader::GLSLCompiler compiler; + + compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"), + [&meshProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + meshProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"), + [&meshProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + meshProgram.addShader(shaderStage, path); + }); + + const std::vector<vkcv::VertexAttachment> vertexAttachments = meshProgram.getVertexAttachments(); + std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + } + + const vkcv::VertexLayout meshVertexLayout(bindings); + + const vkcv::PipelineConfig meshPipelineConfig{ + meshProgram, + UINT32_MAX, + UINT32_MAX, + outPassHandles->renderPass, + { meshVertexLayout }, + {}, + true }; + outPassHandles->pipeline = core.createGraphicsPipeline(meshPipelineConfig); + + if (!outPassHandles->pipeline) { + vkcv_log(vkcv::LogLevel::ERROR, "Error: Could not create graphics pipeline"); + return false; + } + + return true; +} + +RenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, const uint32_t height) { + + RenderTargets targets; + + targets.depthBuffer = core.createImage( + AppConfig::depthBufferFormat, + width, + height, + 1, + false).getHandle(); + + return targets; +} \ No newline at end of file diff --git a/projects/indirect_dispatch/src/AppSetup.hpp b/projects/indirect_dispatch/src/AppSetup.hpp new file mode 100644 index 00000000..1436d134 --- /dev/null +++ b/projects/indirect_dispatch/src/AppSetup.hpp @@ -0,0 +1,22 @@ +#pragma once +#include <vkcv/Core.hpp> + +struct RenderTargets { + vkcv::ImageHandle depthBuffer; +}; + +struct GraphicPassHandles { + vkcv::PipelineHandle pipeline; + vkcv::PassHandle renderPass; +}; + +struct MeshResources { + vkcv::Mesh mesh; + vkcv::BufferHandle vertexBuffer; + vkcv::BufferHandle indexBuffer; +}; + +bool loadSphereMesh(vkcv::Core& core, MeshResources* outMesh); +bool loadMeshGraphicPass(vkcv::Core& core, GraphicPassHandles* outPassHandles); + +RenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, const uint32_t height); \ No newline at end of file diff --git a/projects/indirect_dispatch/src/main.cpp b/projects/indirect_dispatch/src/main.cpp new file mode 100644 index 00000000..6e3d9e63 --- /dev/null +++ b/projects/indirect_dispatch/src/main.cpp @@ -0,0 +1,12 @@ +#include "App.hpp" + +int main(int argc, const char** argv) { + + App app; + if (!app.initialize()) { + std::cerr << "Application initialization failed, exiting" << std::endl; + } + app.run(); + + return 0; +} -- GitLab