Skip to content

Commit

Permalink
feature/imgui: add imgui support and performance graph (#9)
Browse files Browse the repository at this point in the history
* Add imgui and performance graphs

* Remove wrong include directive

* Fix build issues

* Fix build issues

* Fix build issues

* Fix build issues
  • Loading branch information
shg8 authored Feb 21, 2024
1 parent 6a5676b commit 69f3b7a
Show file tree
Hide file tree
Showing 19 changed files with 14,340 additions and 50 deletions.
59 changes: 59 additions & 0 deletions 3dgs/GUIManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "GUIManager.h"

#include <iostream>

static std::shared_ptr<std::unordered_map<std::string, ScrollingBuffer>> metricsMap;

GUIManager::GUIManager() {
metricsMap = std::make_shared<std::unordered_map<std::string, ScrollingBuffer>>();
}

void GUIManager::init() {
ImPlot::CreateContext();
}

void GUIManager::buildGui() {
ImGui::SetNextWindowSize(ImVec2(400, 250), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowPos(ImVec2(10, 10), ImGuiCond_FirstUseEver);
ImGui::Begin("Performance");

static float history = 10;

static ImPlotAxisFlags flags = ImPlotAxisFlags_AutoFit;
if (ImPlot::BeginPlot("##Scrolling", ImVec2(-1, -1))) {
ImPlot::SetupAxes("s", "time (ms)", flags, flags);
const auto t = ImGui::GetTime();
ImPlot::SetupAxisLimits(ImAxis_X1, t - history, t, ImGuiCond_Always);
ImPlot::SetupAxisLimits(ImAxis_Y1, 0, 1);
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.5f);
for (auto& [name, values]: *metricsMap) {
if (!values.Data.empty()) {
ImPlot::PlotLine(name.c_str(), &values.Data[0].x, &values.Data[0].y, values.Data.size(), 0,
values.Offset, 2 * sizeof(float));
}
}
ImPlot::EndPlot();
}
ImGui::SliderFloat("History", &history, 1, 30, "%.1f s");
ImGui::End();

ImGui::SetNextWindowPos(ImVec2(10, 270), ImGuiCond_FirstUseEver);
ImGui::Begin("Controls");
ImGui::Text("WASD: Move");
ImGui::Text("Mouse: Look");
ImGui::End();
}

void GUIManager::pushMetric(const std::string& name, float value) {
int maxSize = 600;
if (!metricsMap->contains(name)) {
metricsMap->insert({name, ScrollingBuffer(maxSize)});
}
metricsMap->at(name).addPoint(ImGui::GetTime(), value);
}

void GUIManager::pushMetric(const std::unordered_map<std::string, float>& name) {
for (auto& [n, v]: name) {
pushMetric(n, v);
}
}
50 changes: 50 additions & 0 deletions 3dgs/GUIManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef GUIMANAGER_H
#define GUIMANAGER_H
#include <unordered_map>
#include <vector>
#include <string>
#include <memory>

#include "imgui.h"
#include "implot/implot.h"

struct ScrollingBuffer {
int MaxSize;
int Offset;
ImVector<ImVec2> Data;
ScrollingBuffer(int max_size = 2000) {
MaxSize = max_size;
Offset = 0;
Data.reserve(MaxSize);
}
void addPoint(float x, float y) {
if (Data.size() < MaxSize)
Data.push_back(ImVec2(x,y));
else {
Data[Offset] = ImVec2(x,y);
Offset = (Offset + 1) % MaxSize;
}
}
void clear() {
if (Data.size() > 0) {
Data.shrink(0);
Offset = 0;
}
}
};

class GUIManager {
public:
GUIManager();

static void init();

static void buildGui();

static void pushMetric(const std::string& name, float value);

static void pushMetric(const std::unordered_map<std::string, float>& name);

};

#endif //GUIMANAGER_H
50 changes: 46 additions & 4 deletions 3dgs/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

void Renderer::initialize() {
initializeVulkan();
createGui();
loadSceneToGPU();
createPreprocessPipeline();
createPrefixSumPipeline();
Expand Down Expand Up @@ -69,7 +70,10 @@ void Renderer::retrieveTimestamps() {
throw std::runtime_error("Failed to retrieve timestamps");
}

queryManager->parseResults(timestamps);
auto metrics = queryManager->parseResults(timestamps);
for (auto& metric: metrics) {
guiManager.pushMetric(metric.first, metric.second / 1000000.0);
}
}

void Renderer::initializeVulkan() {
Expand Down Expand Up @@ -110,6 +114,7 @@ void Renderer::initializeVulkan() {
void Renderer::loadSceneToGPU() {
scene = std::make_shared<GSScene>(configuration.scene);
scene->load(context);

// reset descriptor pool
context->device->resetDescriptorPool(context->descriptorPool.get());
}
Expand Down Expand Up @@ -147,6 +152,16 @@ void Renderer::createPreprocessPipeline() {
Renderer::Renderer(RendererConfiguration configuration) : configuration(std::move(configuration)) {
}

void Renderer::createGui() {
if (!configuration.enableGui) {
return;
}

imguiManager = std::make_shared<ImguiManager>(context, swapchain, window);
imguiManager->init();
guiManager.init();
}

void Renderer::createPrefixSumPipeline() {
prefixSumPingBuffer = Buffer::storage(context, scene->getNumVertices() * sizeof(uint32_t), false);
prefixSumPongBuffer = Buffer::storage(context, scene->getNumVertices() * sizeof(uint32_t), false);
Expand Down Expand Up @@ -380,6 +395,8 @@ void Renderer::run() {
// assert(data2[i] <= data2[i+1]);
// }
}

context->device->waitIdle();
}

void Renderer::createCommandPool() {
Expand All @@ -399,6 +416,8 @@ void Renderer::recordPreprocessCommandBuffer() {

preprocessCommandBuffer->begin(vk::CommandBufferBeginInfo{});

preprocessCommandBuffer->resetQueryPool(context->queryPool.get(), 0, 12);

preprocessPipeline->bind(preprocessCommandBuffer, 0, 0);
preprocessCommandBuffer->writeTimestamp(vk::PipelineStageFlagBits::eTopOfPipe, context->queryPool.get(), queryManager->registerQuery("preprocess_start"));
preprocessCommandBuffer->dispatch(numGroups, 1, 1);
Expand Down Expand Up @@ -560,15 +579,38 @@ void Renderer::recordRenderCommandBuffer(uint32_t currentFrame) {

// image layout transition: general -> present
imageMemoryBarrier.oldLayout = vk::ImageLayout::eGeneral;
imageMemoryBarrier.newLayout = vk::ImageLayout::ePresentSrcKHR;
imageMemoryBarrier.srcAccessMask = vk::AccessFlagBits::eShaderWrite;
imageMemoryBarrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
renderCommandBuffer->pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,

if (configuration.enableGui) {
imageMemoryBarrier.newLayout = vk::ImageLayout::eColorAttachmentOptimal;
imageMemoryBarrier.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
renderCommandBuffer->pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::DependencyFlagBits::eByRegion, nullptr, nullptr, imageMemoryBarrier);
} else {
imageMemoryBarrier.newLayout = vk::ImageLayout::ePresentSrcKHR;
imageMemoryBarrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;
renderCommandBuffer->pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eBottomOfPipe,
vk::DependencyFlagBits::eByRegion, nullptr, nullptr, imageMemoryBarrier);
}
renderCommandBuffer->writeTimestamp(vk::PipelineStageFlagBits::eBottomOfPipe, context->queryPool.get(), queryManager->registerQuery("render_end"));

if (configuration.enableGui) {
imguiManager->draw(renderCommandBuffer.get(), currentImageIndex, &GUIManager::buildGui);

imageMemoryBarrier.oldLayout = vk::ImageLayout::eColorAttachmentOptimal;
imageMemoryBarrier.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;

imageMemoryBarrier.newLayout = vk::ImageLayout::ePresentSrcKHR;
imageMemoryBarrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead;

renderCommandBuffer->pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::PipelineStageFlagBits::eBottomOfPipe,
vk::DependencyFlagBits::eByRegion, nullptr, nullptr, imageMemoryBarrier);
}
renderCommandBuffer->end();
}

Expand Down
9 changes: 8 additions & 1 deletion 3dgs/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#define GLM_SWIZZLE

#include <args.hxx>
#include <atomic>

#include "../vulkan/Window.h"
Expand All @@ -11,6 +12,8 @@
#include "../vulkan/Swapchain.h"
#include <glm/gtc/quaternion.hpp>

#include "GUIManager.h"
#include "../vulkan/ImguiManager.h"
#include "../vulkan/QueryManager.h"

struct RendererConfiguration {
Expand All @@ -22,6 +25,7 @@ struct RendererConfiguration {
float fov = 45.0f;
float near = 0.2f;
float far = 1000.0f;
bool enableGui = true;
};

class Renderer {
Expand Down Expand Up @@ -62,6 +66,8 @@ class Renderer {

explicit Renderer(RendererConfiguration configuration);

void createGui();

void initialize();

void handleInput();
Expand All @@ -75,8 +81,10 @@ class Renderer {
RendererConfiguration configuration;
std::shared_ptr<Window> window;
std::shared_ptr<VulkanContext> context;
std::shared_ptr<ImguiManager> imguiManager;
std::shared_ptr<GSScene> scene;
std::shared_ptr<QueryManager> queryManager = std::make_shared<QueryManager>();
GUIManager guiManager {};

std::shared_ptr<ComputePipeline> preprocessPipeline;
std::shared_ptr<ComputePipeline> renderPipeline;
Expand Down Expand Up @@ -107,7 +115,6 @@ class Renderer {

std::shared_ptr<Swapchain> swapchain;


Camera camera {
.position = glm::vec3(0.0f, 0.0f, 0.0f),
.rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f),
Expand Down
28 changes: 27 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ FetchContent_Declare(libenvpp
)
FetchContent_MakeAvailable(libenvpp)

FetchContent_Declare(imgui
GIT_REPOSITORY https://github.com/ocornut/imgui.git
GIT_TAG v1.90.3
)
FetchContent_MakeAvailable(imgui)

if (APPLE)
add_compile_definitions(__APPLE__)
endif ()
Expand Down Expand Up @@ -95,6 +101,15 @@ add_custom_target(

include_directories(third_party)

file(GLOB EXTERNAL_SOURCE
${imgui_SOURCE_DIR}/*.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_vulkan.cpp
third_party/implot/implot.cpp
third_party/implot/implot_demo.cpp
third_party/implot/implot_items.cpp
)

add_executable(vulkan_splatting main.cpp
vulkan/VulkanContext.cpp
3dgs/Renderer.cpp
Expand All @@ -113,13 +128,24 @@ add_executable(vulkan_splatting main.cpp
vulkan/pipelines/ComputePipeline.h
vulkan/Swapchain.cpp
vulkan/Swapchain.h
${EXTERNAL_SOURCE}
vulkan/ImguiManager.cpp
vulkan/ImguiManager.h
vulkan/QueryManager.cpp
vulkan/QueryManager.h
3dgs/GUIManager.cpp
3dgs/GUIManager.h
)

add_dependencies(vulkan_splatting Shaders)

target_include_directories(vulkan_splatting PUBLIC ${Vulkan_INCLUDE_DIRS} ${GLM_INCLUDE_DIRS} ${glm_SOURCE_DIR})
target_include_directories(vulkan_splatting PUBLIC
${Vulkan_INCLUDE_DIRS}
${GLM_INCLUDE_DIRS}
${glm_SOURCE_DIR}
${imgui_SOURCE_DIR}
${imgui_SOURCE_DIR}/backends
)

target_link_libraries(vulkan_splatting PUBLIC glfw libenvpp::libenvpp)
target_link_libraries(vulkan_splatting PUBLIC Vulkan::Vulkan)
Expand Down
35 changes: 21 additions & 14 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,31 @@

int main(int argc, char** argv) {
args::ArgumentParser parser("Vulkan Splatting");
args::HelpFlag helpFlag {parser, "help", "Display this help menu", {'h', "help"}};
args::Flag validationLayersFlag {parser, "validation-layers", "Enable Vulkan validation layers", {'v', "validation-layers"}};
args::ValueFlag<uint8_t> physicalDeviceIdFlag {parser, "physical-device", "Select physical device by index", {'d', "device"}};
args::Flag immediateSwapchainFlag {parser, "immediate-swapchain", "Set swapchain mode to immediate (VK_PRESENT_MODE_IMMEDIATE_KHR)", {'i', "immediate-swapchain"}};
args::Positional<std::string> scenePath {parser, "scene", "Path to scene file", "scene.ply"};
args::HelpFlag helpFlag{parser, "help", "Display this help menu", {'h', "help"}};
args::Flag validationLayersFlag{
parser, "validation-layers", "Enable Vulkan validation layers", {'v', "validation-layers"}
};
args::ValueFlag<uint8_t> physicalDeviceIdFlag{
parser, "physical-device", "Select physical device by index", {'d', "device"}
};
args::Flag immediateSwapchainFlag{
parser, "immediate-swapchain", "Set swapchain mode to immediate (VK_PRESENT_MODE_IMMEDIATE_KHR)",
{'i', "immediate-swapchain"}
};
args::Flag noGuiFlag{parser, "no-gui", "Disable GUI", { "no-gui"}};
args::Positional<std::string> scenePath{parser, "scene", "Path to scene file", "scene.ply"};

try
{
try {
parser.ParseCLI(argc, argv);
}
catch (const args::Completion& e)
{
} catch (const args::Completion& e) {
std::cout << e.what();
return 0;
}
catch (const args::Help&)
{
catch (const args::Help&) {
std::cout << parser;
return 0;
}
catch (const args::ParseError& e)
{
catch (const args::ParseError& e) {
std::cerr << e.what() << std::endl;
std::cerr << parser;
return 1;
Expand Down Expand Up @@ -66,6 +69,10 @@ int main(int argc, char** argv) {
config.immediateSwapchain = args::get(immediateSwapchainFlag);
}

if (noGuiFlag) {
config.enableGui = false;
}

#ifndef DEBUG
try {
#endif
Expand Down
Loading

0 comments on commit 69f3b7a

Please sign in to comment.