diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index c8d69fe14379dee2677bd8a2f829348bc5289cf0..f3048748bcafdec0758f7022a37c75c67bc8d2fc 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -81,8 +81,6 @@ namespace vkcv SyncResources m_SyncResources; uint32_t m_currentSwapchainImageIndex; std::vector<vk::Framebuffer> m_TemporaryFramebuffers; - - ImageHandle m_DepthImage; /** * recreates the swapchain @@ -240,7 +238,8 @@ namespace vkcv const BufferHandle indexBuffer, const size_t indexCount, const vkcv::ResourcesHandle resourceHandle, - const size_t resourceDescriptorSetIndex); + const size_t resourceDescriptorSetIndex, + const std::vector<ImageHandle> &renderTargets); /** * @brief end recording and present image diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp index bb0438d3e2482bb119c633a4e987cf28dac2375f..bd80630808c03ea731a445209062a98e761849de 100644 --- a/include/vkcv/Handles.hpp +++ b/include/vkcv/Handles.hpp @@ -93,9 +93,8 @@ namespace vkcv class ImageHandle : public Handle { friend class ImageManager; - private: using Handle::Handle; - + public: [[nodiscard]] bool isSwapchainImage() const; diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index 7ca73a0811df7f1568508b56312ce3348237a695..ccbdaf4101c5dabb3e9d43788e255eab85ad5776 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -2,3 +2,4 @@ # Add new projects/examples here: add_subdirectory(first_triangle) add_subdirectory(first_mesh) +add_subdirectory(cmd_sync_test) \ No newline at end of file diff --git a/projects/cmd_sync_test/.gitignore b/projects/cmd_sync_test/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..85ce58a41ce7dcbe4f4a41bbf4779d82cede0106 --- /dev/null +++ b/projects/cmd_sync_test/.gitignore @@ -0,0 +1 @@ +first_mesh \ No newline at end of file diff --git a/projects/cmd_sync_test/CMakeLists.txt b/projects/cmd_sync_test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..da1d12949d9e8c918d78ab5cb0484106fae69b6a --- /dev/null +++ b/projects/cmd_sync_test/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.16) +project(cmd_sync_test) + +# 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(cmd_sync_test src/main.cpp) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(cmd_sync_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(cmd_sync_test 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(cmd_sync_test PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(cmd_sync_test SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(cmd_sync_test vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera) diff --git a/projects/cmd_sync_test/resources/cube/boards2_vcyc_jpg.jpg b/projects/cmd_sync_test/resources/cube/boards2_vcyc_jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2636039e272289c0fba3fa2d88a060b857501248 --- /dev/null +++ b/projects/cmd_sync_test/resources/cube/boards2_vcyc_jpg.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cca33a6e58ddd1b37a6e6853a9aa0e7b15ca678937119194752393dd2a0a0564 +size 1192476 diff --git a/projects/cmd_sync_test/resources/cube/cube.bin b/projects/cmd_sync_test/resources/cube/cube.bin new file mode 100644 index 0000000000000000000000000000000000000000..3303cd8635848bee18e10ab8754d5e4e7218db92 --- /dev/null +++ b/projects/cmd_sync_test/resources/cube/cube.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9bb9b6b8bbe50a0aaa517057f245ee844f80afa7426dacb2aed4128f71629ce4 +size 840 diff --git a/projects/cmd_sync_test/resources/cube/cube.blend b/projects/cmd_sync_test/resources/cube/cube.blend new file mode 100644 index 0000000000000000000000000000000000000000..62ccb2c742094bcfb5ed194ab905bffae86bfd65 --- /dev/null +++ b/projects/cmd_sync_test/resources/cube/cube.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6c1e245f259c610528c9485db6688928faac0ab2addee9e3c2dde7740e4dd09 +size 774920 diff --git a/projects/cmd_sync_test/resources/cube/cube.blend1 b/projects/cmd_sync_test/resources/cube/cube.blend1 new file mode 100644 index 0000000000000000000000000000000000000000..13f21dcca218d7bc7a07a8a9682b5e1d9e607736 --- /dev/null +++ b/projects/cmd_sync_test/resources/cube/cube.blend1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4496f423569b8ca81f3b3a55fad00f925557e0193fb9dbe6cdce7e71fb48f7b +size 774920 diff --git a/projects/cmd_sync_test/resources/cube/cube.glb b/projects/cmd_sync_test/resources/cube/cube.glb new file mode 100644 index 0000000000000000000000000000000000000000..66a42c65e71dcf375e04cc378256024dd3c7834d --- /dev/null +++ b/projects/cmd_sync_test/resources/cube/cube.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:198568b715f397d78f7c358c0f709a419e7fd677e54cdec7c19f71b5ed264897 +size 1194508 diff --git a/projects/cmd_sync_test/resources/cube/cube.gltf b/projects/cmd_sync_test/resources/cube/cube.gltf new file mode 100644 index 0000000000000000000000000000000000000000..428176144843dd06c78fe1d11a6392a0ea02b22d --- /dev/null +++ b/projects/cmd_sync_test/resources/cube/cube.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f82f455647a84ca6242882ae26a79a499d3ce594f8de317ab89488c5b79721ac +size 2823 diff --git a/projects/cmd_sync_test/resources/shaders/compile.bat b/projects/cmd_sync_test/resources/shaders/compile.bat new file mode 100644 index 0000000000000000000000000000000000000000..b4521235c40fe5fb163bab874560c2f219b7517f --- /dev/null +++ b/projects/cmd_sync_test/resources/shaders/compile.bat @@ -0,0 +1,3 @@ +%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv +%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv +pause \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/frag.spv b/projects/cmd_sync_test/resources/shaders/frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..087e4e22fb2fcec27d99b3ff2aa1a705fe755796 Binary files /dev/null and b/projects/cmd_sync_test/resources/shaders/frag.spv differ diff --git a/projects/cmd_sync_test/resources/shaders/shader.frag b/projects/cmd_sync_test/resources/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..71a1de69c57c0d7b7d4665095410e7acaf8dbd62 --- /dev/null +++ b/projects/cmd_sync_test/resources/shaders/shader.frag @@ -0,0 +1,14 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 passNormal; +layout(location = 1) in vec2 passUV; + +layout(location = 0) out vec3 outColor; + +layout(set=0, binding=0) uniform texture2D meshTexture; +layout(set=0, binding=1) uniform sampler textureSampler; + +void main() { + outColor = texture(sampler2D(meshTexture, textureSampler), passUV).rgb; +} \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/shader.vert b/projects/cmd_sync_test/resources/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..76855152253b48b7400f016d063ed4f0e507435e --- /dev/null +++ b/projects/cmd_sync_test/resources/shaders/shader.vert @@ -0,0 +1,19 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec2 inUV; + +layout(location = 0) out vec3 passNormal; +layout(location = 1) out vec2 passUV; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +void main() { + gl_Position = mvp * vec4(inPosition, 1.0); + passNormal = inNormal; + passUV = inUV; +} \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/vert.spv b/projects/cmd_sync_test/resources/shaders/vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..374c023e14b351eb43cbcda5951cbb8b3d6f96a1 Binary files /dev/null and b/projects/cmd_sync_test/resources/shaders/vert.spv differ diff --git a/projects/cmd_sync_test/resources/triangle/Triangle.bin b/projects/cmd_sync_test/resources/triangle/Triangle.bin new file mode 100644 index 0000000000000000000000000000000000000000..57f26ad96592b64377e6aa93823d96a94e6c5022 --- /dev/null +++ b/projects/cmd_sync_test/resources/triangle/Triangle.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:412ebd5f7242c266b4957e7e26be13aa331dbcb7bbb854ab334a2437ae8ed959 +size 104 diff --git a/projects/cmd_sync_test/resources/triangle/Triangle.blend b/projects/cmd_sync_test/resources/triangle/Triangle.blend new file mode 100644 index 0000000000000000000000000000000000000000..2421dc5e1bb029d73a9ec09cc4530c5196851fd7 --- /dev/null +++ b/projects/cmd_sync_test/resources/triangle/Triangle.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:387e544df173219fbf292a64a6656d1d782bbf71a5a9e9fdef0a308f47b05477 +size 758144 diff --git a/projects/cmd_sync_test/resources/triangle/Triangle.glb b/projects/cmd_sync_test/resources/triangle/Triangle.glb new file mode 100644 index 0000000000000000000000000000000000000000..4148620cd6af0dadbc791aa1c52bb5431a40884b --- /dev/null +++ b/projects/cmd_sync_test/resources/triangle/Triangle.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4be087a605212d139416b5352a018283b26b99260cbcddb7013a1beeb331227 +size 980 diff --git a/projects/cmd_sync_test/resources/triangle/Triangle.gltf b/projects/cmd_sync_test/resources/triangle/Triangle.gltf new file mode 100644 index 0000000000000000000000000000000000000000..a188e6ee16a5e8486cf307c7bda8cfd99bdbeea6 --- /dev/null +++ b/projects/cmd_sync_test/resources/triangle/Triangle.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5fc354e040f79cff329e919677b194c75e3a522c6406f75c1108ad9575f12ec +size 2202 diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f6e2c3fd691744460bb38019b47a16c8b724b75 --- /dev/null +++ b/projects/cmd_sync_test/src/main.cpp @@ -0,0 +1,180 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> +#include <vkcv/asset/asset_loader.hpp> + +int main(int argc, const char** argv) { + const char* applicationName = "First Mesh"; + + const int windowWidth = 800; + const int windowHeight = 600; + vkcv::Window window = vkcv::Window::create( + applicationName, + windowWidth, + windowHeight, + false + ); + + vkcv::CameraManager cameraManager(window, windowWidth, windowHeight); + + window.initEvents(); + + 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" } + ); + + vkcv::asset::Mesh mesh; + + const char* path = argc > 1 ? argv[1] : "resources/cube/cube.gltf"; + int result = vkcv::asset::loadMesh(path, mesh); + + if (result == 1) { + std::cout << "Mesh loading successful!" << std::endl; + } + else { + std::cout << "Mesh loading failed: " << result << std::endl; + return 1; + } + + assert(mesh.vertexGroups.size() > 0); + auto vertexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::VERTEX, + mesh.vertexGroups[0].vertexBuffer.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL + ); + + vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data); + + auto indexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::INDEX, + mesh.vertexGroups[0].indexBuffer.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL + ); + + indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data); + + // an example attachment for passes that output to the window + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentLayout::UNDEFINED, + vkcv::AttachmentLayout::COLOR_ATTACHMENT, + vkcv::AttachmentLayout::PRESENTATION, + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchainImageFormat() + ); + + const vkcv::AttachmentDescription depth_attachment( + vkcv::AttachmentLayout::UNDEFINED, + vkcv::AttachmentLayout::DEPTH_STENCIL_ATTACHMENT, + vkcv::AttachmentLayout::DEPTH_STENCIL_ATTACHMENT, + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + vk::Format::eD32Sfloat + ); + + vkcv::PassConfig trianglePassDefinition({ present_color_attachment, depth_attachment }); + vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition); + + if (!trianglePass) { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + vkcv::ShaderProgram triangleShaderProgram{}; + triangleShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv")); + triangleShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); + triangleShaderProgram.reflectShader(vkcv::ShaderStage::VERTEX); + triangleShaderProgram.reflectShader(vkcv::ShaderStage::FRAGMENT); + + auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes; + + std::sort(attributes.begin(), attributes.end(), [](const vkcv::VertexAttribute& x, const vkcv::VertexAttribute& y) { + return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); + }); + + vkcv::DescriptorSetConfig setConfig({ + vkcv::DescriptorBinding(vkcv::DescriptorType::IMAGE_SAMPLED, 1, vkcv::ShaderStage::FRAGMENT), + vkcv::DescriptorBinding(vkcv::DescriptorType::SAMPLER, 1, vkcv::ShaderStage::FRAGMENT) + }); + vkcv::ResourcesHandle set = core.createResourceDescription({ setConfig }); + + //only exemplary code for testing + for (int i = 0; i < 1001; i++) { + vkcv::ResourcesHandle furtherSets = core.createResourceDescription({ setConfig }); + } + //end of exemplary code + + const vkcv::PipelineConfig trianglePipelineDefinition( + triangleShaderProgram, + windowWidth, + windowHeight, + trianglePass, + mesh.vertexGroups[0].vertexBuffer.attributes, + { core.getDescriptorSetLayout(set, 0) }); + vkcv::PipelineHandle trianglePipeline = core.createGraphicsPipeline(trianglePipelineDefinition); + + if (!trianglePipeline) { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, mesh.texture_hack.w, mesh.texture_hack.h); + texture.fill(mesh.texture_hack.img); + + vkcv::SamplerHandle sampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + + std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { + { mesh.vertexGroups[0].vertexBuffer.attributes[0].offset, vertexBuffer.getHandle() }, + { mesh.vertexGroups[0].vertexBuffer.attributes[1].offset, vertexBuffer.getHandle() }, + { mesh.vertexGroups[0].vertexBuffer.attributes[2].offset, vertexBuffer.getHandle() } + }; + + vkcv::DescriptorWrites setWrites; + setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) }; + setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; + core.writeResourceDescription(set, 0, setWrites); + + const vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle(); + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + auto start = std::chrono::system_clock::now(); + while (window.isWindowOpen()) { + core.beginFrame(); + window.pollEvents(); + auto end = std::chrono::system_clock::now(); + auto deltatime = end - start; + start = end; + cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count()); + const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); + + core.renderMesh( + trianglePass, + trianglePipeline, + windowWidth, + windowHeight, + sizeof(mvp), + &mvp, + vertexBufferBindings, + indexBuffer.getHandle(), + mesh.vertexGroups[0].numIndices, + set, + 0, + { swapchainInput, depthBuffer }); + + core.endFrame(); + } + + return 0; +} diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index bd3ec34a1f017fd42639358a977a0ead9666d307..c9a43edbda136e0f1ee3f28389811f23e8c4b1a9 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -184,8 +184,8 @@ namespace vkcv const BufferHandle indexBuffer, const size_t indexCount, const vkcv::ResourcesHandle resourceHandle, - const size_t resourceDescriptorSetIndex - ) { + const size_t resourceDescriptorSetIndex, + const std::vector<ImageHandle>& renderTargets) { if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { return; @@ -193,41 +193,32 @@ namespace vkcv const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); - - const bool checkForDepthImage = ( - (!m_DepthImage) || - (width != m_ImageManager->getImageWidth(m_DepthImage)) || - (height != m_ImageManager->getImageHeight(m_DepthImage)) - ); - - if (checkForDepthImage) { - for (const auto &attachment : passConfig.attachments) { - if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) { - m_DepthImage = m_ImageManager->createImage(width, height, 1, attachment.format); - break; - } - } - } - - const vk::ImageView imageView = m_swapchainImageViews[m_currentSwapchainImageIndex]; + const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); const vk::Buffer vulkanIndexBuffer = m_BufferManager->getBuffer(indexBuffer); - std::vector<vk::ImageView> attachments; - attachments.push_back(imageView); - - if (m_DepthImage) { - attachments.push_back(m_ImageManager->getVulkanImageView(m_DepthImage)); + const vk::ImageView swapchainImageView = m_swapchainImageViews[m_currentSwapchainImageIndex]; + + std::vector<vk::ImageView> attachmentsViews; + for (const ImageHandle handle : renderTargets) { + vk::ImageView targetHandle; + if (handle.isSwapchainImage()) { + targetHandle = m_swapchainImageViews[m_currentSwapchainImageIndex]; + } + else { + targetHandle = m_ImageManager->getVulkanImageView(handle); + } + attachmentsViews.push_back(targetHandle); } - + const vk::Framebuffer framebuffer = createFramebuffer( - m_Context.getDevice(), - renderpass, - width, - height, - attachments + m_Context.getDevice(), + renderpass, + width, + height, + attachmentsViews ); m_TemporaryFramebuffers.push_back(framebuffer); diff --git a/src/vkcv/Handles.cpp b/src/vkcv/Handles.cpp index 33e0cdba7f30fe6c3576803de1d22f912c935dd0..020489418c8e2db6ce2062d6fd20f06f90a05c37 100644 --- a/src/vkcv/Handles.cpp +++ b/src/vkcv/Handles.cpp @@ -93,7 +93,7 @@ namespace vkcv { } ImageHandle ImageHandle::createSwapchainImageHandle(const HandleDestroyFunction &destroy) { - return ImageHandle(UINT64_MAX - 1, destroy); + return ImageHandle(uint64_t(UINT64_MAX - 1), destroy); } }