diff --git a/config/Sources.cmake b/config/Sources.cmake index 8fc0aa9a2605a629596e26d5eeb0772164e6ec7a..6fc477cc9552d0a9a8921151ca4435b894630755 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -50,10 +50,7 @@ set(vkcv_sources ${vkcv_include}/vkcv/QueueManager.hpp ${vkcv_source}/vkcv/QueueManager.cpp - - ${vkcv_source}/vkcv/Surface.hpp - ${vkcv_source}/vkcv/Surface.cpp - + ${vkcv_source}/vkcv/ImageLayoutTransitions.hpp ${vkcv_source}/vkcv/ImageLayoutTransitions.cpp diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index c8d69fe14379dee2677bd8a2f829348bc5289cf0..0a50765fedb07f1117b5e0ecaa43c03b362c23ce 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -56,13 +56,12 @@ namespace vkcv * * @param context encapsulates various Vulkan objects */ - Core(Context &&context, Window &window, SwapChain swapChain, std::vector<vk::ImageView> imageViews, + Core(Context &&context, Window &window, const SwapChain& swapChain, std::vector<vk::ImageView> imageViews, const CommandResources& commandResources, const SyncResources& syncResources) noexcept; // explicit destruction of default constructor Core() = delete; Result acquireSwapchainImage(); - void destroyTemporaryFramebuffers(); Context m_Context; @@ -80,16 +79,12 @@ namespace vkcv CommandResources m_CommandResources; SyncResources m_SyncResources; uint32_t m_currentSwapchainImageIndex; - std::vector<vk::Framebuffer> m_TemporaryFramebuffers; - + ImageHandle m_DepthImage; - /** - * recreates the swapchain - * @param[in] width new window width - * @param[in] height new window hight - */ - static void recreateSwapchain(int width, int height); + std::function<void(int, int)> e_resizeHandle; + + static std::vector<vk::ImageView> createImageViews( Context &context, SwapChain& swapChain); public: /** @@ -230,14 +225,12 @@ namespace vkcv * @brief render a beautiful triangle */ void renderMesh( - const PassHandle renderpassHandle, - const PipelineHandle pipelineHandle, - const uint32_t width, - const uint32_t height, + const PassHandle &renderpassHandle, + const PipelineHandle &pipelineHandle, const size_t pushConstantSize, const void* pushConstantData, const std::vector<VertexBufferBinding> &vertexBufferBindings, - const BufferHandle indexBuffer, + const BufferHandle &indexBuffer, const size_t indexCount, const vkcv::ResourcesHandle resourceHandle, const size_t resourceDescriptorSetIndex); diff --git a/include/vkcv/SwapChain.hpp b/include/vkcv/SwapChain.hpp index 1087d6364f6f811b741904d4e2b31fcfeb450901..53f7b783051307c7d327f20f389d7bef0fb9a16c 100644 --- a/include/vkcv/SwapChain.hpp +++ b/include/vkcv/SwapChain.hpp @@ -3,15 +3,32 @@ #include "Context.hpp" #include "vkcv/Window.hpp" -namespace vkcv { +#include <atomic> + +namespace vkcv +{ class SwapChain final { private: - vk::SurfaceKHR m_surface; - vk::SwapchainKHR m_swapchain; - vk::SurfaceFormatKHR m_format; + struct Surface + { + vk::SurfaceKHR handle; + std::vector<vk::SurfaceFormatKHR> formats; + vk::SurfaceCapabilitiesKHR capabilities; + std::vector<vk::PresentModeKHR> presentModes; + }; + + Surface m_Surface; - uint32_t m_ImageCount; + vk::SwapchainKHR m_Swapchain; + vk::Format m_SwapchainFormat; + vk::ColorSpaceKHR m_SwapchainColorSpace; + vk::PresentModeKHR m_SwapchainPresentMode; + uint32_t m_SwapchainImageCount; + + vk::Extent2D m_Extent; + + std::atomic<bool> m_RecreationRequired; /** * Constructor of a SwapChain object @@ -21,11 +38,17 @@ namespace vkcv { * @param swapchain to show images in the window * @param format */ - SwapChain(vk::SurfaceKHR surface, vk::SwapchainKHR swapchain, vk::SurfaceFormatKHR format, uint32_t imageCount); + // TODO: + SwapChain(const Surface &surface, + vk::SwapchainKHR swapchain, + vk::Format format, + vk::ColorSpaceKHR colorSpace, + vk::PresentModeKHR presentMode, + uint32_t imageCount, + vk::Extent2D extent) noexcept; public: - SwapChain(const SwapChain &other) = default; - SwapChain(SwapChain &&other) = default; + SwapChain(const SwapChain& other); /** * @return The swapchain linked with the #SwapChain class @@ -39,13 +62,14 @@ namespace vkcv { * @return current surface */ [[nodiscard]] - vk::SurfaceKHR getSurface(); + vk::SurfaceKHR getSurface() const; + /** - * gets the current surface format - * @return gets the surface format + * gets the chosen swapchain format + * @return gets the chosen swapchain format */ [[nodiscard]] - vk::SurfaceFormatKHR getSurfaceFormat(); + vk::Format getSwapchainFormat() const; /** * creates a swap chain object out of the given window and the given context @@ -53,7 +77,7 @@ namespace vkcv { * @param context of the application * @return returns an object of swapChain */ - static SwapChain create(const Window &window, const Context &context, const vk::SurfaceKHR surface); + static SwapChain create(const Window &window, const Context &context); /** * Destructor of SwapChain @@ -64,6 +88,34 @@ namespace vkcv { * @return number of images in swapchain */ uint32_t getImageCount(); - }; + + /** + * TODO + * + * @return + */ + bool shouldUpdateSwapchain() const; + /** + * TODO + * + * context + * window + */ + void updateSwapchain(const Context &context, const Window &window); + + /** + * + */ + void recreateSwapchain(); + + /** + * TODO + * + * @return + */ + [[nodiscard]] + const vk::Extent2D& getExtent() const; + + }; } diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp index 7428c7c73eb481f7352821faed36257211dfd5bf..f71671c935a0a5e17bb517c726d75ffff2973532 100644 --- a/include/vkcv/Window.hpp +++ b/include/vkcv/Window.hpp @@ -17,7 +17,6 @@ namespace vkcv { private: GLFWwindow *m_window; - /** * * @param GLFWwindow of the class diff --git a/modules/camera/include/vkcv/camera/Camera.hpp b/modules/camera/include/vkcv/camera/Camera.hpp index 7e177b9a2fbde0890e0c8ea6a1d9a19d6e277c7c..ff8fda811eaad7a99dbb940601f9e5904025255e 100644 --- a/modules/camera/include/vkcv/camera/Camera.hpp +++ b/modules/camera/include/vkcv/camera/Camera.hpp @@ -63,7 +63,7 @@ namespace vkcv { void changeFov(double fov); - void updateRatio(float ratio); + void updateRatio(int width, int height); float getRatio() const; diff --git a/modules/camera/include/vkcv/camera/CameraManager.hpp b/modules/camera/include/vkcv/camera/CameraManager.hpp index 9511b752e972afb1e10f41a118433a4e8933fd65..4e52eccea25e8544a9a5cc89d0dc74ddd0e023c6 100644 --- a/modules/camera/include/vkcv/camera/CameraManager.hpp +++ b/modules/camera/include/vkcv/camera/CameraManager.hpp @@ -9,10 +9,11 @@ namespace vkcv{ class CameraManager{ private: - std::function<void(int, int, int, int)> m_keyHandle; - std::function<void(double, double)> m_mouseMoveHandle; - std::function<void(double, double)> m_mouseScrollHandle; - std::function<void(int, int, int)> m_mouseButtonHandle; + std::function<void(int, int, int, int)> e_keyHandle; + std::function<void(double, double)> e_mouseMoveHandle; + std::function<void(double, double)> e_mouseScrollHandle; + std::function<void(int, int, int)> e_mouseButtonHandle; + std::function<void(int, int)> e_resizeHandle; Window &m_window; Camera m_camera; @@ -29,6 +30,7 @@ namespace vkcv{ void scrollCallback( double offsetX, double offsetY); void mouseMoveCallback( double offsetX, double offsetY); void mouseButtonCallback(int button, int action, int mods); + void resizeCallback(int width, int height); public: CameraManager(Window &window, float width, float height, glm::vec3 up = glm::vec3(0.0f,-1.0f,0.0f), glm::vec3 position = glm::vec3(0.0f,0.0f,0.0f)); diff --git a/modules/camera/src/vkcv/camera/Camera.cpp b/modules/camera/src/vkcv/camera/Camera.cpp index bc8a8498e67a6bd751f5a6ed1d4c4fba0279a68d..b1d7381e3d548c9edf5d41e8d084c7edb1d02647 100644 --- a/modules/camera/src/vkcv/camera/Camera.cpp +++ b/modules/camera/src/vkcv/camera/Camera.cpp @@ -82,8 +82,10 @@ namespace vkcv { setFov(fov); } - void Camera::updateRatio( float ratio){ - m_ratio = ratio; + void Camera::updateRatio( int width, int height){ + m_width = width; + m_height = height; + m_ratio = static_cast<float>(width)/glm::max(height, 1); setPerspective( m_fov, m_ratio, m_near, m_far); } diff --git a/modules/camera/src/vkcv/camera/CameraManager.cpp b/modules/camera/src/vkcv/camera/CameraManager.cpp index 18f499a2b34b64c1442c5d9e267d6476b8d69199..2631890d646fbf27a4fbb14cfeef706678d8918c 100644 --- a/modules/camera/src/vkcv/camera/CameraManager.cpp +++ b/modules/camera/src/vkcv/camera/CameraManager.cpp @@ -15,10 +15,11 @@ namespace vkcv{ } void CameraManager::bindCamera(){ - m_keyHandle = m_window.e_key.add( [&](int key, int scancode, int action, int mods) { this->keyCallback(key, scancode, action, mods); }); - m_mouseMoveHandle = m_window.e_mouseMove.add( [&]( double offsetX, double offsetY) {this->mouseMoveCallback( offsetX, offsetY);} ); - m_mouseScrollHandle = m_window.e_mouseScroll.add([&](double offsetX, double offsetY) {this->scrollCallback( offsetX, offsetY);} ); - m_mouseButtonHandle = m_window.e_mouseButton.add([&] (int button, int action, int mods) {this->mouseButtonCallback( button, action, mods);}); + e_keyHandle = m_window.e_key.add( [&](int key, int scancode, int action, int mods) { this->keyCallback(key, scancode, action, mods); }); + e_mouseMoveHandle = m_window.e_mouseMove.add( [&]( double offsetX, double offsetY) {this->mouseMoveCallback( offsetX, offsetY);} ); + e_mouseScrollHandle = m_window.e_mouseScroll.add([&](double offsetX, double offsetY) {this->scrollCallback( offsetX, offsetY);} ); + e_mouseButtonHandle = m_window.e_mouseButton.add([&] (int button, int action, int mods) {this->mouseButtonCallback( button, action, mods);}); + e_resizeHandle = m_window.e_resize.add([&] (int width, int height) {this->resizeCallback( width, height);}); } void CameraManager::mouseButtonCallback(int button, int action, int mods){ @@ -75,6 +76,11 @@ namespace vkcv{ break; } } + + void CameraManager::resizeCallback(int width, int height){ + m_camera.updateRatio(width, height); + } + Camera &CameraManager::getCamera(){ return m_camera; } diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 306aa524262325b993ade46eaba4b8d989400c51..01d8b74fe39a15459169926645f429805299a786 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -8,16 +8,14 @@ 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 + 800, + 600, + true ); - vkcv::CameraManager cameraManager(window, windowWidth, windowHeight); + vkcv::CameraManager cameraManager(window, static_cast<float>(window.getWidth()), static_cast<float>(window.getHeight())); window.initEvents(); @@ -43,7 +41,7 @@ int main(int argc, const char** argv) { return 1; } - assert(mesh.vertexGroups.size() > 0); + assert(!mesh.vertexGroups.empty()); auto vertexBuffer = core.createBuffer<uint8_t>( vkcv::BufferType::VERTEX, mesh.vertexGroups[0].vertexBuffer.data.size(), @@ -112,9 +110,9 @@ int main(int argc, const char** argv) { //end of exemplary code const vkcv::PipelineConfig trianglePipelineDefinition( - triangleShaderProgram, - windowWidth, - windowHeight, + triangleShaderProgram, + UINT32_MAX, + UINT32_MAX, trianglePass, mesh.vertexGroups[0].vertexBuffer.attributes, { core.getDescriptorSetLayout(set, 0) }); @@ -148,8 +146,12 @@ int main(int argc, const char** argv) { auto start = std::chrono::system_clock::now(); while (window.isWindowOpen()) { + vkcv::Window::pollEvents(); + + if(window.getHeight() == 0 || window.getWidth() == 0) + continue; + core.beginFrame(); - window.pollEvents(); auto end = std::chrono::system_clock::now(); auto deltatime = end - start; start = end; @@ -159,8 +161,6 @@ int main(int argc, const char** argv) { core.renderMesh( trianglePass, trianglePipeline, - windowWidth, - windowHeight, sizeof(mvp), &mvp, vertexBufferBindings, diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 2c071b727f7e41e7eb4dee17a2da3302f615ffa0..397498e60375ee34497b60fef7d27cbb2c0c7989 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -147,8 +147,6 @@ int main(int argc, const char** argv) { core.renderMesh( trianglePass, trianglePipeline, - windowWidth, - windowHeight, sizeof(mvp), &mvp, vertexBufferBindings, diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index bd3ec34a1f017fd42639358a977a0ead9666d307..27e84ee5cdb062adc0e9f96cdfa7e761e6f24279 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -13,7 +13,6 @@ #include "SamplerManager.hpp" #include "ImageManager.hpp" #include "DescriptorManager.hpp" -#include "Surface.hpp" #include "ImageLayoutTransitions.hpp" namespace vkcv @@ -32,40 +31,11 @@ namespace vkcv instanceExtensions, deviceExtensions ); - - const vk::SurfaceKHR surface = createSurface( - window.getWindow(), - context.getInstance(), - context.getPhysicalDevice() - ); - SwapChain swapChain = SwapChain::create(window, context, surface); + SwapChain swapChain = SwapChain::create(window, context); - std::vector<vk::Image> swapChainImages = context.getDevice().getSwapchainImagesKHR(swapChain.getSwapchain()); std::vector<vk::ImageView> imageViews; - imageViews.reserve( swapChainImages.size() ); - //here can be swizzled with vk::ComponentSwizzle if needed - vk::ComponentMapping componentMapping( - vk::ComponentSwizzle::eR, - vk::ComponentSwizzle::eG, - vk::ComponentSwizzle::eB, - vk::ComponentSwizzle::eA ); - - vk::ImageSubresourceRange subResourceRange( vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1 ); - - for ( auto image : swapChainImages ) - { - vk::ImageViewCreateInfo imageViewCreateInfo( - vk::ImageViewCreateFlags(), - image, - vk::ImageViewType::e2D, - swapChain.getSurfaceFormat().format, - componentMapping, - subResourceRange - ); - - imageViews.push_back(context.getDevice().createImageView(imageViewCreateInfo)); - } + imageViews = createImageViews( context, swapChain); const auto& queueManager = context.getQueueManager(); @@ -74,10 +44,6 @@ namespace vkcv const auto commandResources = createCommandResources(context.getDevice(), queueFamilySet); const auto defaultSyncResources = createSyncResources(context.getDevice()); - window.e_resize.add([&](int width, int height){ - recreateSwapchain(width,height); - }); - return Core(std::move(context) , window, swapChain, imageViews, commandResources, defaultSyncResources); } @@ -86,7 +52,7 @@ namespace vkcv return m_Context; } - Core::Core(Context &&context, Window &window , SwapChain swapChain, std::vector<vk::ImageView> imageViews, + Core::Core(Context &&context, Window &window, const SwapChain& swapChain, std::vector<vk::ImageView> imageViews, const CommandResources& commandResources, const SyncResources& syncResources) noexcept : m_Context(std::move(context)), m_window(window), @@ -105,6 +71,10 @@ namespace vkcv m_BufferManager->init(); m_ImageManager->m_core = this; + + e_resizeHandle = window.e_resize.add( [&](int width, int height) { + m_swapchain.recreateSwapchain(); + }); } Core::~Core() noexcept { @@ -115,7 +85,6 @@ namespace vkcv destroyCommandResources(m_Context.getDevice(), m_CommandResources); destroySyncResources(m_Context.getDevice(), m_SyncResources); - destroyTemporaryFramebuffers(); m_Context.m_Device.destroySwapchainKHR(m_swapchain.getSwapchain()); m_Context.m_Instance.destroySurfaceKHR(m_swapchain.getSurface()); @@ -144,6 +113,7 @@ namespace vkcv ); if (acquireResult != vk::Result::eSuccess) { + std::cerr << vk::to_string(acquireResult) << std::endl; return Result::ERROR; } @@ -151,37 +121,33 @@ namespace vkcv return Result::SUCCESS; } - void Core::destroyTemporaryFramebuffers() { - for (const vk::Framebuffer f : m_TemporaryFramebuffers) { - m_Context.getDevice().destroyFramebuffer(f); - } - m_TemporaryFramebuffers.clear(); - } - void Core::beginFrame() { + if (m_swapchain.shouldUpdateSwapchain()) { + m_Context.getDevice().waitIdle(); + + for (auto image : m_swapchainImageViews) + m_Context.m_Device.destroyImageView(image); + + m_swapchain.updateSwapchain(m_Context, m_window); + m_swapchainImageViews = createImageViews(m_Context, m_swapchain); + } + if (acquireSwapchainImage() != Result::SUCCESS) { - return; + std::cerr << "Acquire failed!" << std::endl; + + m_currentSwapchainImageIndex = std::numeric_limits<uint32_t>::max(); } - m_Context.getDevice().waitIdle(); // FIMXE: this is a sin against graphics programming, but its getting late - Alex - destroyTemporaryFramebuffers(); - } - - vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass& renderpass, - const int width, const int height, const std::vector<vk::ImageView>& attachments) { - const vk::FramebufferCreateFlags flags = {}; - const vk::FramebufferCreateInfo createInfo(flags, renderpass, attachments.size(), attachments.data(), width, height, 1); - return device.createFramebuffer(createInfo); + + m_Context.getDevice().waitIdle(); // TODO: this is a sin against graphics programming, but its getting late - Alex } void Core::renderMesh( - const PassHandle renderpassHandle, - const PipelineHandle pipelineHandle, - const uint32_t width, - const uint32_t height, - const size_t pushConstantSize, + const PassHandle &renderpassHandle, + const PipelineHandle &pipelineHandle, + const size_t pushConstantSize, const void *pushConstantData, const std::vector<VertexBufferBinding>& vertexBufferBindings, - const BufferHandle indexBuffer, + const BufferHandle &indexBuffer, const size_t indexCount, const vkcv::ResourcesHandle resourceHandle, const size_t resourceDescriptorSetIndex @@ -190,6 +156,11 @@ namespace vkcv if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { return; } + + const vk::Extent2D& extent = m_swapchain.getExtent(); + + const uint32_t width = extent.width; + const uint32_t height = extent.height; const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); @@ -212,6 +183,7 @@ namespace vkcv 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 vkcv::PipelineConfig pipelineConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); const vk::Buffer vulkanIndexBuffer = m_BufferManager->getBuffer(indexBuffer); @@ -222,15 +194,25 @@ namespace vkcv attachments.push_back(m_ImageManager->getVulkanImageView(m_DepthImage)); } - const vk::Framebuffer framebuffer = createFramebuffer( - m_Context.getDevice(), - renderpass, - width, - height, - attachments - ); - - m_TemporaryFramebuffers.push_back(framebuffer); + vk::Framebuffer framebuffer = nullptr; + const vk::FramebufferCreateInfo createInfo({}, + renderpass, + static_cast<uint32_t>(attachments.size()), + attachments.data(), + width, + height, + 1); + if(m_Context.m_Device.createFramebuffer(&createInfo, nullptr, &framebuffer) != vk::Result::eSuccess) + { + std::cout << "FAILED TO CREATE TEMPORARY FRAMEBUFFER!" << std::endl; + return; + } + + vk::Viewport dynamicViewport(0.0f, 0.0f, + static_cast<float>(width), static_cast<float>(height), + 0.0f, 1.0f); + + vk::Rect2D dynamicScissor({0, 0}, {width, height}); auto &bufferManager = m_BufferManager; @@ -238,48 +220,61 @@ namespace vkcv submitInfo.queueType = QueueType::Graphics; submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; - submitCommands(submitInfo, [&](const vk::CommandBuffer& cmdBuffer) { - std::vector<vk::ClearValue> clearValues; - - for (const auto& attachment : passConfig.attachments) { - if (attachment.load_operation == AttachmentOperation::CLEAR) { - float clear = 0.0f; - - if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) { - clear = 1.0f; - } - - clearValues.emplace_back(std::array<float, 4>{ - clear, - clear, - clear, - 1.f - }); - } - } - - const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data()); - const vk::SubpassContents subpassContents = {}; - cmdBuffer.beginRenderPass(beginInfo, subpassContents, {}); - - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); + auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { + std::vector<vk::ClearValue> clearValues; + + for (const auto& attachment : passConfig.attachments) { + if (attachment.load_operation == AttachmentOperation::CLEAR) { + float clear = 0.0f; + + if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) { + clear = 1.0f; + } + + clearValues.emplace_back(std::array<float, 4>{ + clear, + clear, + clear, + 1.f + }); + } + } + + const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data()); + const vk::SubpassContents subpassContents = {}; + cmdBuffer.beginRenderPass(beginInfo, subpassContents, {}); + + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); + + if(pipelineConfig.m_Height == UINT32_MAX && pipelineConfig.m_Width == UINT32_MAX) + { + cmdBuffer.setViewport(0, 1, &dynamicViewport); + cmdBuffer.setScissor(0, 1, &dynamicScissor); + } + + for (uint32_t i = 0; i < vertexBufferBindings.size(); i++) { + const auto &vertexBinding = vertexBufferBindings[i]; + const auto vertexBuffer = bufferManager->getBuffer(vertexBinding.buffer); + cmdBuffer.bindVertexBuffers(i, (vertexBuffer), (vertexBinding.offset)); + } + + if (resourceHandle) { + const vk::DescriptorSet descriptorSet = m_DescriptorManager->getDescriptorSet(resourceHandle, resourceDescriptorSetIndex); + cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, descriptorSet, nullptr); + } + + cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size + cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData); + cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {}); + cmdBuffer.endRenderPass(); + }; + + auto finishFunction = [&]() + { + m_Context.m_Device.destroy(framebuffer); + }; - for (uint32_t i = 0; i < vertexBufferBindings.size(); i++) { - const auto &vertexBinding = vertexBufferBindings[i]; - const auto vertexBuffer = bufferManager->getBuffer(vertexBinding.buffer); - cmdBuffer.bindVertexBuffers(i, (vertexBuffer), (vertexBinding.offset)); - } - - if (resourceHandle) { - const vk::DescriptorSet descriptorSet = m_DescriptorManager->getDescriptorSet(resourceHandle, resourceDescriptorSetIndex); - cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, descriptorSet, nullptr); - } - - cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size - cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData); - cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {}); - cmdBuffer.endRenderPass(); - }, nullptr); + submitCommands(submitInfo, submitFunction, finishFunction); } void Core::endFrame() { @@ -288,8 +283,7 @@ namespace vkcv } const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain()); - const vk::Image presentImage = swapchainImages[m_currentSwapchainImageIndex]; - + const auto& queueManager = m_Context.getQueueManager(); std::array<vk::Semaphore, 2> waitSemaphores{ m_SyncResources.renderFinished, @@ -309,13 +303,8 @@ namespace vkcv } vk::Format Core::getSwapchainImageFormat() { - return m_swapchain.getSurfaceFormat().format; + return m_swapchain.getSwapchainFormat(); } - - void Core::recreateSwapchain(int width, int height) { - /* boilerplate for #34 */ - std::cout << "Resized to : " << width << " , " << height << std::endl; - } void Core::submitCommands(const SubmitInfo &submitInfo, const RecordCommandFunction& record, const FinishCommandFunction& finish) { @@ -369,4 +358,33 @@ namespace vkcv vk::DescriptorSetLayout Core::getDescriptorSetLayout(ResourcesHandle handle, size_t setIndex) { return m_DescriptorManager->getDescriptorSetLayout(handle, setIndex); } + + std::vector<vk::ImageView> Core::createImageViews( Context &context, SwapChain& swapChain){ + std::vector<vk::ImageView> imageViews; + std::vector<vk::Image> swapChainImages = context.getDevice().getSwapchainImagesKHR(swapChain.getSwapchain()); + imageViews.reserve( swapChainImages.size() ); + //here can be swizzled with vk::ComponentSwizzle if needed + vk::ComponentMapping componentMapping( + vk::ComponentSwizzle::eR, + vk::ComponentSwizzle::eG, + vk::ComponentSwizzle::eB, + vk::ComponentSwizzle::eA ); + + vk::ImageSubresourceRange subResourceRange( vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1 ); + + for ( auto image : swapChainImages ) + { + vk::ImageViewCreateInfo imageViewCreateInfo( + vk::ImageViewCreateFlags(), + image, + vk::ImageViewType::e2D, + swapChain.getSwapchainFormat(), + componentMapping, + subResourceRange + ); + + imageViews.push_back(context.getDevice().createImageView(imageViewCreateInfo)); + } + return imageViews; + } } diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp index 1b866c05d4a12c9bf28d08178438cb3a1ff70a3c..16b08b7a5127769a19b7e0abe47b61f58406bafe 100644 --- a/src/vkcv/PipelineManager.cpp +++ b/src/vkcv/PipelineManager.cpp @@ -5,7 +5,8 @@ namespace vkcv PipelineManager::PipelineManager(vk::Device device) noexcept : m_Device{device}, - m_Pipelines{} + m_Pipelines{}, + m_Configs{} {} PipelineManager::~PipelineManager() noexcept @@ -94,8 +95,8 @@ namespace vkcv //FIXME: hoping that order is the same and compatible: add explicit mapping and validation const VertexAttribute attribute = config.m_vertexAttributes[i]; - vertexAttributeDescriptions.push_back({location, binding, vertexFormatToVulkanFormat(attachment.format), 0}); - vertexBindingDescriptions.push_back(vk::VertexInputBindingDescription( + vertexAttributeDescriptions.emplace_back(location, binding, vertexFormatToVulkanFormat(attachment.format), 0); + vertexBindingDescriptions.emplace_back(vk::VertexInputBindingDescription( binding, attribute.stride + getFormatSize(attachment.format), vk::VertexInputRate::eVertex)); @@ -211,8 +212,19 @@ namespace vkcv break; } } - - // graphics pipeline create + + std::vector<vk::DynamicState> dynamicStates = {}; + if(config.m_Width == UINT32_MAX && config.m_Height == UINT32_MAX) + { + dynamicStates.push_back(vk::DynamicState::eViewport); + dynamicStates.push_back(vk::DynamicState::eScissor); + } + + vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo({}, + static_cast<uint32_t>(dynamicStates.size()), + dynamicStates.data()); + + // graphics pipeline create std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo }; const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo( {}, @@ -226,7 +238,7 @@ namespace vkcv &pipelineMultisampleStateCreateInfo, p_depthStencilCreateInfo, &pipelineColorBlendStateCreateInfo, - nullptr, + &dynamicStateCreateInfo, vkPipelineLayout, pass, 0, @@ -247,6 +259,7 @@ namespace vkcv const uint64_t id = m_Pipelines.size(); m_Pipelines.push_back({ vkPipeline, vkPipelineLayout }); + m_Configs.push_back(config); return PipelineHandle(id, [&](uint64_t id) { destroyPipelineById(id); }); } @@ -293,5 +306,11 @@ namespace vkcv pipeline.m_layout = nullptr; } } - + + const PipelineConfig &PipelineManager::getPipelineConfig(const PipelineHandle &handle) const + { + const uint64_t id = handle.getId(); + return m_Configs.at(id); + } + } \ No newline at end of file diff --git a/src/vkcv/PipelineManager.hpp b/src/vkcv/PipelineManager.hpp index 950df0be2d8edf3037c93e8522215bfa740d033d..e243151f7248c07fa0287bb2eaf698e5080f7f61 100644 --- a/src/vkcv/PipelineManager.hpp +++ b/src/vkcv/PipelineManager.hpp @@ -18,6 +18,7 @@ namespace vkcv vk::Device m_Device; std::vector<Pipeline> m_Pipelines; + std::vector<PipelineConfig> m_Configs; void destroyPipelineById(uint64_t id); @@ -36,7 +37,11 @@ namespace vkcv [[nodiscard]] vk::Pipeline getVkPipeline(const PipelineHandle &handle) const; + [[nodiscard]] vk::PipelineLayout getVkPipelineLayout(const PipelineHandle &handle) const; + + [[nodiscard]] + const PipelineConfig &getPipelineConfig(const PipelineHandle &handle) const; }; } diff --git a/src/vkcv/Surface.cpp b/src/vkcv/Surface.cpp deleted file mode 100644 index 29b6c646dc212cba2cc31f32dca5c4fcc023cd03..0000000000000000000000000000000000000000 --- a/src/vkcv/Surface.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "Surface.hpp" - -#define GLFW_INCLUDE_VULKAN -#include <GLFW/glfw3.h> - -namespace vkcv { - /** - * creates surface and checks availability - * @param window current window for the surface - * @param instance Vulkan-Instance - * @param physicalDevice Vulkan-PhysicalDevice - * @return created surface - */ - vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice) { - //create surface - VkSurfaceKHR surface; - if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &surface) != VK_SUCCESS) { - throw std::runtime_error("failed to create a window surface!"); - } - vk::Bool32 surfaceSupport = false; - if (physicalDevice.getSurfaceSupportKHR(0, vk::SurfaceKHR(surface), &surfaceSupport) != vk::Result::eSuccess && surfaceSupport != true) { - throw std::runtime_error("surface is not supported by the device!"); - } - - return vk::SurfaceKHR(surface); - } -} diff --git a/src/vkcv/Surface.hpp b/src/vkcv/Surface.hpp deleted file mode 100644 index 74aafeba821334767ac5e13cd33e1d9674e12f5b..0000000000000000000000000000000000000000 --- a/src/vkcv/Surface.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include <vulkan/vulkan.hpp> - -struct GLFWwindow; - -namespace vkcv { - vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice); -} \ No newline at end of file diff --git a/src/vkcv/SwapChain.cpp b/src/vkcv/SwapChain.cpp index 3483ae37e718453a99d56d31e025433acb7f4422..39c310de60db2c3678749f142c926a26ac127b58 100644 --- a/src/vkcv/SwapChain.cpp +++ b/src/vkcv/SwapChain.cpp @@ -1,29 +1,70 @@ #include <vkcv/SwapChain.hpp> +#include <utility> -namespace vkcv { +#define GLFW_INCLUDE_VULKAN +#include <GLFW/glfw3.h> - SwapChain::SwapChain(vk::SurfaceKHR surface, vk::SwapchainKHR swapchain, vk::SurfaceFormatKHR format, uint32_t imageCount) - : m_surface(surface), m_swapchain(swapchain), m_format( format), m_ImageCount(imageCount) +namespace vkcv +{ + /** + * creates surface and checks availability + * @param window current window for the surface + * @param instance Vulkan-Instance + * @param physicalDevice Vulkan-PhysicalDevice + * @return created surface + */ + vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice) { + //create surface + VkSurfaceKHR surface; + if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &surface) != VK_SUCCESS) { + throw std::runtime_error("failed to create a window surface!"); + } + vk::Bool32 surfaceSupport = false; + if (physicalDevice.getSurfaceSupportKHR(0, vk::SurfaceKHR(surface), &surfaceSupport) != vk::Result::eSuccess && surfaceSupport != true) { + throw std::runtime_error("surface is not supported by the device!"); + } + + return vk::SurfaceKHR(surface); + } + + SwapChain::SwapChain(const Surface &surface, + vk::SwapchainKHR swapchain, + vk::Format format, + vk::ColorSpaceKHR colorSpace, + vk::PresentModeKHR presentMode, + uint32_t imageCount, + vk::Extent2D extent) noexcept : + m_Surface(surface), + m_Swapchain(swapchain), + m_SwapchainFormat(format), + m_SwapchainColorSpace(colorSpace), + m_SwapchainPresentMode(presentMode), + m_SwapchainImageCount(imageCount), + m_Extent(extent), + m_RecreationRequired(false) {} + + SwapChain::SwapChain(const SwapChain &other) : + m_Surface(other.m_Surface), + m_Swapchain(other.m_Swapchain), + m_SwapchainFormat(other.m_SwapchainFormat), + m_SwapchainColorSpace(other.m_SwapchainColorSpace), + m_SwapchainPresentMode(other.m_SwapchainPresentMode), + m_SwapchainImageCount(other.m_SwapchainImageCount), + m_Extent(other.m_Extent), + m_RecreationRequired(other.m_RecreationRequired.load()) + {} const vk::SwapchainKHR& SwapChain::getSwapchain() const { - return m_swapchain; + return m_Swapchain; } - /** - * gets surface of the swapchain - * @return current surface - */ - vk::SurfaceKHR SwapChain::getSurface() { - return m_surface; + vk::SurfaceKHR SwapChain::getSurface() const { + return m_Surface.handle; } - /** - * gets the surface of the swapchain - * @return chosen format - */ - vk::SurfaceFormatKHR SwapChain::getSurfaceFormat(){ - return m_format; + vk::Format SwapChain::getSwapchainFormat() const{ + return m_SwapchainFormat; } /** @@ -33,7 +74,7 @@ namespace vkcv { * @param window of the current application * @return chosen Extent for the surface */ - vk::Extent2D chooseSwapExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window){ + vk::Extent2D chooseExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window){ vk::SurfaceCapabilitiesKHR surfaceCapabilities; if(physicalDevice.getSurfaceCapabilitiesKHR(surface,&surfaceCapabilities) != vk::Result::eSuccess){ throw std::runtime_error("cannot get surface capabilities. There is an issue with the surface."); @@ -43,15 +84,10 @@ namespace vkcv { static_cast<uint32_t>(window.getWidth()), static_cast<uint32_t>(window.getHeight()) }; + extent2D.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, extent2D.width)); extent2D.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, extent2D.height)); - if (extent2D.width > surfaceCapabilities.maxImageExtent.width || - extent2D.width < surfaceCapabilities.minImageExtent.width || - extent2D.height > surfaceCapabilities.maxImageExtent.height || - extent2D.height < surfaceCapabilities.minImageExtent.height) { - std::printf("Surface size not matching. Resizing to allowed value."); - } return extent2D; } @@ -61,7 +97,7 @@ namespace vkcv { * @param surface of the swapchain * @return available Format */ - vk::SurfaceFormatKHR chooseSwapSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { + vk::SurfaceFormatKHR chooseSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { uint32_t formatCount; physicalDevice.getSurfaceFormatsKHR(surface, &formatCount, nullptr); std::vector<vk::SurfaceFormatKHR> availableFormats(formatCount); @@ -126,23 +162,29 @@ namespace vkcv { * @param context that keeps instance, physicalDevice and a device. * @return swapchain */ - SwapChain SwapChain::create(const Window &window, const Context &context, const vk::SurfaceKHR surface) { + SwapChain SwapChain::create(const Window &window, const Context &context) { const vk::Instance& instance = context.getInstance(); const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice(); const vk::Device& device = context.getDevice(); - vk::Extent2D extent2D = chooseSwapExtent(physicalDevice, surface, window); - vk::SurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(physicalDevice, surface); - vk::PresentModeKHR presentMode = choosePresentMode(physicalDevice, surface); - uint32_t imageCount = chooseImageCount(physicalDevice, surface); + Surface surface; + surface.handle = createSurface(window.getWindow(), instance, physicalDevice); + surface.formats = physicalDevice.getSurfaceFormatsKHR(surface.handle); + surface.capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.handle); + surface.presentModes = physicalDevice.getSurfacePresentModesKHR(surface.handle); + + vk::Extent2D chosenExtent = chooseExtent(physicalDevice, surface.handle, window); + vk::SurfaceFormatKHR chosenSurfaceFormat = chooseSurfaceFormat(physicalDevice, surface.handle); + vk::PresentModeKHR chosenPresentMode = choosePresentMode(physicalDevice, surface.handle); + uint32_t chosenImageCount = chooseImageCount(physicalDevice, surface.handle); vk::SwapchainCreateInfoKHR swapchainCreateInfo( vk::SwapchainCreateFlagsKHR(), //flags - surface, // surface - imageCount, // minImageCount TODO: how many do we need for our application?? "must be less than or equal to the value returned in maxImageCount" -> 3 for Triple Buffering, else 2 for Double Buffering (should be the standard) - surfaceFormat.format, // imageFormat - surfaceFormat.colorSpace, // imageColorSpace - extent2D, // imageExtent + surface.handle, // surface + chosenImageCount, // minImageCount TODO: how many do we need for our application?? "must be less than or equal to the value returned in maxImageCount" -> 3 for Triple Buffering, else 2 for Double Buffering (should be the standard) + chosenSurfaceFormat.format, // imageFormat + chosenSurfaceFormat.colorSpace, // imageColorSpace + chosenExtent, // imageExtent 1, // imageArrayLayers TODO: should we only allow non-stereoscopic applications? yes -> 1, no -> ? "must be greater than 0, less or equal to maxImageArrayLayers" vk::ImageUsageFlagBits::eColorAttachment, // imageUsage TODO: what attachments? only color? depth? vk::SharingMode::eExclusive, // imageSharingMode TODO: which sharing mode? "VK_SHARING_MODE_EXCLUSIV access exclusive to a single queue family, better performance", "VK_SHARING_MODE_CONCURRENT access from multiple queues" @@ -150,22 +192,71 @@ namespace vkcv { nullptr, // pQueueFamilyIndices, the pointer to an array of queue family indices having access to the images(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT vk::SurfaceTransformFlagBitsKHR::eIdentity, // preTransform, transformations applied onto the image before display vk::CompositeAlphaFlagBitsKHR::eOpaque, // compositeAlpha, TODO: how to handle transparent pixels? do we need transparency? If no -> opaque - presentMode, // presentMode + chosenPresentMode, // presentMode true, // clipped nullptr // oldSwapchain ); vk::SwapchainKHR swapchain = device.createSwapchainKHR(swapchainCreateInfo); - return SwapChain(surface, swapchain, surfaceFormat, imageCount); + return SwapChain(surface, + swapchain, + chosenSurfaceFormat.format, + chosenSurfaceFormat.colorSpace, + chosenPresentMode, + chosenImageCount, + chosenExtent); + } + + bool SwapChain::shouldUpdateSwapchain() const { + return m_RecreationRequired; + } + + void SwapChain::updateSwapchain(const Context &context, const Window &window) { + if (!m_RecreationRequired.exchange(false)) + return; + + vk::SwapchainKHR oldSwapchain = m_Swapchain; + vk::Extent2D extent2D = chooseExtent(context.getPhysicalDevice(), m_Surface.handle, window); + + vk::SwapchainCreateInfoKHR swapchainCreateInfo( + vk::SwapchainCreateFlagsKHR(), + m_Surface.handle, + m_SwapchainImageCount, + m_SwapchainFormat, + m_SwapchainColorSpace, + extent2D, + 1, + vk::ImageUsageFlagBits::eColorAttachment, + vk::SharingMode::eExclusive, + 0, + nullptr, + vk::SurfaceTransformFlagBitsKHR::eIdentity, + vk::CompositeAlphaFlagBitsKHR::eOpaque, + m_SwapchainPresentMode, + true, + oldSwapchain + ); + + m_Swapchain = context.getDevice().createSwapchainKHR(swapchainCreateInfo); + context.getDevice().destroySwapchainKHR(oldSwapchain); + + m_Extent = extent2D; } + void SwapChain::recreateSwapchain() { + m_RecreationRequired = true; + } + + const vk::Extent2D& SwapChain::getExtent() const { + return m_Extent; + } SwapChain::~SwapChain() { // needs to be destroyed by creator } uint32_t SwapChain::getImageCount() { - return m_ImageCount; + return m_SwapchainImageCount; } }