From ef16ef8887c00bc3130335aa222c7c3b2b736cdb Mon Sep 17 00:00:00 2001 From: shg8 Date: Wed, 21 Feb 2024 16:20:23 -0600 Subject: [PATCH 1/4] Bundled shaders --- 3dgs/GSScene.cpp | 5 ++++- 3dgs/Renderer.cpp | 15 ++++++++------- CMakeLists.txt | 24 ++++++++++++++++++++++-- vulkan/Shader.cpp | 19 ++++++++++++------- vulkan/Shader.h | 22 +++++++++++++++++++--- vulkan/pipelines/ComputePipeline.cpp | 6 +++--- vulkan/pipelines/ComputePipeline.h | 5 +++-- 7 files changed, 71 insertions(+), 25 deletions(-) diff --git a/3dgs/GSScene.cpp b/3dgs/GSScene.cpp index c3514be..85d8e2f 100644 --- a/3dgs/GSScene.cpp +++ b/3dgs/GSScene.cpp @@ -6,6 +6,7 @@ #include "GSScene.h" #include +#include "shaders.h" #include "../vulkan/Utils.h" #include "../vulkan/DescriptorSet.h" @@ -155,7 +156,9 @@ std::shared_ptr GSScene::createBuffer(const std::shared_ptr&context) { cov3DBuffer = createBuffer(context, header.numVertices * sizeof(float) * 6); - auto pipeline = std::make_shared(context, "precomp_cov3d"); + auto pipeline = std::make_shared( + context, std::make_shared(context, "precomp_cov3d", SPV_PRECOMP_COV3D, SPV_PRECOMP_COV3D_len)); + auto descriptorSet = std::make_shared(context, FRAMES_IN_FLIGHT); descriptorSet->bindBufferToDescriptorSet(0, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eCompute, vertexBuffer); diff --git a/3dgs/Renderer.cpp b/3dgs/Renderer.cpp index 91215f9..2b0952c 100644 --- a/3dgs/Renderer.cpp +++ b/3dgs/Renderer.cpp @@ -5,6 +5,7 @@ #include "../vulkan/Swapchain.h" #include +#include #include #include @@ -129,7 +130,7 @@ void Renderer::createPreprocessPipeline() { vertexAttributeBuffer = Buffer::storage(context, scene->getNumVertices() * sizeof(VertexAttributeBuffer), false); tileOverlapBuffer = Buffer::storage(context, scene->getNumVertices() * sizeof(uint32_t), false); - preprocessPipeline = std::make_shared(context, "preprocess"); + preprocessPipeline = std::make_shared(context, std::make_shared(context, "preprocess", SPV_PREPROCESS, SPV_PREPROCESS_len)); inputSet = std::make_shared(context, FRAMES_IN_FLIGHT); inputSet->bindBufferToDescriptorSet(0, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eCompute, scene->vertexBuffer); @@ -174,7 +175,7 @@ void Renderer::createPrefixSumPipeline() { prefixSumPongBuffer = Buffer::storage(context, scene->getNumVertices() * sizeof(uint32_t), false); totalSumBufferHost = Buffer::staging(context, sizeof(uint32_t)); - prefixSumPipeline = std::make_shared(context, "prefix_sum"); + prefixSumPipeline = std::make_shared(context, std::make_shared(context, "prefix_sum", SPV_PREFIX_SUM, SPV_PREFIX_SUM_len)); auto descriptorSet = std::make_shared(context, FRAMES_IN_FLIGHT); descriptorSet->bindBufferToDescriptorSet(0, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eCompute, prefixSumPingBuffer); @@ -206,8 +207,8 @@ void Renderer::createRadixSortPipeline() { sortHistBuffer = Buffer::storage(context, numWorkgroups * 256 * sizeof(uint32_t), false); - sortHistPipeline = std::make_shared(context, "hist"); - sortPipeline = std::make_shared(context, "sort"); + sortHistPipeline = std::make_shared(context, std::make_shared(context, "hist", SPV_HIST, SPV_HIST_len)); + sortPipeline = std::make_shared(context, std::make_shared(context, "sort", SPV_SORT, SPV_SORT_len)); auto descriptorSet = std::make_shared(context, FRAMES_IN_FLIGHT); descriptorSet->bindBufferToDescriptorSet(0, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eCompute, @@ -248,7 +249,7 @@ void Renderer::createRadixSortPipeline() { void Renderer::createPreprocessSortPipeline() { spdlog::debug("Creating preprocess sort pipeline"); - preprocessSortPipeline = std::make_shared(context, "preprocess_sort"); + preprocessSortPipeline = std::make_shared(context, std::make_shared(context, "preprocess_sort", SPV_PREPROCESS_SORT, SPV_PREPROCESS_SORT_len)); auto descriptorSet = std::make_shared(context, FRAMES_IN_FLIGHT); descriptorSet->bindBufferToDescriptorSet(0, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eCompute, vertexAttributeBuffer); @@ -274,7 +275,7 @@ void Renderer::createTileBoundaryPipeline() { auto tileY = (height + 16 - 1) / 16; tileBoundaryBuffer = Buffer::storage(context, tileX * tileY * sizeof(uint32_t) * 2, false); - tileBoundaryPipeline = std::make_shared(context, "tile_boundary"); + tileBoundaryPipeline = std::make_shared(context, std::make_shared(context, "tile_boundary", SPV_TILE_BOUNDARY, SPV_TILE_BOUNDARY_len)); auto descriptorSet = std::make_shared(context, FRAMES_IN_FLIGHT); descriptorSet->bindBufferToDescriptorSet(0, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eCompute, sortKBufferEven); @@ -291,7 +292,7 @@ void Renderer::createTileBoundaryPipeline() { void Renderer::createRenderPipeline() { spdlog::debug("Creating render pipeline"); - renderPipeline = std::make_shared(context, "render"); + renderPipeline = std::make_shared(context, std::make_shared(context, "render", SPV_RENDER, SPV_RENDER_len)); auto inputSet = std::make_shared(context, FRAMES_IN_FLIGHT); inputSet->bindBufferToDescriptorSet(0, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eCompute, vertexAttributeBuffer); diff --git a/CMakeLists.txt b/CMakeLists.txt index 548c456..e05044e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,21 +89,41 @@ if (APPLE) list(APPEND GLSLC_DEFINE "-DAPPLE") endif () +set(SHADER_HEADER "${PROJECT_BINARY_DIR}/shaders/shaders.h") +message(STATUS "Shader header file: ${SHADER_HEADER}") + foreach (GLSL ${GLSL_SOURCE_FILES}) - get_filename_component(FILE_NAME ${GLSL} NAME) + get_filename_component(FILE_NAME ${GLSL} NAME_WE) + string(TOUPPER ${FILE_NAME} FILE_NAME_UPPER) + set(FILE_NAME_UPPER "SPV_${FILE_NAME_UPPER}") set(SPIRV "${PROJECT_BINARY_DIR}/shaders/${FILE_NAME}.spv") + SET(TEMP_HEADER "${PROJECT_BINARY_DIR}/shaders/${FILE_NAME}.h") add_custom_command( OUTPUT ${SPIRV} COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_BINARY_DIR}/shaders/" COMMAND ${Vulkan_GLSLANG_VALIDATOR_EXECUTABLE} "--target-env" "vulkan1.2" -V ${GLSL} -o ${SPIRV} ${GLSLC_DEFINE} DEPENDS ${GLSL}) list(APPEND SPIRV_BINARY_FILES ${SPIRV}) + + add_custom_command( + OUTPUT ${TEMP_HEADER} + COMMAND xxd -i -n ${FILE_NAME_UPPER} ${SPIRV} > ${TEMP_HEADER} + DEPENDS ${SPIRV}) + + list(APPEND TEMP_HEADERS ${TEMP_HEADER}) endforeach (GLSL) +add_custom_command( + OUTPUT ${SHADER_HEADER} + COMMAND cat ${TEMP_HEADERS} > ${SHADER_HEADER} + DEPENDS ${TEMP_HEADERS} +) + add_custom_target( Shaders - DEPENDS ${SPIRV_BINARY_FILES} + DEPENDS ${SPIRV_BINARY_FILES} ${SHADER_HEADER} ) +include_directories(${PROJECT_BINARY_DIR}/shaders) include_directories(third_party) diff --git a/vulkan/Shader.cpp b/vulkan/Shader.cpp index 5e48a4b..7c24488 100644 --- a/vulkan/Shader.cpp +++ b/vulkan/Shader.cpp @@ -2,13 +2,18 @@ #include "Utils.h" void Shader::load() { - auto filename = "shaders/" + name + ".comp.spv"; - auto shader_code = Utils::readFile(filename); - if (shader_code.empty()) { - throw std::runtime_error("Failed to load shader: " + filename); - } vk::ShaderModuleCreateInfo create_info; - create_info.codeSize = shader_code.size(); - create_info.pCode = reinterpret_cast(shader_code.data()); + if (data == nullptr) { + auto fn = "shaders/" + filename + ".spv"; + auto shader_code = Utils::readFile(fn); + if (shader_code.empty()) { + throw std::runtime_error("Failed to load shader: " + fn); + } + create_info.codeSize = shader_code.size(); + create_info.pCode = reinterpret_cast(shader_code.data()); + } else { + create_info.codeSize = size; + create_info.pCode = reinterpret_cast(data); + } shader = context->device->createShaderModuleUnique(create_info); } diff --git a/vulkan/Shader.h b/vulkan/Shader.h index 31e19b5..9508420 100644 --- a/vulkan/Shader.h +++ b/vulkan/Shader.h @@ -9,17 +9,33 @@ class Shader { public: - Shader(const std::shared_ptr& _context, std::string name) + Shader(const std::shared_ptr& _context, std::string filename) : context(_context), - name(std::move(name)) { + filename(std::move(filename)) { + } + + Shader(const std::shared_ptr& _context, unsigned char *data, size_t size) + : context(_context), + filename(""), + data(data), + size(size) { + } + + Shader(const std::shared_ptr& context, const std::string& filename, unsigned char* data, size_t size) + : filename(filename), + context(context), + data(data), + size(size) { } void load(); vk::UniqueShaderModule shader; private: - const std::string name; + const std::string filename; std::shared_ptr context; + unsigned char* data; + size_t size; }; diff --git a/vulkan/pipelines/ComputePipeline.cpp b/vulkan/pipelines/ComputePipeline.cpp index d4f36ea..83cad78 100644 --- a/vulkan/pipelines/ComputePipeline.cpp +++ b/vulkan/pipelines/ComputePipeline.cpp @@ -2,14 +2,14 @@ #include "ComputePipeline.h" -ComputePipeline::ComputePipeline(const std::shared_ptr &context, const std::string &shaderFile) : Pipeline(context), shader(context, shaderFile) { - shader.load(); +ComputePipeline::ComputePipeline(const std::shared_ptr& context, std::shared_ptr shader): Pipeline(context), shader(std::move(shader)) { + shader->load(); } void ComputePipeline::build() { buildPipelineLayout(); - vk::PipelineShaderStageCreateInfo pipelineShaderStageCreateInfo({}, vk::ShaderStageFlagBits::eCompute, shader.shader.get(), "main"); + vk::PipelineShaderStageCreateInfo pipelineShaderStageCreateInfo({}, vk::ShaderStageFlagBits::eCompute, shader->shader.get(), "main"); vk::ComputePipelineCreateInfo computePipelineCreateInfo({}, pipelineShaderStageCreateInfo, pipelineLayout.get()); pipeline = context->device->createComputePipelineUnique(nullptr, computePipelineCreateInfo).value; } diff --git a/vulkan/pipelines/ComputePipeline.h b/vulkan/pipelines/ComputePipeline.h index 63e2ac7..62c8bc9 100644 --- a/vulkan/pipelines/ComputePipeline.h +++ b/vulkan/pipelines/ComputePipeline.h @@ -5,14 +5,15 @@ #include "Pipeline.h" +#include class ComputePipeline : public Pipeline { public: - explicit ComputePipeline(const std::shared_ptr &context, const std::string& shader); + explicit ComputePipeline(const std::shared_ptr &context, std::shared_ptr shader);; void build() override; private: - Shader shader; + std::shared_ptr shader; }; From 3e67418f392b1229f361fec170a7e32425df6ff1 Mon Sep 17 00:00:00 2001 From: shg8 Date: Wed, 21 Feb 2024 18:44:14 -0600 Subject: [PATCH 2/4] Platform independent commands --- CMakeLists.txt | 22 +++++++------ cmake/embedfile.c | 47 ++++++++++++++++++++++++++++ vulkan/Shader.h | 6 ++-- vulkan/pipelines/ComputePipeline.cpp | 2 +- 4 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 cmake/embedfile.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e05044e..d0b9632 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,9 +89,18 @@ if (APPLE) list(APPEND GLSLC_DEFINE "-DAPPLE") endif () +add_executable(embedfile cmake/embedfile.c) + set(SHADER_HEADER "${PROJECT_BINARY_DIR}/shaders/shaders.h") message(STATUS "Shader header file: ${SHADER_HEADER}") +# Delete old header file +add_custom_command( + OUTPUT ${SHADER_HEADER} + COMMAND ${CMAKE_COMMAND} -E remove ${SHADER_HEADER} + DEPENDS ${GLSL_SOURCE_FILES} +) + foreach (GLSL ${GLSL_SOURCE_FILES}) get_filename_component(FILE_NAME ${GLSL} NAME_WE) string(TOUPPER ${FILE_NAME} FILE_NAME_UPPER) @@ -106,19 +115,14 @@ foreach (GLSL ${GLSL_SOURCE_FILES}) list(APPEND SPIRV_BINARY_FILES ${SPIRV}) add_custom_command( - OUTPUT ${TEMP_HEADER} - COMMAND xxd -i -n ${FILE_NAME_UPPER} ${SPIRV} > ${TEMP_HEADER} - DEPENDS ${SPIRV}) + OUTPUT ${SHADER_HEADER} + COMMAND embedfile ${FILE_NAME_UPPER} ${SPIRV} ${SHADER_HEADER} + DEPENDS ${SPIRV} + APPEND) list(APPEND TEMP_HEADERS ${TEMP_HEADER}) endforeach (GLSL) -add_custom_command( - OUTPUT ${SHADER_HEADER} - COMMAND cat ${TEMP_HEADERS} > ${SHADER_HEADER} - DEPENDS ${TEMP_HEADERS} -) - add_custom_target( Shaders DEPENDS ${SPIRV_BINARY_FILES} ${SHADER_HEADER} diff --git a/cmake/embedfile.c b/cmake/embedfile.c new file mode 100644 index 0000000..ad6b3ae --- /dev/null +++ b/cmake/embedfile.c @@ -0,0 +1,47 @@ +#include +#include + +FILE* open_or_exit(const char* fname, const char* mode) +{ + FILE* f = fopen(fname, mode); + if (f == NULL) { + perror(fname); + exit(EXIT_FAILURE); + } + return f; +} + +int main(int argc, char** argv) +{ + if (argc < 3) { + fprintf(stderr, "USAGE: %s {sym} {rsrc}\n\n" + " Creates {sym}.c from the contents of {rsrc}\n", + argv[0]); + return EXIT_FAILURE; + } + + const char* sym = argv[1]; + FILE* in = open_or_exit(argv[2], "r"); + FILE* out = open_or_exit(argv[3], "a"); + fprintf(out, "static const unsigned char %s[] = {\n", sym); + + unsigned char buf[256]; + size_t nread = 0; + size_t linecount = 0; + do { + nread = fread(buf, 1, sizeof(buf), in); + size_t i; + for (i=0; i < nread; i++) { + fprintf(out, "0x%02x, ", buf[i]); + if (++linecount == 10) { fprintf(out, "\n"); linecount = 0; } + } + } while (nread > 0); + if (linecount > 0) fprintf(out, "\n"); + fprintf(out, "};\n"); + fprintf(out, "static const size_t %s_len = sizeof(%s);\n\n",sym,sym); + + fclose(in); + fclose(out); + + return EXIT_SUCCESS; +} diff --git a/vulkan/Shader.h b/vulkan/Shader.h index 9508420..883d678 100644 --- a/vulkan/Shader.h +++ b/vulkan/Shader.h @@ -14,14 +14,14 @@ class Shader { filename(std::move(filename)) { } - Shader(const std::shared_ptr& _context, unsigned char *data, size_t size) + Shader(const std::shared_ptr& _context, const unsigned char * data, size_t size) : context(_context), filename(""), data(data), size(size) { } - Shader(const std::shared_ptr& context, const std::string& filename, unsigned char* data, size_t size) + Shader(const std::shared_ptr& context, const std::string& filename, const unsigned char * data, size_t size) : filename(filename), context(context), data(data), @@ -34,7 +34,7 @@ class Shader { private: const std::string filename; std::shared_ptr context; - unsigned char* data; + const unsigned char* data = nullptr; size_t size; }; diff --git a/vulkan/pipelines/ComputePipeline.cpp b/vulkan/pipelines/ComputePipeline.cpp index 83cad78..48cac70 100644 --- a/vulkan/pipelines/ComputePipeline.cpp +++ b/vulkan/pipelines/ComputePipeline.cpp @@ -3,7 +3,7 @@ #include "ComputePipeline.h" ComputePipeline::ComputePipeline(const std::shared_ptr& context, std::shared_ptr shader): Pipeline(context), shader(std::move(shader)) { - shader->load(); + this->shader->load(); } void ComputePipeline::build() { From 39497fe67e23217dbce06ff19597666bfe16637f Mon Sep 17 00:00:00 2001 From: shg8 Date: Wed, 13 Mar 2024 18:59:30 -0700 Subject: [PATCH 3/4] Read compiled SPIR-V in binary mode --- CMakeLists.txt | 8 ++++++-- cmake/embedfile.c | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d0b9632..fe02376 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,11 @@ FetchContent_Declare(spdlog GIT_REPOSITORY https://github.com/gabime/spdlog.git GIT_TAG v1.13.0 ) -FetchContent_MakeAvailable(spdlog) +FetchContent_GetProperties(spdlog) +if (NOT spdlog_POPULATED) + FetchContent_Populate(spdlog) + add_subdirectory(${spdlog_SOURCE_DIR} ${spdlog_BINARY_DIR}) +endif() FetchContent_Declare(imgui GIT_REPOSITORY https://github.com/ocornut/imgui.git @@ -178,7 +182,7 @@ target_include_directories(vulkan_splatting PUBLIC ${spdlog_SOURCE_DIR}/include ) -target_link_libraries(vulkan_splatting PUBLIC glfw libenvpp::libenvpp) +target_link_libraries(vulkan_splatting PUBLIC glfw libenvpp::libenvpp spdlog::spdlog) target_link_libraries(vulkan_splatting PUBLIC Vulkan::Vulkan) if (UNIX) target_link_libraries(vulkan_splatting PUBLIC ${CMAKE_DL_LIBS}) diff --git a/cmake/embedfile.c b/cmake/embedfile.c index ad6b3ae..a23fb9e 100644 --- a/cmake/embedfile.c +++ b/cmake/embedfile.c @@ -21,7 +21,7 @@ int main(int argc, char** argv) } const char* sym = argv[1]; - FILE* in = open_or_exit(argv[2], "r"); + FILE* in = open_or_exit(argv[2], "rb"); FILE* out = open_or_exit(argv[3], "a"); fprintf(out, "static const unsigned char %s[] = {\n", sym); From 225d48f1d8a44681fa84272976b0e291211ef677 Mon Sep 17 00:00:00 2001 From: shg8 Date: Wed, 13 Mar 2024 19:34:17 -0700 Subject: [PATCH 4/4] Various fixes --- 3dgs/GUIManager.cpp | 8 ++++---- 3dgs/GUIManager.h | 28 ++++++++++++++-------------- 3dgs/Renderer.cpp | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/3dgs/GUIManager.cpp b/3dgs/GUIManager.cpp index dfcc5b8..e168d9a 100644 --- a/3dgs/GUIManager.cpp +++ b/3dgs/GUIManager.cpp @@ -27,9 +27,9 @@ void GUIManager::buildGui() { 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)); + 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(); @@ -47,7 +47,7 @@ void GUIManager::buildGui() { void GUIManager::pushMetric(const std::string& name, float value) { int maxSize = 600; if (!metricsMap->contains(name)) { - metricsMap->insert({name, ScrollingBuffer(maxSize)}); + metricsMap->insert({name, ScrollingBuffer{}}); } metricsMap->at(name).addPoint(ImGui::GetTime(), value); } diff --git a/3dgs/GUIManager.h b/3dgs/GUIManager.h index 0bbd4c3..a1270f0 100644 --- a/3dgs/GUIManager.h +++ b/3dgs/GUIManager.h @@ -9,26 +9,26 @@ #include "implot/implot.h" struct ScrollingBuffer { - int MaxSize; - int Offset; - ImVector Data; - ScrollingBuffer(int max_size = 2000) { - MaxSize = max_size; - Offset = 0; - Data.reserve(MaxSize); + int maxSize; + int offset; + ImVector data; + explicit ScrollingBuffer(const int max_size = 10000) { + maxSize = max_size; + offset = 0; + data.reserve(maxSize); } void addPoint(float x, float y) { - if (Data.size() < MaxSize) - Data.push_back(ImVec2(x,y)); + if (data.size() < maxSize) + data.push_back(ImVec2(x,y)); else { - Data[Offset] = ImVec2(x,y); - Offset = (Offset + 1) % MaxSize; + data[offset] = ImVec2(x,y); + offset = (offset + 1) % maxSize; } } void clear() { - if (Data.size() > 0) { - Data.shrink(0); - Offset = 0; + if (data.size() > 0) { + data.shrink(0); + offset = 0; } } }; diff --git a/3dgs/Renderer.cpp b/3dgs/Renderer.cpp index 2b0952c..c59531b 100644 --- a/3dgs/Renderer.cpp +++ b/3dgs/Renderer.cpp @@ -81,7 +81,7 @@ void Renderer::retrieveTimestamps() { void Renderer::initializeVulkan() { spdlog::debug("Initializing Vulkan"); - window = std::make_shared("Vulkan Splatting", 800, 600); + window = std::make_shared("Vulkan Splatting", 1920, 1080); context = std::make_shared(Window::getRequiredInstanceExtensions(), std::vector{}, configuration.enableVulkanValidationLayers); @@ -640,7 +640,7 @@ void Renderer::updateUniforms() { auto view = glm::inverse(translation * rotation); data.view_mat = view; - data.proj_mat = glm::perspective(glm::radians(camera.fov), static_cast(width) / static_cast(height), + data.proj_mat = glm::perspective(glm::radians(camera.fov) / 2.0f, static_cast(width) / static_cast(height), camera.nearPlane, camera.farPlane) * view;