Revision 35efca7662eafe5c0648fbb4e97a7bc1eda84322 authored by Christoph Neuhauser on 23 October 2023, 22:10:04 UTC, committed by Christoph Neuhauser on 23 October 2023, 22:10:04 UTC
1 parent ef25cab
Main.cpp
/*
* BSD 2-Clause License
*
* Copyright (c) 2022, Christoph Neuhauser
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <unordered_map>
#include <Utils/StringUtils.hpp>
#include <Utils/AppSettings.hpp>
#include <Utils/AppLogic.hpp>
#include <Utils/File/FileUtils.hpp>
#include <Utils/File/Logfile.hpp>
#include <Graphics/Window.hpp>
#include <Graphics/Vulkan/Utils/Instance.hpp>
#include <Graphics/Vulkan/Utils/Device.hpp>
#include <Graphics/Vulkan/Utils/Swapchain.hpp>
#include <Graphics/Vulkan/Shader/ShaderManager.hpp>
#ifdef SUPPORT_OPENGL
#include <Graphics/OpenGL/Context/OffscreenContextEGL.hpp>
#include <Graphics/OpenGL/Context/OffscreenContextGlfw.hpp>
#endif
#include "Renderers/Diagram/SamplingTest.hpp"
#include "MainApp.hpp"
void vulkanErrorCallbackHeadless() {
SDL_CaptureMouse(SDL_FALSE);
std::cerr << "Application callback" << std::endl;
}
#ifdef __linux__
#include <sys/resource.h>
// Some systems have 1024 open file descriptors as the maximum. Increase the soft limit of the process to the maximum.
void setFileDescriptorLimit() {
rlimit lim{};
getrlimit(RLIMIT_NOFILE, &lim);
size_t rlimOld = lim.rlim_cur;
if (lim.rlim_cur < lim.rlim_max) {
lim.rlim_cur = lim.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &lim) == -1) {
sgl::Logfile::get()->writeError("Error in setFileDescriptorLimit: setrlimit failed.");
return;
}
getrlimit(RLIMIT_NOFILE, &lim);
sgl::Logfile::get()->write(
"File descriptor limit: " + std::to_string(lim.rlim_cur)
+ " (old: " + std::to_string(rlimOld) + ")", sgl::BLUE);
} else {
sgl::Logfile::get()->write("File descriptor limit: " + std::to_string(lim.rlim_cur), sgl::BLUE);
}
}
#endif
int main(int argc, char *argv[]) {
// Initialize the filesystem utilities.
std::setlocale(LC_ALL, "en_US.UTF-8"); // For font rendering with VKVG.
sgl::FileUtils::get()->initialize("Correrender", argc, argv);
// Parse the arguments.
bool usePerfMode = false, useSamplingMode = false, useReplicabilityStampMode = false;
std::string dataSetPath;
int testIdx = -1;
for (int i = 1; i < argc; i++) {
std::string command = argv[i];
if (command == "--perf") {
usePerfMode = true;
} else if (command == "--sampling") {
useSamplingMode = true;
if (i + 1 < argc && !sgl::startsWith(argv[i + 1], "-")) {
i++;
dataSetPath = argv[i];
}
if (i + 1 < argc && !sgl::startsWith(argv[i + 1], "-")) {
i++;
testIdx = sgl::fromString<int>(argv[i]);
}
} else if (command == "--replicability") {
useReplicabilityStampMode = true;
}
}
bool isHeadlessMode = useSamplingMode;
#ifdef DATA_PATH
if (!sgl::FileUtils::get()->directoryExists("Data") && !sgl::FileUtils::get()->directoryExists("../Data")) {
sgl::AppSettings::get()->setDataDirectory(DATA_PATH);
}
#endif
sgl::AppSettings::get()->initializeDataDirectory();
std::string iconPath = sgl::AppSettings::get()->getDataDirectory() + "Fonts/icon_256.png";
sgl::AppSettings::get()->loadApplicationIconFromFile(iconPath);
#ifdef __linux__
setFileDescriptorLimit();
#endif
// Load the file containing the app settings
ImVector<ImWchar> fontRanges;
if (isHeadlessMode) {
sgl::AppSettings::get()->setSaveSettings(false);
sgl::AppSettings::get()->getSettings().addKeyValue("window-debugContext", true);
} else {
std::string settingsFile = sgl::FileUtils::get()->getConfigDirectory() + "settings.txt";
sgl::AppSettings::get()->loadSettings(settingsFile.c_str());
sgl::AppSettings::get()->getSettings().addKeyValue("window-multisamples", 0);
sgl::AppSettings::get()->getSettings().addKeyValue("window-debugContext", true);
if (usePerfMode) {
sgl::AppSettings::get()->getSettings().addKeyValue("window-vSync", false);
} else {
sgl::AppSettings::get()->getSettings().addKeyValue("window-vSync", true);
}
sgl::AppSettings::get()->getSettings().addKeyValue("window-resizable", true);
sgl::AppSettings::get()->getSettings().addKeyValue("window-savePosition", true);
//sgl::AppSettings::get()->setVulkanDebugPrintfEnabled();
ImFontGlyphRangesBuilder builder;
builder.AddChar(L'\u03BB'); // lambda
builder.AddChar(L'\u03C3'); // sigma
builder.BuildRanges(&fontRanges);
bool useMultiViewport = false;
if (sgl::AppSettings::get()->getSettings().getValueOpt("useDockSpaceMode", useMultiViewport)) {
useMultiViewport = !useMultiViewport;
}
sgl::AppSettings::get()->setLoadGUI(fontRanges.Data, true, useMultiViewport);
}
sgl::AppSettings::get()->setRenderSystem(sgl::RenderSystem::VULKAN);
sgl::Window* window = nullptr;
std::vector<const char*> optionalDeviceExtensions;
if (isHeadlessMode) {
sgl::AppSettings::get()->createHeadless();
} else {
#ifdef SUPPORT_OPENGL
/*
* OpenGL interop is optionally supported for rendering with NanoVG.
* For this, we need to enable a few instance and device extensions.
* We need to do this before we know whether we were able to successfully create the OpenGL context,
* as we need a Vulkan device for matching an OpenGL context if EGL is supported.
*/
sgl::AppSettings::get()->enableVulkanOffscreenOpenGLContextInteropSupport();
#endif
window = sgl::AppSettings::get()->createWindow();
#ifdef SUPPORT_CUDA_INTEROP
optionalDeviceExtensions = sgl::vk::Device::getCudaInteropDeviceExtensions();
#endif
#ifdef SUPPORT_OPENGL
if (sgl::AppSettings::get()->getInstanceSupportsVulkanOpenGLInterop()) {
std::vector<const char*> interopDeviceExtensions =
sgl::AppSettings::get()->getVulkanOpenGLInteropDeviceExtensions();
for (const char* extensionName : interopDeviceExtensions) {
bool foundExtension = false;
for (size_t i = 0; i < optionalDeviceExtensions.size(); i++) {
if (strcmp(extensionName, optionalDeviceExtensions.at(i)) == 0) {
foundExtension = true;
break;
}
}
if (!foundExtension) {
optionalDeviceExtensions.push_back(extensionName);
}
}
}
#endif
//optionalDeviceExtensions.push_back(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME);
}
optionalDeviceExtensions.push_back(VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME);
sgl::vk::Instance* instance = sgl::AppSettings::get()->getVulkanInstance();
if (isHeadlessMode) {
sgl::AppSettings::get()->getVulkanInstance()->setDebugCallback(&vulkanErrorCallbackHeadless);
}
auto* device = new sgl::vk::Device;
sgl::vk::DeviceFeatures requestedDeviceFeatures{};
requestedDeviceFeatures.optionalPhysicalDeviceFeatures.sampleRateShading = VK_TRUE; // For MSAA.
requestedDeviceFeatures.optionalPhysicalDeviceFeatures.geometryShader = VK_TRUE; // For Skia (if enabled).
requestedDeviceFeatures.optionalPhysicalDeviceFeatures.dualSrcBlend = VK_TRUE; // For Skia (if enabled).
requestedDeviceFeatures.optionalPhysicalDeviceFeatures.logicOp = VK_TRUE; // For VKVG (if enabled).
requestedDeviceFeatures.optionalPhysicalDeviceFeatures.fillModeNonSolid = VK_TRUE; // For VKVG (if enabled).
requestedDeviceFeatures.optionalEnableShaderDrawParametersFeatures = true; // For deferred shading.
requestedDeviceFeatures.requestedPhysicalDeviceFeatures.fragmentStoresAndAtomics = VK_TRUE;
// For transfer function optimization with 64-bit accuracy.
requestedDeviceFeatures.optionalPhysicalDeviceFeatures.shaderInt64 = VK_TRUE;
requestedDeviceFeatures.optionalPhysicalDeviceFeatures.shaderFloat64 = VK_TRUE;
// For ensemble combination when using Vulkan-CUDA interop with PyTorch.
requestedDeviceFeatures.optionalPhysicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing = VK_TRUE;
requestedDeviceFeatures.optionalPhysicalDeviceFeatures.shaderStorageBufferArrayDynamicIndexing = VK_TRUE;
requestedDeviceFeatures.optionalVulkan12Features.descriptorIndexing = VK_TRUE;
requestedDeviceFeatures.optionalVulkan12Features.descriptorBindingVariableDescriptorCount = VK_TRUE;
requestedDeviceFeatures.optionalVulkan12Features.runtimeDescriptorArray = VK_TRUE;
requestedDeviceFeatures.optionalVulkan12Features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE;
requestedDeviceFeatures.optionalVulkan12Features.shaderStorageBufferArrayNonUniformIndexing = VK_TRUE;
// For VMLP.
requestedDeviceFeatures.optionalVulkan12Features.shaderFloat16 = VK_TRUE;
requestedDeviceFeatures.optionalVulkan11Features.storageBuffer16BitAccess = VK_TRUE;
#ifdef VK_NV_cooperative_matrix
optionalDeviceExtensions.push_back(VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME);
#endif
#ifdef VK_KHR_cooperative_matrix
optionalDeviceExtensions.push_back(VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME);
#endif
if (isHeadlessMode) {
device->createDeviceHeadless(
instance, {
VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME
},
optionalDeviceExtensions, requestedDeviceFeatures);
} else {
device->createDeviceSwapchain(
instance, window, {
VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME
},
optionalDeviceExtensions, requestedDeviceFeatures);
}
sgl::OffscreenContext* offscreenContext = nullptr;
if (!isHeadlessMode) {
#ifdef SUPPORT_OPENGL
sgl::OffscreenContextParams params{};
#ifdef USE_ZINK
params.tryUseZinkIfAvailable = true;
setenv("__GLX_VENDOR_LIBRARY_NAME", "mesa", 0);
setenv("MESA_LOADER_DRIVER_OVERRIDE", "zink", 0);
setenv("GALLIUM_DRIVER", "zink", 0);
#endif
offscreenContext = sgl::createOffscreenContext(device, params, false);
if (offscreenContext && offscreenContext->getIsInitialized()) {
//offscreenContext->makeCurrent(); //< This is called by createOffscreenContext to check interop extensions.
sgl::AppSettings::get()->setOffscreenContext(offscreenContext);
}
#endif
sgl::vk::Swapchain* swapchain = new sgl::vk::Swapchain(device);
swapchain->create(window);
sgl::AppSettings::get()->setSwapchain(swapchain);
}
sgl::AppSettings::get()->setPrimaryDevice(device);
sgl::AppSettings::get()->initializeSubsystems();
if (!isHeadlessMode) {
auto app = new MainApp();
if (useReplicabilityStampMode) {
app->setUseReplicabilityStampMode();
}
app->run();
delete app;
}
if (useSamplingMode) {
if (dataSetPath.empty()) {
dataSetPath = sgl::FileUtils::get()->getUserDirectory() + "datasets/Necker/nc/necker_t5_tk_u.nc";
//dataSetPath = sgl::FileUtils::get()->getUserDirectory() + "datasets/Necker/nc/necker_t5_e100_tk.nc";
}
if (testIdx < 0) {
testIdx = 0;
}
runSamplingTests(dataSetPath, testIdx);
}
sgl::AppSettings::get()->release();
#ifdef SUPPORT_OPENGL
if (offscreenContext) {
sgl::destroyOffscreenContext(offscreenContext);
offscreenContext = nullptr;
}
#endif
return 0;
}
Computing file changes ...