diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt index 535affeb..310710aa 100644 --- a/assets/CMakeLists.txt +++ b/assets/CMakeLists.txt @@ -55,7 +55,7 @@ source_group("Textures" FILES ${texture_files}) add_custom_target( Assets DEPENDS ${copied_fonts} ${copied_locale} ${copied_models} ${compiled_shaders} ${copied_textures} - SOURCES ${font_files} ${model_files} ${shader_files} ${shader_extra_files} ${texture_files} ${shader_common_files}) + SOURCES ${font_files} ${locale_files} ${model_files} ${shader_files} ${shader_extra_files} ${texture_files} ${shader_common_files}) # Shader compilation -> POST_BUILD diff --git a/build_windows.bat b/build_windows.bat index 26b15de6..67d3a6fb 100644 --- a/build_windows.bat +++ b/build_windows.bat @@ -4,7 +4,7 @@ for %%X in (cmake.exe) do (set FOUND=%%~$PATH:X) if defined FOUND ( set CMAKE=cmake ) ELSE ( -set CMAKE="%CD%\build\vcpkg.windows\downloads\tools\cmake-3.27.1-windows\cmake-3.27.1-windows-i386\bin\cmake.exe" +set CMAKE="%CD%\build\vcpkg.windows\downloads\tools\cmake-3.29.2-windows\cmake-3.29.2-windows-i386\bin\cmake.exe" ) for %%X in (msbuild.exe) do (set FOUND=%%~$PATH:X) diff --git a/build_windows_oidn.bat b/build_windows_oidn.bat index 25bd7885..21c33787 100644 --- a/build_windows_oidn.bat +++ b/build_windows_oidn.bat @@ -4,7 +4,7 @@ for %%X in (cmake.exe) do (set FOUND=%%~$PATH:X) if defined FOUND ( set CMAKE=cmake ) ELSE ( -set CMAKE="%CD%\build\vcpkg.windows\downloads\tools\cmake-3.27.1-windows\cmake-3.27.1-windows-i386\bin\cmake.exe" +set CMAKE="%CD%\build\vcpkg.windows\downloads\tools\cmake-3.29.2-windows\cmake-3.29.2-windows-i386\bin\cmake.exe" ) for %%X in (msbuild.exe) do (set FOUND=%%~$PATH:X) diff --git a/src/AndroidMain.cpp b/src/AndroidMain.cpp new file mode 100644 index 00000000..f862c4a1 --- /dev/null +++ b/src/AndroidMain.cpp @@ -0,0 +1,136 @@ +#include "Vulkan/Enumerate.hpp" +#include "Vulkan/Strings.hpp" +#include "Utilities/Console.hpp" +#include "Utilities/Exception.hpp" +#include "Options.hpp" +#include "Runtime/Application.hpp" +#include +#include +#include +#include +#include + +#include "Runtime/Platform/PlatformCommon.h" + +#include +#include +#include + +std::unique_ptr GApplication = nullptr; + +void handle_cmd(android_app* app, int32_t cmd) { + switch (cmd) { + case APP_CMD_INIT_WINDOW: + // The window is being shown, get it ready. + { + MakeExternalDirectory(app, "assets/fonts"); + MakeExternalDirectory(app, "assets/models"); + MakeExternalDirectory(app, "assets/shaders"); + MakeExternalDirectory(app, "assets/textures"); + MakeExternalDirectory(app, "assets/locale"); + + const char* argv[] = { "gkNextRenderer", "--renderer=4", "--scene=1", "--load-scene=qx50.glb"}; + const Options options(4, argv); + GOption = &options; + GApplication.reset(new NextRendererApplication(options)); + __android_log_print(ANDROID_LOG_INFO, "vkdemo", + "start gknextrenderer: %d", options.RendererType); + GApplication->Start(); + } + break; + case APP_CMD_TERM_WINDOW: + // The window is being hidden or closed, clean it up. + { + + } + break; + default: + __android_log_print(ANDROID_LOG_INFO, "Vulkan Tutorials", + "event not handled: %d", cmd); + } +} + +static int32_t engine_handle_input(struct android_app* app) { + ImGuiIO& io = ImGui::GetIO(); + //auto* engine = (struct engine*)app->userData; + auto ib = android_app_swap_input_buffers(app); + if (ib && ib->motionEventsCount) { + for (int i = 0; i < ib->motionEventsCount; i++) { + auto *event = &ib->motionEvents[i]; + int32_t ptrIdx = 0; + switch (event->action & AMOTION_EVENT_ACTION_MASK) { + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_POINTER_UP: + // Retrieve the index for the starting and the ending of any secondary pointers + ptrIdx = (event->action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> + AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_UP: + io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); + io.AddMousePosEvent(GameActivityPointerAxes_getAxisValue( + &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X) * 0.75, GameActivityPointerAxes_getAxisValue( + &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y) * 0.75); + io.AddMouseButtonEvent(0, event->action == AMOTION_EVENT_ACTION_DOWN); + + GApplication->OnTouch(event->action == AMOTION_EVENT_ACTION_DOWN, GameActivityPointerAxes_getAxisValue( + &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y) * 0.75, + GameActivityPointerAxes_getAxisValue( + &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X) * 0.75); + + break; + case AMOTION_EVENT_ACTION_MOVE: + // Process the move action: the new coordinates for all active touch pointers + // are inside the event->pointers[]. Compare with our internally saved + // coordinates to find out which pointers are actually moved. Note that there is + // no index embedded inside event->action for AMOTION_EVENT_ACTION_MOVE (there + // might be multiple pointers moved at the same time). + //... + io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); + io.AddMousePosEvent(GameActivityPointerAxes_getAxisValue( + &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X) * 0.75, + GameActivityPointerAxes_getAxisValue( + &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y) * 0.75); + + GApplication->OnTouchMove(GameActivityPointerAxes_getAxisValue( + &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y) * 0.75, + GameActivityPointerAxes_getAxisValue( + &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X) * 0.75); + break; + } + } + android_app_clear_motion_events(ib); + } + + // Process the KeyEvent in a similar way. + //... + +return 0; +} + +void android_main(struct android_app* app) +{ + std::cout.rdbuf(new androidbuf); + + app->onAppCmd = handle_cmd; + + // Used to poll the events in the main loop + int events; + android_poll_source* source; + + // Main loop + do { + if (ALooper_pollAll(GApplication != nullptr ? 1 : 0, nullptr, + &events, (void**)&source) >= 0) { + if (source != NULL) source->process(app, source); + } + + engine_handle_input(app); + + // render if vulkan is ready + if (GApplication != nullptr) { + GApplication->Tick(); + } + } while (app->destroyRequested == 0); + + delete std::cout.rdbuf(0); +} diff --git a/src/Application.cpp b/src/Application.cpp deleted file mode 100644 index 5cd47bd8..00000000 --- a/src/Application.cpp +++ /dev/null @@ -1,970 +0,0 @@ -#include "Application.hpp" -#include "UserInterface.hpp" -#include "UserSettings.hpp" -#include "Assets/Model.hpp" -#include "Assets/Scene.hpp" -#include "Assets/Texture.hpp" -#include "Assets/UniformBuffer.hpp" -#include "Utilities/Exception.hpp" -#include "Utilities/Console.hpp" -#include "Utilities/Glm.hpp" -#include "Vulkan/Window.hpp" -#include "Vulkan/SwapChain.hpp" -#include "Vulkan/Device.hpp" -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "Options.hpp" -#include "curl/curl.h" -#include "cpp-base64/base64.cpp" -#include "ThirdParty/json11/json11.hpp" - -#include "stb_image_write.h" - -#define _USE_MATH_DEFINES -#include - -#include "TaskCoordinator.hpp" -#include "Editor/EditorCommand.hpp" -#include "Utilities/Localization.hpp" - -#include "Vulkan/RayQuery/RayQueryRenderer.hpp" -#include "Vulkan/RayTrace/RayTracingRenderer.hpp" -#include "Vulkan/HybridDeferred/HybridDeferredRenderer.hpp" -#include "Vulkan/LegacyDeferred/LegacyDeferredRenderer.hpp" -#include "Vulkan/ModernDeferred/ModernDeferredRenderer.hpp" - -#if WITH_AVIF -#include "avif/avif.h" -#endif - -namespace -{ - const bool EnableValidationLayers = -#if defined(NDEBUG) || defined(ANDROID) - false; -#else - true; -#endif - - struct SceneTaskContext - { - float elapsed; - std::array outputInfo; - }; -} - -template -NextRendererApplication::NextRendererApplication(const UserSettings& userSettings, - const Vulkan::WindowConfig& windowConfig, - const VkPresentModeKHR presentMode) : - Renderer(Renderer::StaticClass(), windowConfig, presentMode, EnableValidationLayers), - userSettings_(userSettings) -{ - CheckFramebufferSize(); - - status_ = NextRenderer::EApplicationStatus::Starting; - -#if !ANDROID - Utilities::Localization::ReadLocTexts(fmt::format("assets/locale/{}.txt", GOption->locale).c_str()); - - EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdSystem_RequestExit, [this](std::string& args)->bool { - GetWindow().Close(); - return true; - }); - EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdSystem_RequestMaximum, [this](std::string& args)->bool { - GetWindow().Maximum(); - return true; - }); - EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdSystem_RequestMinimize, [this](std::string& args)->bool { - GetWindow().Minimize(); - return true; - }); - EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdIO_LoadScene, [this](std::string& args)->bool { - userSettings_.SceneIndex = SceneList::AddExternalScene(args); - return true; - }); - EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdIO_LoadHDRI, [this](std::string& args)->bool { - Assets::GlobalTexturePool::UpdateHDRTexture(0, args.c_str(), Vulkan::SamplerConfig()); - userSettings_.SkyIdx = 0; - return true; - }); -#endif -} - -template -NextRendererApplication::~NextRendererApplication() -{ -#if !ANDROID - Utilities::Localization::SaveLocTexts(fmt::format("assets/locale/{}.txt", GOption->locale).c_str()); -#endif - scene_.reset(); -} - -template -Assets::UniformBufferObject NextRendererApplication::GetUniformBufferObject(const VkOffset2D offset, const VkExtent2D extent) const -{ - glm::mat4 pre_rotate_mat = glm::mat4(1.0f); - glm::vec3 rotation_axis = glm::vec3(0.0f, 0.0f, 1.0f); - - //if (pretransformFlag & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { - pre_rotate_mat = glm::rotate(pre_rotate_mat, glm::radians(90.0f), rotation_axis); - //} - - if(userSettings_.CameraIdx >= 0 && previousSettings_.CameraIdx != userSettings_.CameraIdx) - { - modelViewController_.Reset((userSettings_.cameras[userSettings_.CameraIdx]).ModelView); - } - - const auto& init = cameraInitialSate_; - - Assets::UniformBufferObject ubo = {}; - - ubo.ModelView = modelViewController_.ModelView(); - ubo.Projection = glm::perspective(glm::radians(userSettings_.FieldOfView), - extent.width / static_cast(extent.height), 0.1f, 10000.0f); - ubo.Projection[1][1] *= -1; -#if ANDROID - ubo.Projection = glm::perspective(glm::radians(userSettings_.FieldOfView), - extent.height / static_cast(extent.width), 0.1f, 10000.0f); - ubo.Projection[1][1] *= -1; - ubo.Projection = pre_rotate_mat * ubo.Projection; -#endif - // Inverting Y for Vulkan, https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/ - ubo.ModelViewInverse = glm::inverse(ubo.ModelView); - ubo.ProjectionInverse = glm::inverse(ubo.Projection); - ubo.ViewProjection = ubo.Projection * ubo.ModelView; - ubo.PrevViewProjection = prevUBO_.TotalFrames != 0 ? prevUBO_.ViewProjection : ubo.ViewProjection; - - ubo.ViewportRect = glm::vec4(offset.x, offset.y, extent.width, extent.height); - - glm::vec2 pixel = mousePos_ - glm::vec2(offset.x, offset.y); - glm::vec2 uv = pixel / glm::vec2(extent.width, extent.height) * glm::vec2(2.0,2.0) - glm::vec2(1.0,1.0); - glm::vec4 origin = ubo.ModelViewInverse * glm::vec4(0, 0, 0, 1); - glm::vec4 target = ubo.ProjectionInverse * (glm::vec4(uv.x, uv.y, 1, 1)); - - glm::vec3 raydir = ubo.ModelViewInverse * glm::vec4(normalize((glm::vec3(target) - glm::vec3(0.0,0.0,0.0))), 0.0); - glm::vec3 rayorg = glm::vec3(origin); - - Renderer::SetRaycastRay(rayorg, raydir); - - Assets::RayCastResult rayResult {}; - Renderer::GetLastRaycastResult(rayResult); - - if( userSettings_.AutoFocus ) - { - if(rayResult.Hitted ) - { - userSettings_.FocusDistance = rayResult.T; - scene_->SetSelectedId(rayResult.InstanceId); - } - else - { - scene_->SetSelectedId(-1); - } - } - - ubo.SelectedId = scene_->GetSelectedId(); - - userSettings_.HitResult = rayResult; - - ubo.Aperture = userSettings_.Aperture; - ubo.FocusDistance = userSettings_.FocusDistance; - - - ubo.SkyRotation = userSettings_.SkyRotation; - ubo.MaxNumberOfBounces = userSettings_.MaxNumberOfBounces; - ubo.TotalFrames = totalFrames_; - ubo.NumberOfSamples = userSettings_.NumberOfSamples; - ubo.NumberOfBounces = userSettings_.NumberOfBounces; - ubo.RR_MIN_DEPTH = userSettings_.RR_MIN_DEPTH; - ubo.AdaptiveSample = userSettings_.AdaptiveSample; - ubo.AdaptiveVariance = userSettings_.AdaptiveVariance; - ubo.AdaptiveSteps = userSettings_.AdaptiveSteps; - ubo.TAA = userSettings_.TAA; - ubo.RandomSeed = rand(); - ubo.SunDirection = glm::vec4( glm::normalize(glm::vec3( sinf(float( userSettings_.SunRotation * M_PI )), 0.75f, cosf(float( userSettings_.SunRotation * M_PI )) )), 0.0f ); - ubo.SunColor = glm::vec4(1,1,1, 0) * userSettings_.SunLuminance; - ubo.SkyIntensity = userSettings_.SkyIntensity; - ubo.SkyIdx = userSettings_.SkyIdx; - ubo.BackGroundColor = glm::vec4(0.4, 0.6, 1.0, 0.0) * 4.0f * userSettings_.SkyIntensity; - ubo.HasSky = init.HasSky; - ubo.HasSun = init.HasSun && userSettings_.SunLuminance > 0; - ubo.ShowHeatmap = false; - ubo.HeatmapScale = userSettings_.HeatmapScale; - ubo.UseCheckerBoard = userSettings_.UseCheckerBoardRendering; - ubo.TemporalFrames = userSettings_.TemporalFrames; - ubo.HDR = Renderer::SwapChain().IsHDR(); - - ubo.PaperWhiteNit = userSettings_.PaperWhiteNit; - - ubo.LightCount = scene_->GetLightCount(); - - prevUBO_ = ubo; - - return ubo; -} - -template -void NextRendererApplication::SetPhysicalDeviceImpl( - VkPhysicalDevice physicalDevice, - std::vector& requiredExtensions, - VkPhysicalDeviceFeatures& deviceFeatures, - void* nextDeviceFeatures) -{ - deviceFeatures.fillModeNonSolid = true; - deviceFeatures.samplerAnisotropy = true; - - // Required extensions. windows only -#if WIN32 - requiredExtensions.insert(requiredExtensions.end(), - { - // VK_KHR_SHADER_CLOCK is required for heatmap - VK_KHR_SHADER_CLOCK_EXTENSION_NAME - }); - - // Opt-in into mandatory device features. - VkPhysicalDeviceShaderClockFeaturesKHR shaderClockFeatures = {}; - shaderClockFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR; - shaderClockFeatures.pNext = nextDeviceFeatures; - shaderClockFeatures.shaderSubgroupClock = true; - - deviceFeatures.shaderInt64 = true; - Renderer::SetPhysicalDeviceImpl(physicalDevice, requiredExtensions, deviceFeatures, &shaderClockFeatures); -#else - Renderer::SetPhysicalDeviceImpl(physicalDevice, requiredExtensions, deviceFeatures, nextDeviceFeatures); -#endif -} - -template -void NextRendererApplication::OnDeviceSet() -{ - Renderer::OnDeviceSet(); - - // global textures - // texture id 0: dynamic hdri sky - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/std_env.hdr"), Vulkan::SamplerConfig()); - - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/canary_wharf_1k.hdr"), Vulkan::SamplerConfig()); - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/kloppenheim_01_puresky_1k.hdr"), Vulkan::SamplerConfig()); - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/kloppenheim_07_1k.hdr"), Vulkan::SamplerConfig()); - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/river_road_2.hdr"), Vulkan::SamplerConfig()); - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/rainforest_trail_1k.hdr"), Vulkan::SamplerConfig()); - - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/studio_small_03_1k.hdr"), Vulkan::SamplerConfig()); - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/studio_small_09_1k.hdr"), Vulkan::SamplerConfig()); - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/sunset_fairway_1k.hdr"), Vulkan::SamplerConfig()); - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/umhlanga_sunrise_1k.hdr"), Vulkan::SamplerConfig()); - Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/shanghai_bund_1k.hdr"), Vulkan::SamplerConfig()); - - if(GOption->HDRIfile != "") Assets::GlobalTexturePool::UpdateHDRTexture(0, GOption->HDRIfile.c_str(), Vulkan::SamplerConfig()); - - std::vector models; - std::vector nodes; - std::vector materials; - std::vector lights; - Assets::CameraInitialSate cameraState; - - scene_.reset(new Assets::Scene(Renderer::CommandPool(), nodes, models, - materials, lights, Renderer::supportRayTracing_)); - - Renderer::OnPostLoadScene(); - - status_ = NextRenderer::EApplicationStatus::Running; -} - -template -void NextRendererApplication::CreateSwapChain() -{ - Renderer::CreateSwapChain(); - - userInterface_.reset(new UserInterface(Renderer::CommandPool(), Renderer::SwapChain(), Renderer::DepthBuffer(), - userSettings_, Renderer::GetRenderImage())); - - CheckFramebufferSize(); -} - -template -void NextRendererApplication::DeleteSwapChain() -{ - userInterface_.reset(); - - Renderer::DeleteSwapChain(); -} - -template -void NextRendererApplication::DrawFrame() -{ - // Check if the scene has been changed by the user. - if (status_ == NextRenderer::EApplicationStatus::Running && sceneIndex_ != static_cast(userSettings_.SceneIndex)) - { - LoadScene(userSettings_.SceneIndex); - //return; - } - - previousSettings_ = userSettings_; - - Renderer::DrawFrame(); - - totalFrames_ += 1; -} - -template -void NextRendererApplication::Render(VkCommandBuffer commandBuffer, const uint32_t imageIndex) -{ - const auto prevTime = time_; - time_ = Renderer::Window().GetTime(); - const auto timeDelta = time_ - prevTime; - - // Update the camera position / angle. - modelViewController_.UpdateCamera(cameraInitialSate_.ControlSpeed, timeDelta); - - Renderer::supportDenoiser_ = userSettings_.Denoiser; - Renderer::checkerboxRendering_ = userSettings_.UseCheckerBoardRendering; - - // Render the scene if scene loaded - if(cameraInitialSate_.CameraIdx != -1) - { - Renderer::Render(commandBuffer, imageIndex); - } - - // Check the current state of the benchmark, update it for the new frame. - if(status_ == NextRenderer::EApplicationStatus::Running) - { - CheckAndUpdateBenchmarkState(prevTime); - } -} - -template -void NextRendererApplication::RenderUI(VkCommandBuffer commandBuffer, uint32_t imageIndex) -{ - static float frameRate = 0.0; - static double lastTime = 0.0; - static double lastTimestamp = 0.0; - double now = Renderer::Window().GetTime(); - - // Record delta time between calls to Render. - if(totalFrames_ % 30 == 0) - { - const auto timeDelta = now - lastTime; - lastTime = now; - frameRate = static_cast(30 / timeDelta); - } - - // Render the UI - Statistics stats = {}; - - stats.FrameTime = static_cast((now - lastTimestamp) * 1000.0); - lastTimestamp = now; - - stats.Stats["gpu"] = Renderer::Device().DeviceProperties().deviceName; - - stats.FramebufferSize = Renderer::Window().FramebufferSize(); - stats.FrameRate = frameRate; - - - stats.TotalFrames = totalFrames_; - stats.RenderTime = time_ - sceneInitialTime_; - - stats.CamPosX = modelViewController_.Position()[0]; - stats.CamPosY = modelViewController_.Position()[1]; - stats.CamPosZ = modelViewController_.Position()[2]; - - stats.InstanceCount = static_cast(scene_->Nodes().size()); - stats.TriCount = scene_->GetIndicesCount() / 3; - stats.TextureCount = Assets::GlobalTexturePool::GetInstance()->TotalTextures(); - stats.ComputePassCount = 0; - stats.LoadingStatus = status_ == NextRenderer::EApplicationStatus::Loading; - - Renderer::visualDebug_ = userSettings_.ShowVisualDebug; - - userInterface_->Render(commandBuffer, imageIndex, stats, Renderer::GpuTimer(), scene_.get()); -} - -template -void NextRendererApplication::OnKey(int key, int scancode, int action, int mods) -{ - if (userInterface_->WantsToCaptureKeyboard()) - { - return; - } -#if !ANDROID - if (action == GLFW_PRESS) - { - switch (key) - { - case GLFW_KEY_ESCAPE: Renderer::Window().Close(); - break; - default: break; - } - - // Settings (toggle switches) - if (!userSettings_.Benchmark) - { - switch (key) - { - case GLFW_KEY_F1: userSettings_.ShowSettings = !userSettings_.ShowSettings; - break; - case GLFW_KEY_F2: userSettings_.ShowOverlay = !userSettings_.ShowOverlay; - break; - case GLFW_KEY_SPACE: userSettings_.AutoFocus = true; - break; - default: break; - } - } - } - else if(action == GLFW_RELEASE) - { - if (!userSettings_.Benchmark) - { - switch (key) - { - case GLFW_KEY_SPACE: userSettings_.AutoFocus = false; - break; - default: break; - } - } - } -#endif - - // Camera motions - if (!userSettings_.Benchmark) - { - modelViewController_.OnKey(key, scancode, action, mods); - } -} - -template -void NextRendererApplication::OnCursorPosition(const double xpos, const double ypos) -{ - if (!Renderer::HasSwapChain() || - userSettings_.Benchmark || - userInterface_->WantsToCaptureKeyboard() || - userInterface_->WantsToCaptureMouse() - ) - { - return; - } - - // Camera motions - modelViewController_.OnCursorPosition(xpos, ypos); - - mousePos_ = glm::vec2(xpos, ypos); -} - -template -void NextRendererApplication::OnMouseButton(const int button, const int action, const int mods) -{ - if (!Renderer::HasSwapChain() || - userSettings_.Benchmark || - userInterface_->WantsToCaptureMouse()) - { - return; - } - - // Camera motions - modelViewController_.OnMouseButton(button, action, mods); -#if !ANDROID - if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) - { - userSettings_.AutoFocus = true; - } - else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) - { - userSettings_.AutoFocus = false; - } -#endif -} - -template -void NextRendererApplication::OnScroll(const double xoffset, const double yoffset) -{ - if (!Renderer::HasSwapChain() || - userSettings_.Benchmark || - userInterface_->WantsToCaptureMouse()) - { - return; - } - const auto prevFov = userSettings_.FieldOfView; - userSettings_.FieldOfView = std::clamp( - static_cast(prevFov - yoffset), - UserSettings::FieldOfViewMinValue, - UserSettings::FieldOfViewMaxValue); -} - -template -void NextRendererApplication::OnDropFile(int path_count, const char* paths[]) -{ - // add glb to the last, and loaded - if (path_count > 0) - { - std::string path = paths[path_count - 1]; - std::string ext = path.substr(path.find_last_of(".") + 1); - std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); - - if (ext == "glb") - { - userSettings_.SceneIndex = SceneList::AddExternalScene(path); - } - - if( ext == "hdr") - { - Assets::GlobalTexturePool::UpdateHDRTexture(0, path, Vulkan::SamplerConfig()); - userSettings_.SkyIdx = 0; - } - } -} - -template -void NextRendererApplication::BeforeNextFrame() -{ - TaskCoordinator::GetInstance()->Tick(); - Renderer::BeforeNextFrame(); -} - -template -void NextRendererApplication::OnTouch(bool down, double xpos, double ypos) -{ - modelViewController_.OnTouch(down, xpos, ypos); -} - -template -void NextRendererApplication::OnTouchMove(double xpos, double ypos) -{ - modelViewController_.OnCursorPosition(xpos, ypos); -} - -template -void NextRendererApplication::LoadScene(const uint32_t sceneIndex) -{ - status_ = NextRenderer::EApplicationStatus::Loading; - - std::shared_ptr< std::vector > models = std::make_shared< std::vector >(); - std::shared_ptr< std::vector > nodes = std::make_shared< std::vector >(); - std::shared_ptr< std::vector > materials = std::make_shared< std::vector >(); - std::shared_ptr< std::vector > lights = std::make_shared< std::vector >(); - std::shared_ptr< Assets::CameraInitialSate > cameraState = std::make_shared< Assets::CameraInitialSate >(); - - cameraInitialSate_.cameras.clear(); - cameraInitialSate_.CameraIdx = -1; - - // dispatch in thread task and reset in main thread - TaskCoordinator::GetInstance()->AddTask( [cameraState, sceneIndex, models, nodes, materials, lights](ResTask& task) - { - SceneTaskContext taskContext {}; - const auto timer = std::chrono::high_resolution_clock::now(); - - SceneList::AllScenes[sceneIndex].second(*cameraState, *nodes, *models, *materials, *lights); - - taskContext.elapsed = std::chrono::duration(std::chrono::high_resolution_clock::now() - timer).count(); - - std::string info = fmt::format("parsed scene #{} on cpu in {:.2f}ms", sceneIndex, taskContext.elapsed * 1000.f); - std::copy(info.begin(), info.end(), taskContext.outputInfo.data()); - task.SetContext( taskContext ); - }, - [this, cameraState, sceneIndex, models, nodes, materials, lights](ResTask& task) - { - SceneTaskContext taskContext {}; - task.GetContext( taskContext ); - fmt::print("{} {}{}\n", CONSOLE_GREEN_COLOR, taskContext.outputInfo.data(), CONSOLE_DEFAULT_COLOR); - - const auto timer = std::chrono::high_resolution_clock::now(); - - cameraInitialSate_ = *cameraState; - - Renderer::Device().WaitIdle(); - DeleteSwapChain(); - Renderer::OnPreLoadScene(); - - scene_.reset(new Assets::Scene(Renderer::CommandPool(), *nodes, *models, - *materials, *lights, Renderer::supportRayTracing_)); - - sceneIndex_ = sceneIndex; - - userSettings_.FieldOfView = cameraInitialSate_.FieldOfView; - userSettings_.Aperture = cameraInitialSate_.Aperture; - userSettings_.FocusDistance = cameraInitialSate_.FocusDistance; - userSettings_.SkyIdx = cameraInitialSate_.SkyIdx; - userSettings_.SunRotation = cameraInitialSate_.SunRotation; - - userSettings_.cameras = cameraInitialSate_.cameras; - userSettings_.CameraIdx = cameraInitialSate_.CameraIdx; - - modelViewController_.Reset(cameraInitialSate_.ModelView); - - periodTotalFrames_ = 0; - totalFrames_ = 0; - benchmarkTotalFrames_ = 0; - sceneInitialTime_ = Renderer::Window().GetTime(); - - Renderer::OnPostLoadScene(); - CreateSwapChain(); - - float elapsed = std::chrono::duration(std::chrono::high_resolution_clock::now() - timer).count(); - - fmt::print("{} uploaded scene #{} to gpu in {:.2f}ms{}\n", CONSOLE_GREEN_COLOR, sceneIndex, elapsed * 1000.f, CONSOLE_DEFAULT_COLOR); - - sceneIndex_ = sceneIndex; - status_ = NextRenderer::EApplicationStatus::Running; - }, - 1); -} - -template -void NextRendererApplication::CheckAndUpdateBenchmarkState(double prevTime) -{ - if (!userSettings_.Benchmark) - { - return; - } - - // Initialise scene benchmark timers - if (periodTotalFrames_ == 0) - { - if (benchmarkNumber_ == 0) - { - std::time_t now = std::time(nullptr); - std::string report_filename = fmt::format("report_{:%d-%m-%Y-%H-%M-%S}.csv", fmt::localtime(now)); - benchmarkCsvReportFile.open(report_filename); - benchmarkCsvReportFile << fmt::format("#;scene;FPS\n"); - } - - fmt::print("\n\nRenderer: {}\n", Renderer::StaticClass()); - fmt::print("Benchmark: Start scene #{} '{}'\n", sceneIndex_, SceneList::AllScenes[sceneIndex_].first); - periodInitialTime_ = time_; - } - - // Print out the frame rate at regular intervals. - { - const double period = 5; - const double prevTotalTime = prevTime - periodInitialTime_; - const double totalTime = time_ - periodInitialTime_; - - if (periodTotalFrames_ != 0 && static_cast(prevTotalTime / period) != static_cast(totalTime - / period)) - { - fmt::print("Benchmark: {:.3f}\n", float(periodTotalFrames_) / float(totalTime)); - periodInitialTime_ = time_; - periodTotalFrames_ = 0; - benchmarkNumber_++; - } - - periodTotalFrames_++; - benchmarkTotalFrames_++; - } - - // If in benchmark mode, bail out from the scene if we've reached the time or sample limit. - { - const bool timeLimitReached = userSettings_.BenchmarkMaxFrame == 0 && periodTotalFrames_ != 0 && time_ - sceneInitialTime_ > - userSettings_.BenchmarkMaxTime; - const bool frameLimitReached = userSettings_.BenchmarkMaxFrame > 0 && benchmarkTotalFrames_ >= userSettings_.BenchmarkMaxFrame; - if (timeLimitReached || frameLimitReached) - { - { - const double totalTime = time_ - sceneInitialTime_; - std::string SceneName = SceneList::AllScenes[userSettings_.SceneIndex].first; - double fps = benchmarkTotalFrames_ / totalTime; - - fmt::print("\n*** totalTime {:%H:%M:%S} fps {:.3f}\n", std::chrono::seconds(static_cast(totalTime)), fps); - - Report(static_cast(floor(fps)), SceneName, false, GOption->SaveFile); - benchmarkCsvReportFile << fmt::format("{};{};{:.3f}\n", sceneIndex_, SceneList::AllScenes[sceneIndex_].first, fps); - } - - if (!userSettings_.BenchmarkNextScenes || static_cast(userSettings_.SceneIndex) == - SceneList::AllScenes.size() - 1) - { - Renderer::Window().Close(); - } - - puts(""); - userSettings_.SceneIndex += 1; - } - } -} - -template -void NextRendererApplication::CheckFramebufferSize() const -{ - // Check the framebuffer size when requesting a fullscreen window, as it's not guaranteed to match. - const auto& cfg = Renderer::Window().Config(); - const auto fbSize = Renderer::Window().FramebufferSize(); - - if (userSettings_.Benchmark && cfg.Fullscreen && (fbSize.width != cfg.Width || fbSize.height != cfg.Height)) - { - std::string out = fmt::format("framebuffer fullscreen size mismatch (requested: {}x{}, got: {}x{})", cfg.Width, cfg.Height, fbSize.width, fbSize.height); - - Throw(std::runtime_error(out)); - } -} - -inline const std::string versionToString(const uint32_t version) -{ - return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version)); -} - -template -void NextRendererApplication::Report(int fps, const std::string& sceneName, bool upload_screen, bool save_screen) -{ - VkPhysicalDeviceProperties deviceProp1{}; - vkGetPhysicalDeviceProperties(Renderer::Device().PhysicalDevice(), &deviceProp1); - - std::string img_encoded {}; - if (upload_screen || save_screen) - { -#if WITH_AVIF - // screenshot stuffs - const Vulkan::SwapChain& swapChain = Renderer::SwapChain(); - const auto extent = swapChain.Extent(); - - // capture and export - Renderer::CaptureScreenShot(); - - constexpr uint32_t kCompCnt = 3; - int imageSize = extent.width * extent.height * kCompCnt; - - avifImage* image = avifImageCreate(extent.width, extent.height, swapChain.IsHDR() ? 10 : 8, AVIF_PIXEL_FORMAT_YUV444); // these values dictate what goes into the final AVIF - if (!image) - { - Throw(std::runtime_error("avif image creation failed")); - } - image->yuvRange = AVIF_RANGE_FULL; - image->colorPrimaries = swapChain.IsHDR() ? AVIF_COLOR_PRIMARIES_BT2020 : AVIF_COLOR_PRIMARIES_BT709; - image->transferCharacteristics = swapChain.IsHDR() ? AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084 : AVIF_TRANSFER_CHARACTERISTICS_BT709; - image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY; - image->clli.maxCLL = static_cast(userSettings_.PaperWhiteNit); //maxCLLNits; - image->clli.maxPALL = 0; //maxFALLNits; - - avifEncoder* encoder = NULL; - avifRWData avifOutput = AVIF_DATA_EMPTY; - - avifRGBImage rgbAvifImage{}; - avifRGBImageSetDefaults(&rgbAvifImage, image); - rgbAvifImage.format = AVIF_RGB_FORMAT_RGB; - rgbAvifImage.ignoreAlpha = AVIF_TRUE; - - void* data = nullptr; - if(swapChain.IsHDR()) - { - size_t hdrsize = rgbAvifImage.width * rgbAvifImage.height * 3 * 2; - data = malloc(hdrsize); - uint16_t* dataview = (uint16_t*)data; - { - Vulkan::DeviceMemory* vkMemory = Renderer::GetScreenShotMemory(); - - uint8_t* mappedData = (uint8_t*)vkMemory->Map(0, VK_WHOLE_SIZE); - - uint32_t yDelta = extent.width * kCompCnt; - uint32_t xDelta = kCompCnt; - uint32_t idxDelta = extent.width * 4; - uint32_t yy = 0; - uint32_t xx = 0, idx = 0; - for (uint32_t y = 0; y < extent.height; y++) - { - xx = 0; - for (uint32_t x = 0; x < extent.width; x++) - { - uint32_t* pInPixel = (uint32_t*)&mappedData[idx]; - uint32_t uInPixel = *pInPixel; - dataview[yy + xx + 2] = (uInPixel & (0b1111111111 << 20)) >> 20; - dataview[yy + xx + 1] = (uInPixel & (0b1111111111 << 10)) >> 10; - dataview[yy + xx + 0] = (uInPixel & (0b1111111111 << 0)) >> 0; - - idx += 4; - xx += xDelta; - } - //idx += idxDelta; - yy += yDelta; - } - vkMemory->Unmap(); - } - - rgbAvifImage.pixels = (uint8_t*)data; - rgbAvifImage.rowBytes = rgbAvifImage.width * 3 * sizeof(uint16_t); - } - else - { - data = malloc(imageSize); - uint8_t* dataview = (uint8_t*)data; - { - Vulkan::DeviceMemory* vkMemory = Renderer::GetScreenShotMemory(); - - uint8_t* mappedData = (uint8_t*)vkMemory->Map(0, VK_WHOLE_SIZE); - - uint32_t yDelta = extent.width * kCompCnt; - uint32_t xDelta = kCompCnt; - uint32_t idxDelta = extent.width * 4; - uint32_t yy = 0; - uint32_t xx = 0, idx = 0; - for (uint32_t y = 0; y < extent.height; y++) - { - xx = 0; - for (uint32_t x = 0; x < extent.width; x++) - { - uint32_t* pInPixel = (uint32_t*)&mappedData[idx]; - uint32_t uInPixel = *pInPixel; - - dataview[yy + xx] = (uInPixel & (0b11111111 << 16)) >> 16; - dataview[yy + xx + 1] = (uInPixel & (0b11111111 << 8)) >> 8; - dataview[yy + xx + 2] = (uInPixel & (0b11111111 << 0)) >> 0; - - idx += 4; - xx += xDelta; - } - yy += yDelta; - } - vkMemory->Unmap(); - } - - rgbAvifImage.pixels = (uint8_t*)data; - rgbAvifImage.rowBytes = rgbAvifImage.width * 3 * sizeof(uint8_t); - } - - - - avifResult convertResult = avifImageRGBToYUV(image, &rgbAvifImage); - if (convertResult != AVIF_RESULT_OK) - { - Throw(std::runtime_error("Failed to convert RGB to YUV: " + std::string(avifResultToString(convertResult)))); - } - encoder = avifEncoderCreate(); - if (!encoder) - { - Throw(std::runtime_error("Failed to create encoder")); - } - encoder->quality = 80; - encoder->qualityAlpha = AVIF_QUALITY_LOSSLESS; - encoder->speed = AVIF_SPEED_FASTEST; - - avifResult addImageResult = avifEncoderAddImage(encoder, image, 1, AVIF_ADD_IMAGE_FLAG_SINGLE); - if (addImageResult != AVIF_RESULT_OK) - { - Throw(std::runtime_error("Failed to add image: " + std::string(avifResultToString(addImageResult)))); - } - avifResult finishResult = avifEncoderFinish(encoder, &avifOutput); - if (finishResult != AVIF_RESULT_OK) - { - Throw(std::runtime_error("Failed to finish encoding: " + std::string(avifResultToString(finishResult)))); - } - - // save to file with scenename - std::string filename = sceneName + ".avif"; - std::wfstream file(filename.c_str()); - file << avifOutput.data; - file.close(); - - free(data); - - // send to server - img_encoded = base64_encode(avifOutput.data, avifOutput.size, false); -#else - // screenshot stuffs - const Vulkan::SwapChain& swapChain = Renderer::SwapChain(); - const auto extent = swapChain.Extent(); - - // capture and export - Renderer::CaptureScreenShot(); - - constexpr uint32_t kCompCnt = 3; - int imageSize = extent.width * extent.height * kCompCnt; - - uint8_t* data = (uint8_t*)malloc(imageSize); - { - Vulkan::DeviceMemory* vkMemory = Renderer::GetScreenShotMemory(); - - uint8_t* mappedData = (uint8_t*)vkMemory->Map(0, imageSize); - - uint32_t yDelta = extent.width * kCompCnt; - uint32_t xDelta = kCompCnt; - uint32_t idxDelta = extent.width * 4; - uint32_t yy = 0; - uint32_t xx = 0, idx = 0; - for (uint32_t y = 0; y < extent.height; y++) - { - xx = 0; - for (uint32_t x = 0; x < extent.width; x++) - { - uint32_t* pInPixel = (uint32_t*)&mappedData[idx]; - uint32_t uInPixel = *pInPixel; - - data[yy + xx] = (uInPixel & (0b11111111 << 16)) >> 16; - data[yy + xx + 1] = (uInPixel & (0b11111111 << 8)) >> 8; - data[yy + xx + 2] = (uInPixel & (0b11111111 << 0)) >> 0; - - idx += 4; - xx += xDelta; - } - yy += yDelta; - } - vkMemory->Unmap(); - } - - // save to file with scenename - std::string filename = sceneName + ".jpg"; - stbi_write_jpg(filename.c_str(), extent.width, extent.height, kCompCnt, (const void*)data, 91); - fmt::print("screenshot saved to {}\n", filename); - std::uintmax_t img_file_size = std::filesystem::file_size(filename); - fmt::print("file size: {}\n", Utilities::metricFormatter(static_cast(img_file_size), "b", 1024)); - // send to server - //img_encoded = base64_encode(data, img_file_size, false); - free(data); -#endif - } - - if( NextRenderer::GetBuildVersion() != "v0.0.0.0" ) - { - json11::Json my_json = json11::Json::object{ - {"renderer", Renderer::StaticClass()}, - {"scene", sceneName}, - {"gpu", std::string(deviceProp1.deviceName)}, - {"driver", versionToString(deviceProp1.driverVersion)}, - {"fps", fps}, - {"version", NextRenderer::GetBuildVersion()}, - {"screenshot", img_encoded} - }; - std::string json_str = my_json.dump(); - - fmt::print("Sending benchmark to perf server...\n"); - // upload from curl - CURL* curl; - CURLcode res; - curl_global_init(CURL_GLOBAL_ALL); - curl = curl_easy_init(); - if (curl) - { - curl_slist* slist1 = nullptr; - slist1 = curl_slist_append(slist1, "Content-Type: application/json"); - slist1 = curl_slist_append(slist1, "Accept: application/json"); - - /* set custom headers */ - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1); - curl_easy_setopt(curl, CURLOPT_URL, "http://gameknife.site:60010/rt_benchmark"); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_str.c_str()); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L); - - /* Perform the request, res gets the return code */ - res = curl_easy_perform(curl); - /* Check for errors */ - if (res != CURLE_OK) - fmt::print(stderr, "curl_easy_perform() failed: {}\n", curl_easy_strerror(res)); - - /* always cleanup */ - curl_easy_cleanup(curl); - } - } -} - -// export it -template class NextRendererApplication; -template class NextRendererApplication; -template class NextRendererApplication; -template class NextRendererApplication; -template class NextRendererApplication; -template class NextRendererApplication; diff --git a/src/Application.hpp b/src/Application.hpp deleted file mode 100644 index f656af1e..00000000 --- a/src/Application.hpp +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include "ModelViewController.hpp" -#include "SceneList.hpp" -#include "UserSettings.hpp" -#include "Assets/UniformBuffer.hpp" -#include "Assets/Model.hpp" -#include "Vulkan/FrameBuffer.hpp" -#include "Vulkan/WindowConfig.hpp" -#include "Vulkan/VulkanBaseRenderer.hpp" - -#include - -namespace NextRenderer -{ - enum class EApplicationStatus - { - Starting, - Running, - Loading, - AsyncPreparing, - }; - - std::string GetBuildVersion(); -} - - -template -class NextRendererApplication final : public Renderer -{ -public: - - VULKAN_NON_COPIABLE(NextRendererApplication) - - NextRendererApplication(const UserSettings& userSettings, const Vulkan::WindowConfig& windowConfig, VkPresentModeKHR presentMode); - ~NextRendererApplication(); - - void OnTouch(bool down, double xpos, double ypos) override; - void OnTouchMove(double xpos, double ypos) override; - -protected: - - const Assets::Scene& GetScene() const override { return *scene_; } - Assets::UniformBufferObject GetUniformBufferObject(const VkOffset2D offset, const VkExtent2D extent) const override; - - void SetPhysicalDeviceImpl( - VkPhysicalDevice physicalDevice, - std::vector& requiredExtensions, - VkPhysicalDeviceFeatures& deviceFeatures, - void* nextDeviceFeatures) override; - - void OnDeviceSet() override; - void CreateSwapChain() override; - void DeleteSwapChain() override; - void DrawFrame() override; - void Render(VkCommandBuffer commandBuffer, uint32_t imageIndex) override; - void RenderUI(VkCommandBuffer commandBuffer, uint32_t imageIndex) override; - void OnKey(int key, int scancode, int action, int mods) override; - void OnCursorPosition(double xpos, double ypos) override; - void OnMouseButton(int button, int action, int mods) override; - void OnScroll(double xoffset, double yoffset) override; - void OnDropFile(int path_count, const char* paths[]) override; - void BeforeNextFrame() override; - - Vulkan::Window& GetWindow() {return Renderer::Window();} -private: - - void LoadScene(uint32_t sceneIndex); - void CheckAndUpdateBenchmarkState(double prevTime); - void CheckFramebufferSize() const; - - void Report(int fps, const std::string& sceneName, bool upload_screen, bool save_screen); - - uint32_t sceneIndex_{((uint32_t)~((uint32_t)0))}; - mutable UserSettings userSettings_{}; - UserSettings previousSettings_{}; - Assets::CameraInitialSate cameraInitialSate_{}; - - mutable ModelViewController modelViewController_{}; - - mutable Assets::UniformBufferObject prevUBO_ {}; - - std::unique_ptr scene_; - std::unique_ptr userInterface_; - - double time_{}; - - NextRenderer::EApplicationStatus status_{}; - - uint32_t totalFrames_{}; - - // Benchmark stats - double sceneInitialTime_{}; - double periodInitialTime_{}; - uint32_t periodTotalFrames_{}; - uint32_t benchmarkTotalFrames_{}; - uint32_t benchmarkNumber_{0}; - std::ofstream benchmarkCsvReportFile; - - glm::vec2 mousePos_ {}; -}; diff --git a/src/Assets/Texture.cpp b/src/Assets/Texture.cpp index 597c69e8..a75103da 100644 --- a/src/Assets/Texture.cpp +++ b/src/Assets/Texture.cpp @@ -5,7 +5,8 @@ #include #include -#include "TaskCoordinator.hpp" +#include "Options.hpp" +#include "Runtime/TaskCoordinator.hpp" #include "TextureImage.hpp" #include "Vulkan/Device.hpp" #include "Vulkan/ImageView.hpp" @@ -211,7 +212,7 @@ namespace Assets { TextureTaskContext taskContext {}; task.GetContext( taskContext ); - fmt::print("{}\n", taskContext.outputInfo.data()); + if(!GOption->Benchmark) fmt::print("{}\n", taskContext.outputInfo.data()); }, 0); // cache in namemap @@ -304,7 +305,7 @@ namespace Assets TextureTaskContext taskContext {}; task.GetContext( taskContext ); textureImages_[taskContext.textureId]->MainThreadPostLoading(mainThreadCommandPool_); - fmt::print("{}\n", taskContext.outputInfo.data()); + if(!GOption->Benchmark) fmt::print("{}\n", taskContext.outputInfo.data()); delete[] copyedData; }, 0); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 075bbe1a..8e9104aa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -180,6 +180,7 @@ set_source_files_properties( COMPILE_FLAGS "-w" ) endif() + set(src_files_editor Editor/EditorMain.cpp Editor/EditorMain.h @@ -202,21 +203,29 @@ set(src_files_editor Editor/Nodes/NodeMaterial.hpp ) +set(src_files_runtime + Runtime/ModelViewController.cpp + Runtime/ModelViewController.hpp + Runtime/Application.cpp + Runtime/Application.hpp + Runtime/SceneList.cpp + Runtime/SceneList.hpp + Runtime/UserInterface.cpp + Runtime/UserInterface.hpp + Runtime/UserSettings.hpp + Runtime/TaskCoordinator.cpp + Runtime/TaskCoordinator.hpp + Runtime/BenchMark.cpp + Runtime/BenchMark.hpp + Runtime/Platform/PlatformCommon.h + Runtime/Platform/PlatformAndroid.h + Runtime/Platform/PlatformWindows.h + Runtime/Platform/PlatformLinux.h +) + set(src_files - main.cpp - ModelViewController.cpp - ModelViewController.hpp Options.cpp Options.hpp - Application.cpp - Application.hpp - SceneList.cpp - SceneList.hpp - UserInterface.cpp - UserInterface.hpp - UserSettings.hpp - TaskCoordinator.cpp - TaskCoordinator.hpp ) source_group("Assets" FILES ${src_files_assets}) @@ -246,7 +255,9 @@ add_library(gkNextRenderer SHARED ${src_files_vulkan_hybriddeferred} ${src_files_common_compute_pipeline} ${src_files_thirdparty_json11} + ${src_files_runtime} ${src_files} + AndroidMain.cpp GameActivitySources.cpp ) else() @@ -262,7 +273,9 @@ add_executable(gkNextRenderer ${src_files_vulkan_hybriddeferred} ${src_files_common_compute_pipeline} ${src_files_thirdparty_json11} + ${src_files_runtime} ${src_files} + DesktopMain.cpp ) add_executable(gkNextEditor ${src_files_assets} @@ -277,7 +290,9 @@ add_executable(gkNextEditor ${src_files_common_compute_pipeline} ${src_files_thirdparty_json11} ${src_files_editor} + ${src_files_runtime} ${src_files} + DesktopMain.cpp ) endif() @@ -363,7 +378,7 @@ foreach(target IN LISTS AllTargets) if (MSVC) target_compile_options(${target} PRIVATE /WX) else() - target_compile_options(${target} PRIVATE -Wall -Werror -Wno-unused-const-variable -Wno-unused-variable -Wno-unused-private-field -Wno-unused-function -Wno-sign-compare -Wno-unused-result) + target_compile_options(${target} PRIVATE -Wall -Werror -Wno-unused-but-set-variable -Wno-inconsistent-missing-override -Wno-unused-const-variable -Wno-unused-variable -Wno-unused-private-field -Wno-unused-function -Wno-sign-compare -Wno-unused-result) endif() # specific for targets diff --git a/src/DesktopMain.cpp b/src/DesktopMain.cpp new file mode 100644 index 00000000..2af49cb1 --- /dev/null +++ b/src/DesktopMain.cpp @@ -0,0 +1,90 @@ +#include "Utilities/Console.hpp" +#include "Utilities/Exception.hpp" +#include "Options.hpp" +#include "Runtime/Application.hpp" + +#include +#include +#include + +#include "Runtime/Platform/PlatformCommon.h" + +int main(int argc, const char* argv[]) noexcept +{ + // Runtime Main Routine + try + { + // Handle command line options. + const Options options(argc, argv); + // Global GOption, can access from everywhere + GOption = &options; + + // Init environment variables +#if __APPLE__ + setenv("MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS", "1", 1); +#endif + if(options.RenderDoc) + { +#if __linux__ + setenv("ENABLE_VULKAN_RENDERDOC_CAPTURE", "1", 1); +#endif + +#if __APPLE__ + setenv("MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE", "~/capture/cap.gputrace", 1); + setenv("MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX", "0", 1); + setenv("MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX", "0", 1); + setenv("MTL_CAPTURE_ENABLED", "1", 1); + setenv("MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE","2",1); +#endif + } + + NextRenderer::PlatformInit(); + + // Start the application. + std::unique_ptr GApplication; + GApplication.reset( new NextRendererApplication(options) ); + + // Application Main Loop + GApplication->Start(); + while (1) + { + if( GApplication->Tick() ) + { + break; + } + } + GApplication->End(); + + // Shutdown + GApplication.reset(); + + return EXIT_SUCCESS; + } + // Exception Handle + catch (const Options::Help&) + { + return EXIT_SUCCESS; + } + catch (const std::exception& exception) + { + Utilities::Console::Write(Utilities::Severity::Fatal, [&exception]() + { + const auto stacktrace = boost::get_error_info(exception); + + std::cerr << "FATAL: " << exception.what() << std::endl; + + if (stacktrace) + { + std::cerr << '\n' << *stacktrace << '\n'; + } + }); + } + catch (...) + { + Utilities::Console::Write(Utilities::Severity::Fatal, []() + { + fmt::print(stderr, "FATAL: caught unhandled exception\n"); + }); + } + return EXIT_FAILURE; +} diff --git a/src/Editor/EditorMain.cpp b/src/Editor/EditorMain.cpp index 5f838b44..9d8b64fb 100644 --- a/src/Editor/EditorMain.cpp +++ b/src/Editor/EditorMain.cpp @@ -1,8 +1,6 @@ #include "EditorMain.h" #include -#include "UserInterface.hpp" - void MainWindowGUI(Editor::GUI & gui_r, Assets::Scene* scene, const Statistics& statistics, ImGuiID id, bool firstRun) { ////////////////////////////////// diff --git a/src/Editor/EditorUtils.cpp b/src/Editor/EditorUtils.cpp index 1d78eac8..d2d6d5fa 100644 --- a/src/Editor/EditorUtils.cpp +++ b/src/Editor/EditorUtils.cpp @@ -3,7 +3,7 @@ #include #include -#include "Application.hpp" +#include "Runtime/Application.hpp" #include "ImNodeFlow.h" #include "Editor/Nodes/NodeSetInt.hpp" diff --git a/src/Editor/EditorViewport.cpp b/src/Editor/EditorViewport.cpp index 49e249c7..49ff75f6 100644 --- a/src/Editor/EditorViewport.cpp +++ b/src/Editor/EditorViewport.cpp @@ -1,5 +1,5 @@ #include "EditorGUI.h" -#include "UserInterface.hpp" +#include "Runtime/UserInterface.hpp" #include "Assets/Model.hpp" #include "Utilities/Math.hpp" diff --git a/src/Editor/Nodes/NodeSetInt.cpp b/src/Editor/Nodes/NodeSetInt.cpp index 2f7fb93a..63b43ef8 100644 --- a/src/Editor/Nodes/NodeSetInt.cpp +++ b/src/Editor/Nodes/NodeSetInt.cpp @@ -3,7 +3,7 @@ #include #include -#include "UserInterface.hpp" +#include "Runtime/UserInterface.hpp" #include "Assets/Texture.hpp" #include "Assets/TextureImage.hpp" #include "Vulkan/ImageView.hpp" diff --git a/src/Options.cpp b/src/Options.cpp index 95905d2a..d330630d 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -1,5 +1,4 @@ #include "Options.hpp" -#include "SceneList.hpp" #include "Utilities/Exception.hpp" #include #include @@ -76,12 +75,7 @@ Options::Options(const int argc, const char* argv[]) std::cout << desc << std::endl; Throw(Help()); } - - // if (SceneIndex >= SceneList::AllScenes.size()) // w/o loaded scene - // { - // Throw(std::out_of_range("scene index is too large")); - // } - + if (PresentMode > 3) { Throw(std::out_of_range("invalid present mode")); diff --git a/src/Runtime/Application.cpp b/src/Runtime/Application.cpp new file mode 100644 index 00000000..6bc8ede6 --- /dev/null +++ b/src/Runtime/Application.cpp @@ -0,0 +1,724 @@ +#include "Application.hpp" +#include "UserInterface.hpp" +#include "UserSettings.hpp" +#include "Assets/Model.hpp" +#include "Assets/Scene.hpp" +#include "Assets/Texture.hpp" +#include "Assets/UniformBuffer.hpp" +#include "Utilities/Exception.hpp" +#include "Utilities/Console.hpp" +#include "Utilities/Glm.hpp" +#include "Vulkan/Window.hpp" +#include "Vulkan/SwapChain.hpp" +#include "Vulkan/Device.hpp" +#include "BenchMark.hpp" + +#include +#include +#include +#include +#include +#include + +#include "Options.hpp" +#include "TaskCoordinator.hpp" +#include "Editor/EditorCommand.hpp" +#include "Utilities/Localization.hpp" +#include "Vulkan/RayQuery/RayQueryRenderer.hpp" +#include "Vulkan/RayTrace/RayTracingRenderer.hpp" +#include "Vulkan/HybridDeferred/HybridDeferredRenderer.hpp" +#include "Vulkan/LegacyDeferred/LegacyDeferredRenderer.hpp" +#include "Vulkan/ModernDeferred/ModernDeferredRenderer.hpp" + +#define _USE_MATH_DEFINES +#include + +#define BUILDVER(X) std::string buildver(#X); +#include "build.version" + +namespace NextRenderer +{ + std::string GetBuildVersion() + { + return buildver; + } + + Vulkan::VulkanBaseRenderer* CreateRenderer(uint32_t rendererType, Vulkan::Window* window, const VkPresentModeKHR presentMode, const bool enableValidationLayers) + { + switch(rendererType) + { + case 0: + return new Vulkan::RayTracing::RayTracingRenderer(window, presentMode, enableValidationLayers); + case 1: + return new Vulkan::ModernDeferred::ModernDeferredRenderer(window, presentMode, enableValidationLayers); + case 2: + return new Vulkan::LegacyDeferred::LegacyDeferredRenderer(window, presentMode, enableValidationLayers); + case 3: + return new Vulkan::RayTracing::RayQueryRenderer(window, presentMode, enableValidationLayers); + case 4: + return new Vulkan::HybridDeferred::HybridDeferredRenderer(window, presentMode, enableValidationLayers); + default: + return new Vulkan::VulkanBaseRenderer(window, presentMode, enableValidationLayers); + } + } + +} + +namespace +{ + const bool EnableValidationLayers = +#if defined(NDEBUG) || defined(ANDROID) + false; +#else + true; +#endif + + struct SceneTaskContext + { + float elapsed; + std::array outputInfo; + }; +} + +UserSettings CreateUserSettings(const Options& options) +{ + SceneList::ScanScenes(); + + UserSettings userSettings{}; + + userSettings.Benchmark = options.Benchmark; + userSettings.BenchmarkNextScenes = options.BenchmarkNextScenes; + userSettings.BenchmarkMaxTime = options.BenchmarkMaxTime; + userSettings.BenchmarkMaxFrame = options.BenchmarkMaxFrame; + userSettings.SceneIndex = options.SceneIndex; + + if(options.SceneName != "") + { + std::string mappedSceneName = ""; + bool foundInAssets = false; + + //if found options.SceneName in key of Assets::sceneNames - set mappedSceneName to compare and find scene + Assets::uo_string_string_t::const_iterator got = Assets::sceneNames.find(options.SceneName); + if (got != Assets::sceneNames.end()) mappedSceneName = got->second; + + for( uint32_t i = 0; i < SceneList::AllScenes.size(); i++ ) + { + if( SceneList::AllScenes[i].first == options.SceneName || SceneList::AllScenes[i].first == mappedSceneName ) + { + userSettings.SceneIndex = i; + foundInAssets = true; + break; + } + } + + if(!foundInAssets) + { + userSettings.SceneIndex = SceneList::AddExternalScene(options.SceneName); + } + } + + userSettings.IsRayTraced = true; + userSettings.AccumulateRays = false; + userSettings.NumberOfSamples = options.Benchmark ? 1 : options.Samples; + userSettings.NumberOfBounces = options.Benchmark ? 4 : options.Bounces; + userSettings.MaxNumberOfBounces = options.MaxBounces; + userSettings.RR_MIN_DEPTH = options.RR_MIN_DEPTH; + userSettings.AdaptiveSample = options.AdaptiveSample; + userSettings.AdaptiveVariance = 6.0f; + userSettings.AdaptiveSteps = 8; + userSettings.TAA = true; + + userSettings.ShowSettings = !options.Benchmark; + userSettings.ShowOverlay = true; + + userSettings.ShowVisualDebug = false; + userSettings.HeatmapScale = 1.5f; + + userSettings.UseCheckerBoardRendering = false; + userSettings.TemporalFrames = options.Benchmark ? 512 : options.Temporal; + + userSettings.Denoiser = options.Denoiser; + + userSettings.PaperWhiteNit = 600.f; + + userSettings.SunRotation = 0.5f; + userSettings.SunLuminance = 500.f; + userSettings.SkyIntensity = 50.f; + + userSettings.AutoFocus = false; + + return userSettings; +} + +NextRendererApplication::NextRendererApplication(const Options& options) +{ + status_ = NextRenderer::EApplicationStatus::Starting; + + // Create Window + const Vulkan::WindowConfig windowConfig + { + "gkNextRenderer " + NextRenderer::GetBuildVersion(), + options.Width, + options.Height, + options.Benchmark && options.Fullscreen, + options.Fullscreen, + !options.Fullscreen, + options.SaveFile, + nullptr, + options.ForceSDR + }; + + userSettings_ = CreateUserSettings(options); + window_.reset( new Vulkan::Window(windowConfig)); + + // Initialize BenchMarker + if(options.Benchmark) + { + benchMarker_ = std::make_unique(); + } + + // Initialize Renderer + renderer_.reset( NextRenderer::CreateRenderer(options.RendererType, window_.get(), static_cast(options.Benchmark ? 0 : options.PresentMode), EnableValidationLayers) ); + renderer_->DelegateOnDeviceSet = [this]()->void{OnRendererDeviceSet();}; + renderer_->DelegateCreateSwapChain = [this]()->void{OnRendererCreateSwapChain();}; + renderer_->DelegateDeleteSwapChain = [this]()->void{OnRendererDeleteSwapChain();}; + renderer_->DelegateBeforeNextTick = [this]()->void{OnRendererBeforeNextFrame();}; + renderer_->DelegateGetUniformBufferObject = [this](VkOffset2D offset, VkExtent2D extend)->Assets::UniformBufferObject{ return GetUniformBufferObject(offset, extend);}; + renderer_->DelegatePostRender = [this](VkCommandBuffer commandBuffer, uint32_t imageIndex)->void{OnRendererPostRender(commandBuffer, imageIndex);}; + + // Initialize IO + window_->OnKey = [this](const int key, const int scancode, const int action, const int mods) { OnKey(key, scancode, action, mods); }; + window_->OnCursorPosition = [this](const double xpos, const double ypos) { OnCursorPosition(xpos, ypos); }; + window_->OnMouseButton = [this](const int button, const int action, const int mods) { OnMouseButton(button, action, mods); }; + window_->OnScroll = [this](const double xoffset, const double yoffset) { OnScroll(xoffset, yoffset); }; + window_->OnDropFile = [this](int path_count, const char* paths[]) { OnDropFile(path_count, paths); }; + + // Initialize Localization + Utilities::Localization::ReadLocTexts(fmt::format("assets/locale/{}.txt", GOption->locale).c_str()); + + // EditorCommand, need Refactoring +#if WITH_EDITOR + EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdSystem_RequestExit, [this](std::string& args)->bool { + GetWindow().Close(); + return true; + }); + EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdSystem_RequestMaximum, [this](std::string& args)->bool { + GetWindow().Maximum(); + return true; + }); + EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdSystem_RequestMinimize, [this](std::string& args)->bool { + GetWindow().Minimize(); + return true; + }); + EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdIO_LoadScene, [this](std::string& args)->bool { + userSettings_.SceneIndex = SceneList::AddExternalScene(args); + return true; + }); + EditorCommand::RegisterEdtiorCommand( EEditorCommand::ECmdIO_LoadHDRI, [this](std::string& args)->bool { + Assets::GlobalTexturePool::UpdateHDRTexture(0, args.c_str(), Vulkan::SamplerConfig()); + userSettings_.SkyIdx = 0; + return true; + }); +#endif +} + +NextRendererApplication::~NextRendererApplication() +{ + Utilities::Localization::SaveLocTexts(fmt::format("assets/locale/{}.txt", GOption->locale).c_str()); + + scene_.reset(); + renderer_.reset(); + window_.reset(); + benchMarker_.reset(); +} + +void NextRendererApplication::Start() +{ + renderer_->Start(); +} + +bool NextRendererApplication::Tick() +{ + // delta time calc + const auto prevTime = time_; + time_ = GetWindow().GetTime(); + const auto timeDelta = time_ - prevTime; + + // Camera Update + modelViewController_.UpdateCamera(cameraInitialSate_.ControlSpeed, timeDelta); + + // Handle Scene Switching + if (status_ == NextRenderer::EApplicationStatus::Running && sceneIndex_ != static_cast(userSettings_.SceneIndex)) + { + LoadScene(userSettings_.SceneIndex); + } + + // Setting Update + previousSettings_ = userSettings_; + + // Benchmark Update + if(status_ == NextRenderer::EApplicationStatus::Running) + { + TickBenchMarker(); + } + + // Renderer Tick +#if ANDROID + renderer_->DrawFrame(); + totalFrames_ += 1; + return false; +#else + glfwPollEvents(); + renderer_->DrawFrame(); + window_->attemptDragWindow(); + totalFrames_ += 1; + return glfwWindowShouldClose( window_->Handle() ) != 0; +#endif +} + +void NextRendererApplication::End() +{ + renderer_->End(); +} + +Assets::UniformBufferObject NextRendererApplication::GetUniformBufferObject(const VkOffset2D offset, const VkExtent2D extent) const +{ + if(userSettings_.CameraIdx >= 0 && previousSettings_.CameraIdx != userSettings_.CameraIdx) + { + modelViewController_.Reset((userSettings_.cameras[userSettings_.CameraIdx]).ModelView); + } + + const auto& init = cameraInitialSate_; + + Assets::UniformBufferObject ubo = {}; + + ubo.ModelView = modelViewController_.ModelView(); + ubo.Projection = glm::perspective(glm::radians(userSettings_.FieldOfView), + extent.width / static_cast(extent.height), 0.1f, 10000.0f); + ubo.Projection[1][1] *= -1; + + // handle android vulkan pre rotation +#if ANDROID + glm::mat4 pre_rotate_mat = glm::mat4(1.0f); + glm::vec3 rotation_axis = glm::vec3(0.0f, 0.0f, 1.0f); + pre_rotate_mat = glm::rotate(pre_rotate_mat, glm::radians(90.0f), rotation_axis); + + ubo.Projection = glm::perspective(glm::radians(userSettings_.FieldOfView), + extent.height / static_cast(extent.width), 0.1f, 10000.0f); + ubo.Projection[1][1] *= -1; + ubo.Projection = pre_rotate_mat * ubo.Projection; +#endif + + // Inverting Y for Vulkan, https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/ + ubo.ModelViewInverse = glm::inverse(ubo.ModelView); + ubo.ProjectionInverse = glm::inverse(ubo.Projection); + ubo.ViewProjection = ubo.Projection * ubo.ModelView; + + ubo.PrevViewProjection = prevUBO_.TotalFrames != 0 ? prevUBO_.ViewProjection : ubo.ViewProjection; + + ubo.ViewportRect = glm::vec4(offset.x, offset.y, extent.width, extent.height); + + // Raycasting + { + glm::vec2 pixel = mousePos_ - glm::vec2(offset.x, offset.y); + glm::vec2 uv = pixel / glm::vec2(extent.width, extent.height) * glm::vec2(2.0,2.0) - glm::vec2(1.0,1.0); + glm::vec4 origin = ubo.ModelViewInverse * glm::vec4(0, 0, 0, 1); + glm::vec4 target = ubo.ProjectionInverse * (glm::vec4(uv.x, uv.y, 1, 1)); + glm::vec3 raydir = ubo.ModelViewInverse * glm::vec4(normalize((glm::vec3(target) - glm::vec3(0.0,0.0,0.0))), 0.0); + glm::vec3 rayorg = glm::vec3(origin); + + // Send new + renderer_->SetRaycastRay(rayorg, raydir); + Assets::RayCastResult rayResult {}; + renderer_->GetLastRaycastResult(rayResult); + + if( userSettings_.AutoFocus ) + { + if(rayResult.Hitted ) + { + userSettings_.FocusDistance = rayResult.T; + scene_->SetSelectedId(rayResult.InstanceId); + } + else + { + scene_->SetSelectedId(-1); + } + + // only active one frame + userSettings_.AutoFocus = false; + } + + userSettings_.HitResult = rayResult; + } + + + ubo.SelectedId = scene_->GetSelectedId(); + + // Camera Stuff + ubo.Aperture = userSettings_.Aperture; + ubo.FocusDistance = userSettings_.FocusDistance; + + // SceneStuff + ubo.SkyRotation = userSettings_.SkyRotation; + ubo.MaxNumberOfBounces = userSettings_.MaxNumberOfBounces; + ubo.TotalFrames = totalFrames_; + ubo.NumberOfSamples = userSettings_.NumberOfSamples; + ubo.NumberOfBounces = userSettings_.NumberOfBounces; + ubo.RR_MIN_DEPTH = userSettings_.RR_MIN_DEPTH; + ubo.AdaptiveSample = userSettings_.AdaptiveSample; + ubo.AdaptiveVariance = userSettings_.AdaptiveVariance; + ubo.AdaptiveSteps = userSettings_.AdaptiveSteps; + ubo.TAA = userSettings_.TAA; + ubo.RandomSeed = rand(); + ubo.SunDirection = glm::vec4( glm::normalize(glm::vec3( sinf(float( userSettings_.SunRotation * M_PI )), 0.75f, cosf(float( userSettings_.SunRotation * M_PI )) )), 0.0f ); + ubo.SunColor = glm::vec4(1,1,1, 0) * userSettings_.SunLuminance; + ubo.SkyIntensity = userSettings_.SkyIntensity; + ubo.SkyIdx = userSettings_.SkyIdx; + ubo.BackGroundColor = glm::vec4(0.4, 0.6, 1.0, 0.0) * 4.0f * userSettings_.SkyIntensity; + ubo.HasSky = init.HasSky; + ubo.HasSun = init.HasSun && userSettings_.SunLuminance > 0; + ubo.ShowHeatmap = false; + ubo.HeatmapScale = userSettings_.HeatmapScale; + ubo.UseCheckerBoard = userSettings_.UseCheckerBoardRendering; + ubo.TemporalFrames = userSettings_.TemporalFrames; + ubo.HDR = renderer_->SwapChain().IsHDR(); + + ubo.PaperWhiteNit = userSettings_.PaperWhiteNit; + ubo.LightCount = scene_->GetLightCount(); + + // UBO Backup, for motion vector calc + prevUBO_ = ubo; + + return ubo; +} + +void NextRendererApplication::OnRendererDeviceSet() +{ + // global textures + // texture id 0: dynamic hdri sky + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/std_env.hdr"), Vulkan::SamplerConfig()); + + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/canary_wharf_1k.hdr"), Vulkan::SamplerConfig()); + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/kloppenheim_01_puresky_1k.hdr"), Vulkan::SamplerConfig()); + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/kloppenheim_07_1k.hdr"), Vulkan::SamplerConfig()); + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/river_road_2.hdr"), Vulkan::SamplerConfig()); + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/rainforest_trail_1k.hdr"), Vulkan::SamplerConfig()); + + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/studio_small_03_1k.hdr"), Vulkan::SamplerConfig()); + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/studio_small_09_1k.hdr"), Vulkan::SamplerConfig()); + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/sunset_fairway_1k.hdr"), Vulkan::SamplerConfig()); + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/umhlanga_sunrise_1k.hdr"), Vulkan::SamplerConfig()); + Assets::GlobalTexturePool::LoadHDRTexture(Utilities::FileHelper::GetPlatformFilePath("assets/textures/shanghai_bund_1k.hdr"), Vulkan::SamplerConfig()); + + if(GOption->HDRIfile != "") Assets::GlobalTexturePool::UpdateHDRTexture(0, GOption->HDRIfile.c_str(), Vulkan::SamplerConfig()); + + std::vector models; + std::vector nodes; + std::vector materials; + std::vector lights; + Assets::CameraInitialSate cameraState; + + scene_.reset(new Assets::Scene(renderer_->CommandPool(), nodes, models, + materials, lights, renderer_->supportRayTracing_)); + + renderer_->SetScene(scene_); + renderer_->OnPostLoadScene(); + + status_ = NextRenderer::EApplicationStatus::Running; +} + +void NextRendererApplication::OnRendererCreateSwapChain() +{ + userInterface_.reset(new UserInterface(renderer_->CommandPool(), renderer_->SwapChain(), renderer_->DepthBuffer(), + userSettings_, renderer_->GetRenderImage())); +} + +void NextRendererApplication::OnRendererDeleteSwapChain() +{ + userInterface_.reset(); +} + +void NextRendererApplication::OnRendererPostRender(VkCommandBuffer commandBuffer, uint32_t imageIndex) +{ + static float frameRate = 0.0; + static double lastTime = 0.0; + static double lastTimestamp = 0.0; + double now = GetWindow().GetTime(); + + // Record delta time between calls to Render. + if(totalFrames_ % 30 == 0) + { + const auto timeDelta = now - lastTime; + lastTime = now; + frameRate = static_cast(30 / timeDelta); + } + + // Render the UI + Statistics stats = {}; + + stats.FrameTime = static_cast((now - lastTimestamp) * 1000.0); + lastTimestamp = now; + + stats.Stats["gpu"] = renderer_->Device().DeviceProperties().deviceName; + + stats.FramebufferSize = GetWindow().FramebufferSize(); + stats.FrameRate = frameRate; + + + stats.TotalFrames = totalFrames_; + //stats.RenderTime = time_ - sceneInitialTime_; + + stats.CamPosX = modelViewController_.Position()[0]; + stats.CamPosY = modelViewController_.Position()[1]; + stats.CamPosZ = modelViewController_.Position()[2]; + + stats.InstanceCount = static_cast(scene_->Nodes().size()); + stats.TriCount = scene_->GetIndicesCount() / 3; + stats.TextureCount = Assets::GlobalTexturePool::GetInstance()->TotalTextures(); + stats.ComputePassCount = 0; + stats.LoadingStatus = status_ == NextRenderer::EApplicationStatus::Loading; + + //Renderer::visualDebug_ = userSettings_.ShowVisualDebug; + + userInterface_->Render(commandBuffer, imageIndex, stats, renderer_->GpuTimer(), scene_.get()); +} + +void NextRendererApplication::OnKey(int key, int scancode, int action, int mods) +{ + if (userInterface_->WantsToCaptureKeyboard()) + { + return; + } +#if !ANDROID + if (action == GLFW_PRESS) + { + switch (key) + { + case GLFW_KEY_ESCAPE: GetWindow().Close(); + break; + default: break; + } + + // Settings (toggle switches) + if (!userSettings_.Benchmark) + { + switch (key) + { + case GLFW_KEY_F1: userSettings_.ShowSettings = !userSettings_.ShowSettings; + break; + case GLFW_KEY_F2: userSettings_.ShowOverlay = !userSettings_.ShowOverlay; + break; + default: break; + } + } + } + else if(action == GLFW_RELEASE) + { + if (!userSettings_.Benchmark) + { + // switch (key) + // { + // default: break; + // } + } + } +#endif + + // Camera motions + if (!userSettings_.Benchmark) + { + modelViewController_.OnKey(key, scancode, action, mods); + } +} + +void NextRendererApplication::OnCursorPosition(const double xpos, const double ypos) +{ + if (!renderer_->HasSwapChain() || + userSettings_.Benchmark || + userInterface_->WantsToCaptureKeyboard() || + userInterface_->WantsToCaptureMouse() + ) + { + return; + } + + // Camera motions + modelViewController_.OnCursorPosition(xpos, ypos); + + mousePos_ = glm::vec2(xpos, ypos); +} + +void NextRendererApplication::OnMouseButton(const int button, const int action, const int mods) +{ + if (!renderer_->HasSwapChain() || + userSettings_.Benchmark || + userInterface_->WantsToCaptureMouse()) + { + return; + } + + // Camera motions + modelViewController_.OnMouseButton(button, action, mods); +#if !ANDROID + static glm::vec2 pressMousePos_ {}; + if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) + { + pressMousePos_ = mousePos_; + } + else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) + { + if( glm::distance(pressMousePos_, mousePos_) < 1.0f ) + { + userSettings_.AutoFocus = true; + } + } +#endif +} + +void NextRendererApplication::OnScroll(const double xoffset, const double yoffset) +{ + if (!renderer_->HasSwapChain() || + userSettings_.Benchmark || + userInterface_->WantsToCaptureMouse()) + { + return; + } + const auto prevFov = userSettings_.FieldOfView; + userSettings_.FieldOfView = std::clamp( + static_cast(prevFov - yoffset), + UserSettings::FieldOfViewMinValue, + UserSettings::FieldOfViewMaxValue); +} + +void NextRendererApplication::OnDropFile(int path_count, const char* paths[]) +{ + // add glb to the last, and loaded + if (path_count > 0) + { + std::string path = paths[path_count - 1]; + std::string ext = path.substr(path.find_last_of(".") + 1); + std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + + if (ext == "glb") + { + userSettings_.SceneIndex = SceneList::AddExternalScene(path); + } + + if( ext == "hdr") + { + Assets::GlobalTexturePool::UpdateHDRTexture(0, path, Vulkan::SamplerConfig()); + userSettings_.SkyIdx = 0; + } + } +} + +void NextRendererApplication::OnRendererBeforeNextFrame() +{ + TaskCoordinator::GetInstance()->Tick(); +} + +void NextRendererApplication::OnTouch(bool down, double xpos, double ypos) +{ + modelViewController_.OnTouch(down, xpos, ypos); +} + +void NextRendererApplication::OnTouchMove(double xpos, double ypos) +{ + modelViewController_.OnCursorPosition(xpos, ypos); +} + +void NextRendererApplication::LoadScene(const uint32_t sceneIndex) +{ + status_ = NextRenderer::EApplicationStatus::Loading; + + std::shared_ptr< std::vector > models = std::make_shared< std::vector >(); + std::shared_ptr< std::vector > nodes = std::make_shared< std::vector >(); + std::shared_ptr< std::vector > materials = std::make_shared< std::vector >(); + std::shared_ptr< std::vector > lights = std::make_shared< std::vector >(); + std::shared_ptr< Assets::CameraInitialSate > cameraState = std::make_shared< Assets::CameraInitialSate >(); + + cameraInitialSate_.cameras.clear(); + cameraInitialSate_.CameraIdx = -1; + + // dispatch in thread task and reset in main thread + TaskCoordinator::GetInstance()->AddTask( [cameraState, sceneIndex, models, nodes, materials, lights](ResTask& task) + { + SceneTaskContext taskContext {}; + const auto timer = std::chrono::high_resolution_clock::now(); + + SceneList::AllScenes[sceneIndex].second(*cameraState, *nodes, *models, *materials, *lights); + + taskContext.elapsed = std::chrono::duration(std::chrono::high_resolution_clock::now() - timer).count(); + + std::string info = fmt::format("parsed scene #{} on cpu in {:.2f}ms", sceneIndex, taskContext.elapsed * 1000.f); + std::copy(info.begin(), info.end(), taskContext.outputInfo.data()); + task.SetContext( taskContext ); + }, + [this, cameraState, sceneIndex, models, nodes, materials, lights](ResTask& task) + { + SceneTaskContext taskContext {}; + task.GetContext( taskContext ); + fmt::print("{} {}{}\n", CONSOLE_GREEN_COLOR, taskContext.outputInfo.data(), CONSOLE_DEFAULT_COLOR); + + const auto timer = std::chrono::high_resolution_clock::now(); + + cameraInitialSate_ = *cameraState; + + renderer_->Device().WaitIdle(); + renderer_->DeleteSwapChain(); + renderer_->OnPreLoadScene(); + + scene_.reset(new Assets::Scene(renderer_->CommandPool(), *nodes, *models, + *materials, *lights, renderer_->supportRayTracing_)); + renderer_->SetScene(scene_); + + sceneIndex_ = sceneIndex; + + userSettings_.FieldOfView = cameraInitialSate_.FieldOfView; + userSettings_.Aperture = cameraInitialSate_.Aperture; + userSettings_.FocusDistance = cameraInitialSate_.FocusDistance; + userSettings_.SkyIdx = cameraInitialSate_.SkyIdx; + userSettings_.SunRotation = cameraInitialSate_.SunRotation; + + userSettings_.cameras = cameraInitialSate_.cameras; + userSettings_.CameraIdx = cameraInitialSate_.CameraIdx; + + modelViewController_.Reset(cameraInitialSate_.ModelView); + + + totalFrames_ = 0; + + if(benchMarker_) + { + benchMarker_->OnSceneStart(GetWindow().GetTime()); + } + + renderer_->OnPostLoadScene(); + renderer_->CreateSwapChain(); + + float elapsed = std::chrono::duration(std::chrono::high_resolution_clock::now() - timer).count(); + + fmt::print("{} uploaded scene #{} to gpu in {:.2f}ms{}\n", CONSOLE_GREEN_COLOR, sceneIndex, elapsed * 1000.f, CONSOLE_DEFAULT_COLOR); + + sceneIndex_ = sceneIndex; + status_ = NextRenderer::EApplicationStatus::Running; + }, + 1); +} + +void NextRendererApplication::TickBenchMarker() +{ + if( benchMarker_ && benchMarker_->OnTick( GetWindow().GetTime(), renderer_.get() )) + { + // Benchmark is done, report the results. + benchMarker_->OnReport(renderer_.get(), SceneList::AllScenes[userSettings_.SceneIndex].first); + + if (!userSettings_.BenchmarkNextScenes || static_cast(userSettings_.SceneIndex) == + SceneList::AllScenes.size() - 1) + { + GetWindow().Close(); + } + + userSettings_.SceneIndex += 1; + } +} diff --git a/src/Runtime/Application.hpp b/src/Runtime/Application.hpp new file mode 100644 index 00000000..3c8582db --- /dev/null +++ b/src/Runtime/Application.hpp @@ -0,0 +1,98 @@ +#pragma once + +#include "ModelViewController.hpp" +#include "SceneList.hpp" +#include "UserSettings.hpp" +#include "Assets/UniformBuffer.hpp" +#include "Assets/Model.hpp" +#include "Vulkan/FrameBuffer.hpp" +#include "Vulkan/VulkanBaseRenderer.hpp" +#include "Options.hpp" + +class BenchMarker; + +namespace NextRenderer +{ + enum class EApplicationStatus + { + Starting, + Running, + Loading, + AsyncPreparing, + }; + + std::string GetBuildVersion(); + + Vulkan::VulkanBaseRenderer* CreateRenderer(uint32_t rendererType, Vulkan::Window* window, const VkPresentModeKHR presentMode, const bool enableValidationLayers); +} + +class NextRendererApplication final +{ +public: + + VULKAN_NON_COPIABLE(NextRendererApplication) + + NextRendererApplication(const Options& options); + ~NextRendererApplication(); + + Vulkan::VulkanBaseRenderer& GetRenderer() { return *renderer_; } + + void Start(); + bool Tick(); + void End(); + +public: + void OnTouch(bool down, double xpos, double ypos); + void OnTouchMove(double xpos, double ypos); + +protected: + + Assets::UniformBufferObject GetUniformBufferObject(const VkOffset2D offset, const VkExtent2D extent) const; + void OnRendererDeviceSet(); + void OnRendererCreateSwapChain(); + void OnRendererDeleteSwapChain(); + void OnRendererPostRender(VkCommandBuffer commandBuffer, uint32_t imageIndex); + void OnRendererBeforeNextFrame(); + + const Assets::Scene& GetScene() const { return *scene_; } + + void OnKey(int key, int scancode, int action, int mods); + void OnCursorPosition(double xpos, double ypos); + void OnMouseButton(int button, int action, int mods); + void OnScroll(double xoffset, double yoffset); + void OnDropFile(int path_count, const char* paths[]); + + Vulkan::Window& GetWindow() {return *window_;} + + +private: + + void LoadScene(uint32_t sceneIndex); + void TickBenchMarker(); + void CheckFramebufferSize(); + + void Report(int fps, const std::string& sceneName, bool upload_screen, bool save_screen); + + std::unique_ptr window_; + std::unique_ptr renderer_; + std::unique_ptr benchMarker_; + + uint32_t sceneIndex_{((uint32_t)~((uint32_t)0))}; + mutable UserSettings userSettings_{}; + UserSettings previousSettings_{}; + Assets::CameraInitialSate cameraInitialSate_{}; + + mutable ModelViewController modelViewController_{}; + + mutable Assets::UniformBufferObject prevUBO_ {}; + + std::shared_ptr scene_; + std::unique_ptr userInterface_; + + NextRenderer::EApplicationStatus status_{}; + + uint32_t totalFrames_{}; + double time_{}; + + glm::vec2 mousePos_ {}; +}; diff --git a/src/Runtime/BenchMark.cpp b/src/Runtime/BenchMark.cpp new file mode 100644 index 00000000..bbffb7ef --- /dev/null +++ b/src/Runtime/BenchMark.cpp @@ -0,0 +1,325 @@ +#include "BenchMark.hpp" +#include "Options.hpp" +#include "Utilities/Console.hpp" +#include "Vulkan/VulkanBaseRenderer.hpp" +#include +#include + +#include "curl/curl.h" +#include "cpp-base64/base64.cpp" +#include "ThirdParty/json11/json11.hpp" +#include "stb_image_write.h" + +#define _USE_MATH_DEFINES +#include +#include + +#include "Application.hpp" +#include "Utilities/Exception.hpp" +#include "Utilities/Math.hpp" +#include "Vulkan/Device.hpp" +#include "Vulkan/SwapChain.hpp" + +#if WITH_AVIF +#include "avif/avif.h" +#endif + + +BenchMarker::BenchMarker() +{ + std::time_t now = std::time(nullptr); + std::string report_filename = fmt::format("report_{:%d-%m-%Y-%H-%M-%S}.csv", fmt::localtime(now)); + + benchmarkCsvReportFile.open(report_filename); + benchmarkCsvReportFile << fmt::format("#,scene,FPS\n"); +} + +BenchMarker::~BenchMarker() +{ + benchmarkCsvReportFile.close(); +} + +void BenchMarker::OnSceneStart( double nowInSeconds ) +{ + periodTotalFrames_ = 0; + benchmarkTotalFrames_ = 0; + sceneInitialTime_ = nowInSeconds; +} + +bool BenchMarker::OnTick( double nowInSeconds, Vulkan::VulkanBaseRenderer* renderer ) +{ + double prevTime = time_; + time_ = nowInSeconds; + // Initialise scene benchmark timers + if (periodTotalFrames_ == 0) + { + periodInitialTime_ = nowInSeconds; + } + + // Print out the frame rate at regular intervals. + { + const double period = 1; + const double prevTotalTime = prevTime - periodInitialTime_; + const double totalTime = time_ - periodInitialTime_; + + if (periodTotalFrames_ != 0 && static_cast(prevTotalTime / period) != static_cast(totalTime + / period)) + { + fmt::print("\t[Benchmarking] fps: {:.0f}\n", float(periodTotalFrames_) / float(totalTime)); + periodInitialTime_ = time_; + periodTotalFrames_ = 0; + } + + periodTotalFrames_++; + benchmarkTotalFrames_++; + } + + // If in benchmark mode, bail out from the scene if we've reached the time or sample limit. + { + const bool timeLimitReached = GOption->BenchmarkMaxFrame == 0 && periodTotalFrames_ != 0 && time_ - sceneInitialTime_ > + GOption->BenchmarkMaxTime; + const bool frameLimitReached = GOption->BenchmarkMaxFrame > 0 && benchmarkTotalFrames_ >= GOption->BenchmarkMaxFrame; + if (timeLimitReached || frameLimitReached) + { + return true; + } + } + return false; +} + +void BenchMarker::OnReport(Vulkan::VulkanBaseRenderer* renderer, const std::string& SceneName) +{ + const double totalTime = time_ - sceneInitialTime_; + + double fps = benchmarkTotalFrames_ / totalTime; + fmt::print("{} totalTime {:%H:%M:%S} fps {:.3f}{}\n", CONSOLE_GOLD_COLOR, std::chrono::seconds(static_cast(totalTime)), fps, CONSOLE_DEFAULT_COLOR); + Report(renderer, static_cast(floor(fps)), SceneName, false, GOption->SaveFile); +} + + +inline const std::string versionToString(const uint32_t version) +{ + return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version)); +} + +void BenchMarker::Report(Vulkan::VulkanBaseRenderer* renderer_, int fps, const std::string& sceneName, bool upload_screen, bool save_screen) +{ + // report file + benchmarkCsvReportFile << fmt::format("{},{},{}\n", benchUnit_++, sceneName, fps); + benchmarkCsvReportFile.flush(); + // screenshot + VkPhysicalDeviceProperties deviceProp1{}; + vkGetPhysicalDeviceProperties(renderer_->Device().PhysicalDevice(), &deviceProp1); + + std::string img_encoded {}; + if (upload_screen || save_screen) + { + + // screenshot stuffs + const Vulkan::SwapChain& swapChain = renderer_->SwapChain(); + const auto extent = swapChain.Extent(); + + // capture and export + renderer_->CaptureScreenShot(); + + // prepare data + void* data = nullptr; + uint32_t dataBytes = 0; + uint32_t rowBytes = 0; + + constexpr uint32_t kCompCnt = 3; + if(swapChain.IsHDR()) + { + dataBytes = extent.width * extent.height * 3 * 2; + rowBytes = extent.width * 3 * sizeof(uint16_t); + data = malloc(dataBytes); + + uint16_t* dataview = (uint16_t*)data; + { + Vulkan::DeviceMemory* vkMemory = renderer_->GetScreenShotMemory(); + uint8_t* mappedData = (uint8_t*)vkMemory->Map(0, VK_WHOLE_SIZE); + uint32_t yDelta = extent.width * kCompCnt; + uint32_t xDelta = kCompCnt; + uint32_t yy = 0; + uint32_t xx = 0, idx = 0; + for (uint32_t y = 0; y < extent.height; y++) + { + xx = 0; + for (uint32_t x = 0; x < extent.width; x++) + { + uint32_t* pInPixel = (uint32_t*)&mappedData[idx]; + uint32_t uInPixel = *pInPixel; + dataview[yy + xx + 2] = (uInPixel & (0b1111111111 << 20)) >> 20; + dataview[yy + xx + 1] = (uInPixel & (0b1111111111 << 10)) >> 10; + dataview[yy + xx + 0] = (uInPixel & (0b1111111111 << 0)) >> 0; + + idx += 4; + xx += xDelta; + } + yy += yDelta; + } + vkMemory->Unmap(); + } + } + else + { + dataBytes = extent.width * extent.height * kCompCnt; + rowBytes = extent.width * 3 * sizeof(uint8_t); + data = malloc(dataBytes); + + uint8_t* dataview = (uint8_t*)data; + { + Vulkan::DeviceMemory* vkMemory = renderer_->GetScreenShotMemory(); + uint8_t* mappedData = (uint8_t*)vkMemory->Map(0, VK_WHOLE_SIZE); + uint32_t yDelta = extent.width * kCompCnt; + uint32_t xDelta = kCompCnt; + uint32_t yy = 0; + uint32_t xx = 0, idx = 0; + for (uint32_t y = 0; y < extent.height; y++) + { + xx = 0; + for (uint32_t x = 0; x < extent.width; x++) + { + uint32_t* pInPixel = (uint32_t*)&mappedData[idx]; + uint32_t uInPixel = *pInPixel; + dataview[yy + xx] = (uInPixel & (0b11111111 << 16)) >> 16; + dataview[yy + xx + 1] = (uInPixel & (0b11111111 << 8)) >> 8; + dataview[yy + xx + 2] = (uInPixel & (0b11111111 << 0)) >> 0; + idx += 4; + xx += xDelta; + } + yy += yDelta; + } + vkMemory->Unmap(); + } + } + +#if WITH_AVIF + avifImage* image = avifImageCreate(extent.width, extent.height, swapChain.IsHDR() ? 10 : 8, AVIF_PIXEL_FORMAT_YUV444); // these values dictate what goes into the final AVIF + if (!image) + { + Throw(std::runtime_error("avif image creation failed")); + } + image->yuvRange = AVIF_RANGE_FULL; + image->colorPrimaries = swapChain.IsHDR() ? AVIF_COLOR_PRIMARIES_BT2020 : AVIF_COLOR_PRIMARIES_BT709; + image->transferCharacteristics = swapChain.IsHDR() ? AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084 : AVIF_TRANSFER_CHARACTERISTICS_BT709; + image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY; + image->clli.maxCLL = static_cast(600); //maxCLLNits; + image->clli.maxPALL = 0; //maxFALLNits; + + avifEncoder* encoder = NULL; + avifRWData avifOutput = AVIF_DATA_EMPTY; + + avifRGBImage rgbAvifImage{}; + avifRGBImageSetDefaults(&rgbAvifImage, image); + rgbAvifImage.format = AVIF_RGB_FORMAT_RGB; + rgbAvifImage.ignoreAlpha = AVIF_TRUE; + rgbAvifImage.pixels = (uint8_t*)data; + rgbAvifImage.rowBytes = rowBytes; + + avifResult convertResult = avifImageRGBToYUV(image, &rgbAvifImage); + if (convertResult != AVIF_RESULT_OK) + { + Throw(std::runtime_error("Failed to convert RGB to YUV: " + std::string(avifResultToString(convertResult)))); + } + encoder = avifEncoderCreate(); + if (!encoder) + { + Throw(std::runtime_error("Failed to create encoder")); + } + encoder->quality = 80; + encoder->qualityAlpha = AVIF_QUALITY_LOSSLESS; + encoder->speed = AVIF_SPEED_FASTEST; + + avifResult addImageResult = avifEncoderAddImage(encoder, image, 1, AVIF_ADD_IMAGE_FLAG_SINGLE); + if (addImageResult != AVIF_RESULT_OK) + { + Throw(std::runtime_error("Failed to add image: " + std::string(avifResultToString(addImageResult)))); + } + avifResult finishResult = avifEncoderFinish(encoder, &avifOutput); + if (finishResult != AVIF_RESULT_OK) + { + Throw(std::runtime_error("Failed to finish encoding: " + std::string(avifResultToString(finishResult)))); + } + + // save to file with scenename + std::string filename = sceneName + ".avif"; + std::ofstream file(filename, std::ios::out | std::ios::binary); + if(file.is_open()) + { + file.write(reinterpret_cast(avifOutput.data), avifOutput.size); + } + file.close(); + + // send to server + img_encoded = base64_encode(avifOutput.data, avifOutput.size, false); +#else + // save to file with scenename + std::string filename = sceneName + ".jpg"; + + // if hdr, transcode 16bit to 8bit + if(swapChain.IsHDR()) + { + uint16_t* dataview = (uint16_t*)data; + uint8_t* sdrData = (uint8_t*)malloc(extent.width * extent.height * kCompCnt); + for ( uint32_t i = 0; i < extent.width * extent.height * kCompCnt; i++ ) + { + float scaled = dataview[i] / 1200.f * 2.0f; + scaled = scaled * scaled; + scaled *= 255.f; + sdrData[i] = (uint8_t)(std::min(scaled, 255.f)); + } + stbi_write_jpg(filename.c_str(), extent.width, extent.height, kCompCnt, (const void*)sdrData, 91); + free(sdrData); + } + else + { + stbi_write_jpg(filename.c_str(), extent.width, extent.height, kCompCnt, (const void*)data, 91); + } +#endif + free(data); + } + + // perf server upload + if( NextRenderer::GetBuildVersion() != "v0.0.0.0" ) + { + json11::Json my_json = json11::Json::object{ + {"renderer", renderer_->StaticClass()}, + {"scene", sceneName}, + {"gpu", std::string(deviceProp1.deviceName)}, + {"driver", versionToString(deviceProp1.driverVersion)}, + {"fps", fps}, + {"version", NextRenderer::GetBuildVersion()}, + {"screenshot", img_encoded} + }; + std::string json_str = my_json.dump(); + + fmt::print("Sending benchmark to perf server...\n"); + // upload from curl + CURL* curl; + CURLcode res; + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if (curl) + { + curl_slist* slist1 = nullptr; + slist1 = curl_slist_append(slist1, "Content-Type: application/json"); + slist1 = curl_slist_append(slist1, "Accept: application/json"); + + /* set custom headers */ + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1); + curl_easy_setopt(curl, CURLOPT_URL, "http://gameknife.site:60010/rt_benchmark"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_str.c_str()); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L); + + /* Perform the request, res gets the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if (res != CURLE_OK) + fmt::print(stderr, "curl_easy_perform() failed: {}\n", curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + } +} diff --git a/src/Runtime/BenchMark.hpp b/src/Runtime/BenchMark.hpp new file mode 100644 index 00000000..bbe67e5c --- /dev/null +++ b/src/Runtime/BenchMark.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include "Vulkan/VulkanBaseRenderer.hpp" + +class BenchMarker final +{ +public: + BenchMarker(); + ~BenchMarker(); + + void OnSceneStart( double nowInSeconds ); + bool OnTick( double nowInSeconds, Vulkan::VulkanBaseRenderer* renderer ); + void OnReport(Vulkan::VulkanBaseRenderer* renderer, const std::string& SceneName); + void Report(Vulkan::VulkanBaseRenderer* renderer_, int fps, const std::string& sceneName, bool upload_screen, bool save_screen); + // Benchmark stats + int32_t benchUnit_{}; + double time_{}; + double sceneInitialTime_{}; + double periodInitialTime_{}; + uint32_t periodTotalFrames_{}; + uint32_t benchmarkTotalFrames_{}; + std::ofstream benchmarkCsvReportFile; +}; diff --git a/src/ModelViewController.cpp b/src/Runtime/ModelViewController.cpp similarity index 100% rename from src/ModelViewController.cpp rename to src/Runtime/ModelViewController.cpp diff --git a/src/ModelViewController.hpp b/src/Runtime/ModelViewController.hpp similarity index 100% rename from src/ModelViewController.hpp rename to src/Runtime/ModelViewController.hpp diff --git a/src/Runtime/Platform/PlatformAndroid.h b/src/Runtime/Platform/PlatformAndroid.h new file mode 100644 index 00000000..a7576e69 --- /dev/null +++ b/src/Runtime/Platform/PlatformAndroid.h @@ -0,0 +1,77 @@ +#pragma once + +namespace NextRenderer +{ + void PlatformInit() + { + + } +} +#if ANDROID +#include +#include +#include + +static void MakeExternalDirectory( android_app* app, std::string srcPath ) +{ + if( std::filesystem::exists(std::string("/sdcard/Android/data/com.gknextrenderer/files/") + srcPath) ) + { + return; + } + + std::filesystem::create_directories(std::filesystem::path(std::string("/sdcard/Android/data/com.gknextrenderer/files/") + srcPath)); + + AAssetDir* assetDir = AAssetManager_openDir( + app->activity->assetManager, srcPath.c_str()); + const char* filename; + while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL){ + AAsset* file = AAssetManager_open(app->activity->assetManager, (srcPath + "/" + filename).c_str(), + AASSET_MODE_BUFFER); + size_t fileLen = AAsset_getLength(file); + std::vector fileData; + fileData.resize(fileLen); + + AAsset_read(file, static_cast(fileData.data()), fileLen); + AAsset_close(file); + + std::string targetPath = std::string("/sdcard/Android/data/com.gknextrenderer/files/") + srcPath + "/" + filename; + + FILE* targetFile = fopen(targetPath.c_str(), "wb"); + fwrite(fileData.data(), 1, fileLen, targetFile); + fclose(targetFile); + } + AAssetDir_close(assetDir); +} + +class androidbuf : public std::streambuf { +public: + enum { bufsize = 512 }; // ... or some other suitable buffer size + androidbuf() { this->setp(buffer, buffer + bufsize - 1); } + +private: + int overflow(int c) + { + if (c == traits_type::eof()) { + *this->pptr() = traits_type::to_char_type(c); + this->sbumpc(); + } + return this->sync()? traits_type::eof(): traits_type::not_eof(c); + } + + int sync() + { + int rc = 0; + if (this->pbase() != this->pptr()) { + char writebuf[bufsize+1]; + memcpy(writebuf, this->pbase(), this->pptr() - this->pbase()); + writebuf[this->pptr() - this->pbase()] = '\0'; + + rc = __android_log_print(ANDROID_LOG_INFO, "vkdemo", "%s", writebuf) > 0; + this->setp(buffer, buffer + bufsize - 1); + } + return rc; + } + + char buffer[bufsize]; +}; +#endif diff --git a/src/Runtime/Platform/PlatformCommon.h b/src/Runtime/Platform/PlatformCommon.h new file mode 100644 index 00000000..2309b442 --- /dev/null +++ b/src/Runtime/Platform/PlatformCommon.h @@ -0,0 +1,9 @@ +#pragma once + +#if ANDROID +#include "PlatformAndroid.h" +#elif WIN32 +#include "PlatformWindows.h" +#else +#include "PlatformLinux.h" +#endif \ No newline at end of file diff --git a/src/Runtime/Platform/PlatformLinux.h b/src/Runtime/Platform/PlatformLinux.h new file mode 100644 index 00000000..66ac243e --- /dev/null +++ b/src/Runtime/Platform/PlatformLinux.h @@ -0,0 +1,10 @@ +#pragma once + +namespace NextRenderer +{ + void PlatformInit() + { + + } +} + diff --git a/src/Runtime/Platform/PlatformWindows.h b/src/Runtime/Platform/PlatformWindows.h new file mode 100644 index 00000000..35f24a35 --- /dev/null +++ b/src/Runtime/Platform/PlatformWindows.h @@ -0,0 +1,18 @@ +#pragma once + +namespace NextRenderer +{ + void PlatformInit() + { + // Windows console color support +#if WIN32 && !defined(__MINGW32__) + HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwMode; + + GetConsoleMode(hOutput, &dwMode); + dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(hOutput, dwMode); +#endif + } +} + diff --git a/src/SceneList.cpp b/src/Runtime/SceneList.cpp similarity index 98% rename from src/SceneList.cpp rename to src/Runtime/SceneList.cpp index 664934e8..05015b67 100644 --- a/src/SceneList.cpp +++ b/src/Runtime/SceneList.cpp @@ -7,6 +7,7 @@ #include #include +#include "Application.hpp" #include "Utilities/FileHelper.hpp" #include "Vulkan/VulkanBaseRenderer.hpp" @@ -21,7 +22,7 @@ using Assets::Material; using Assets::Model; using Assets::Texture; -extern std::unique_ptr GApplication; +extern std::unique_ptr GApplication; namespace { @@ -98,7 +99,7 @@ void RayTracingInOneWeekend(Assets::CameraInitialSate& camera, std::vectorGetRendererType() != "RayQueryRenderer"; + const bool isProc = false; std::mt19937 engine(42); std::function random = std::bind(std::uniform_real_distribution(), engine); diff --git a/src/SceneList.hpp b/src/Runtime/SceneList.hpp similarity index 100% rename from src/SceneList.hpp rename to src/Runtime/SceneList.hpp diff --git a/src/TaskCoordinator.cpp b/src/Runtime/TaskCoordinator.cpp similarity index 100% rename from src/TaskCoordinator.cpp rename to src/Runtime/TaskCoordinator.cpp diff --git a/src/TaskCoordinator.hpp b/src/Runtime/TaskCoordinator.hpp similarity index 100% rename from src/TaskCoordinator.hpp rename to src/Runtime/TaskCoordinator.hpp diff --git a/src/UserInterface.cpp b/src/Runtime/UserInterface.cpp similarity index 91% rename from src/UserInterface.cpp rename to src/Runtime/UserInterface.cpp index fa4cb186..fae8575f 100644 --- a/src/UserInterface.cpp +++ b/src/Runtime/UserInterface.cpp @@ -504,7 +504,7 @@ void UserInterface::DrawSettings() ImGui::Separator(); ImGui::BulletText("%s", LOCTEXT("F1: toggle Settings.")); ImGui::BulletText("%s", LOCTEXT("F2: toggle Statistics.")); - ImGui::BulletText("%s", LOCTEXT("SPACE: hold to auto focus.")); + ImGui::BulletText("%s", LOCTEXT("Click: Click Object to Focus.")); ImGui::BulletText("%s", LOCTEXT("DropFile: if glb file, load it.")); ImGui::NewLine(); @@ -518,21 +518,13 @@ void UserInterface::DrawSettings() ImGui::Text("%s", LOCTEXT("Ray Tracing")); ImGui::Separator(); uint32_t min = 0, max = 7; //max bounce + 1 will off roulette. max bounce now is 6 - ImGui::SliderScalar(LOCTEXT("RR Start"), ImGuiDataType_U32, &Settings().RR_MIN_DEPTH, &min, &max); - ImGui::Checkbox(LOCTEXT("AdaptiveSample"), &Settings().AdaptiveSample); + //ImGui::SliderScalar(LOCTEXT("RR Start"), ImGuiDataType_U32, &Settings().RR_MIN_DEPTH, &min, &max); + //ImGui::Checkbox(LOCTEXT("AdaptiveSample"), &Settings().AdaptiveSample); ImGui::Checkbox(LOCTEXT("AntiAlias"), &Settings().TAA); - ImGui::SliderFloat(LOCTEXT("AdaptiveVariance"), &Settings().AdaptiveVariance, 0.1f, 10.0f, "%.0f"); + //ImGui::SliderFloat(LOCTEXT("AdaptiveVariance"), &Settings().AdaptiveVariance, 0.1f, 10.0f, "%.0f"); ImGui::SliderInt(LOCTEXT("TemporalSteps"), &Settings().AdaptiveSteps, 2, 16); - ImGui::NewLine(); - - // min = 1, max = 128; - // ImGui::SliderScalar("Samples", ImGuiDataType_U32, &Settings().NumberOfSamples, &min, &max); - // min = 1, max = 32; - // ImGui::SliderScalar("Bounces", ImGuiDataType_U32, &Settings().NumberOfBounces, &min, &max); - // ImGui::NewLine(); - #if WITH_OIDN ImGui::Text("Denoiser"); ImGui::Separator(); @@ -650,38 +642,38 @@ void UserInterface::DrawOverlay(const Statistics& statistics, Vulkan::VulkanGpuT } ImGui::End(); - if( Settings().AutoFocus ) - { - // draw a center dot with imgui - auto io = ImGui::GetIO(); - ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); - ImGui::SetNextWindowBgAlpha(0.0f); // Transparent background - ImGui::SetNextWindowSize(ImVec2(8, 8)); - - // set border color - ImGui::PushStyleColor(ImGuiCol_Border, !Settings().AutoFocus ? ImVec4(1,1,1,1) : Settings().HitResult.Hitted ? ImVec4(0.0f, 1.0f, 0.0f, 1.0f): ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(1,1)); - ImGui::Begin("CenterDot", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings); - //ImGui::Text(" "); - ImGui::End(); - ImGui::PopStyleColor(); - ImGui::PopStyleVar(); - - ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); - ImGui::SetNextWindowBgAlpha(0.0f); // Transparent background - ImGui::SetNextWindowSize(ImVec2(1, 1)); - - // set border color - ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f + 10.0f, io.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0, 0.5f)); - ImGui::SetNextWindowBgAlpha(0.0f); // Transparent background - ImGui::SetNextWindowSize(ImVec2(0, 0)); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0,0,0,0)); - ImGui::Begin("HitInfo", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings); - ImGui::Text("%.1fm\nInst: %d\nMat: %d", Settings().HitResult.T, Settings().HitResult.InstanceId, Settings().HitResult.MaterialId); - ImGui::End(); - ImGui::PopStyleColor(); - - } + // if( Settings().AutoFocus ) + // { + // // draw a center dot with imgui + // auto io = ImGui::GetIO(); + // ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + // ImGui::SetNextWindowBgAlpha(0.0f); // Transparent background + // ImGui::SetNextWindowSize(ImVec2(8, 8)); + // + // // set border color + // ImGui::PushStyleColor(ImGuiCol_Border, !Settings().AutoFocus ? ImVec4(1,1,1,1) : Settings().HitResult.Hitted ? ImVec4(0.0f, 1.0f, 0.0f, 1.0f): ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); + // ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(1,1)); + // ImGui::Begin("CenterDot", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings); + // //ImGui::Text(" "); + // ImGui::End(); + // ImGui::PopStyleColor(); + // ImGui::PopStyleVar(); + // + // ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + // ImGui::SetNextWindowBgAlpha(0.0f); // Transparent background + // ImGui::SetNextWindowSize(ImVec2(1, 1)); + // + // // set border color + // ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f + 10.0f, io.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0, 0.5f)); + // ImGui::SetNextWindowBgAlpha(0.0f); // Transparent background + // ImGui::SetNextWindowSize(ImVec2(0, 0)); + // ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0,0,0,0)); + // ImGui::Begin("HitInfo", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings); + // ImGui::Text("%.1fm\nInst: %d\nMat: %d", Settings().HitResult.T, Settings().HitResult.InstanceId, Settings().HitResult.MaterialId); + // ImGui::End(); + // ImGui::PopStyleColor(); + // + // } } void UserInterface::DrawIndicator(uint32_t frameCount) diff --git a/src/UserInterface.hpp b/src/Runtime/UserInterface.hpp similarity index 100% rename from src/UserInterface.hpp rename to src/Runtime/UserInterface.hpp diff --git a/src/UserSettings.hpp b/src/Runtime/UserSettings.hpp similarity index 100% rename from src/UserSettings.hpp rename to src/Runtime/UserSettings.hpp diff --git a/src/Utilities/Console.hpp b/src/Utilities/Console.hpp index 7a3a850e..4711ca1c 100644 --- a/src/Utilities/Console.hpp +++ b/src/Utilities/Console.hpp @@ -3,6 +3,7 @@ #include "Vulkan/Vulkan.hpp" #define CONSOLE_GREEN_COLOR "\033[1;32m-" +#define CONSOLE_GOLD_COLOR "\033[1;33m-" #define CONSOLE_DEFAULT_COLOR "\033[0m" namespace Utilities diff --git a/src/Vulkan/HybridDeferred/HybridDeferredRenderer.cpp b/src/Vulkan/HybridDeferred/HybridDeferredRenderer.cpp index 3fbe46bd..4566a204 100644 --- a/src/Vulkan/HybridDeferred/HybridDeferredRenderer.cpp +++ b/src/Vulkan/HybridDeferred/HybridDeferredRenderer.cpp @@ -23,8 +23,8 @@ namespace Vulkan::HybridDeferred { - HybridDeferredRenderer::HybridDeferredRenderer(const char* rendererType, const WindowConfig& windowConfig, const VkPresentModeKHR presentMode, const bool enableValidationLayers) : - RayTracing::RayTraceBaseRenderer(rendererType, windowConfig, presentMode, enableValidationLayers) + HybridDeferredRenderer::HybridDeferredRenderer(Vulkan::Window* window, const VkPresentModeKHR presentMode, const bool enableValidationLayers) : + RayTracing::RayTraceBaseRenderer(window, presentMode, enableValidationLayers) { } diff --git a/src/Vulkan/HybridDeferred/HybridDeferredRenderer.hpp b/src/Vulkan/HybridDeferred/HybridDeferredRenderer.hpp index 90e60f9b..a5ecd44c 100644 --- a/src/Vulkan/HybridDeferred/HybridDeferredRenderer.hpp +++ b/src/Vulkan/HybridDeferred/HybridDeferredRenderer.hpp @@ -38,7 +38,7 @@ namespace Vulkan::HybridDeferred VULKAN_NON_COPIABLE(HybridDeferredRenderer) - HybridDeferredRenderer(const char* rendererType, const WindowConfig& windowConfig, VkPresentModeKHR presentMode, bool enableValidationLayers); + HybridDeferredRenderer(Vulkan::Window* window, VkPresentModeKHR presentMode, bool enableValidationLayers); ~HybridDeferredRenderer(); void CreateSwapChain() override; diff --git a/src/Vulkan/LegacyDeferred/LegacyDeferredRenderer.cpp b/src/Vulkan/LegacyDeferred/LegacyDeferredRenderer.cpp index 30d80c52..3dc856f7 100644 --- a/src/Vulkan/LegacyDeferred/LegacyDeferredRenderer.cpp +++ b/src/Vulkan/LegacyDeferred/LegacyDeferredRenderer.cpp @@ -18,8 +18,8 @@ namespace Vulkan::LegacyDeferred { -LegacyDeferredRenderer::LegacyDeferredRenderer(const char* rendererType, const WindowConfig& windowConfig, const VkPresentModeKHR presentMode, const bool enableValidationLayers) : - Vulkan::VulkanBaseRenderer(rendererType, windowConfig, presentMode, enableValidationLayers) +LegacyDeferredRenderer::LegacyDeferredRenderer(Vulkan::Window* window, const VkPresentModeKHR presentMode, const bool enableValidationLayers) : + Vulkan::VulkanBaseRenderer(window, presentMode, enableValidationLayers) { } diff --git a/src/Vulkan/LegacyDeferred/LegacyDeferredRenderer.hpp b/src/Vulkan/LegacyDeferred/LegacyDeferredRenderer.hpp index d3c66f77..364dc20f 100644 --- a/src/Vulkan/LegacyDeferred/LegacyDeferredRenderer.hpp +++ b/src/Vulkan/LegacyDeferred/LegacyDeferredRenderer.hpp @@ -28,7 +28,7 @@ namespace Vulkan::LegacyDeferred VULKAN_NON_COPIABLE(LegacyDeferredRenderer) - LegacyDeferredRenderer(const char* rendererType, const WindowConfig& windowConfig, VkPresentModeKHR presentMode, bool enableValidationLayers); + LegacyDeferredRenderer(Vulkan::Window* window, VkPresentModeKHR presentMode, bool enableValidationLayers); ~LegacyDeferredRenderer(); void CreateSwapChain() override; diff --git a/src/Vulkan/ModernDeferred/ModernDeferredRenderer.cpp b/src/Vulkan/ModernDeferred/ModernDeferredRenderer.cpp index 94c00245..d2b6ce2a 100644 --- a/src/Vulkan/ModernDeferred/ModernDeferredRenderer.cpp +++ b/src/Vulkan/ModernDeferred/ModernDeferredRenderer.cpp @@ -19,8 +19,8 @@ namespace Vulkan::ModernDeferred { -ModernDeferredRenderer::ModernDeferredRenderer(const char* rendererType, const WindowConfig& windowConfig, const VkPresentModeKHR presentMode, const bool enableValidationLayers) : - Vulkan::VulkanBaseRenderer(rendererType, windowConfig, presentMode, enableValidationLayers) +ModernDeferredRenderer::ModernDeferredRenderer(Vulkan::Window* window,const VkPresentModeKHR presentMode, const bool enableValidationLayers) : + Vulkan::VulkanBaseRenderer(window, presentMode, enableValidationLayers) { } diff --git a/src/Vulkan/ModernDeferred/ModernDeferredRenderer.hpp b/src/Vulkan/ModernDeferred/ModernDeferredRenderer.hpp index 19096d8d..c28eab53 100644 --- a/src/Vulkan/ModernDeferred/ModernDeferredRenderer.hpp +++ b/src/Vulkan/ModernDeferred/ModernDeferredRenderer.hpp @@ -33,7 +33,7 @@ namespace Vulkan::ModernDeferred VULKAN_NON_COPIABLE(ModernDeferredRenderer) - ModernDeferredRenderer(const char* rendererType, const WindowConfig& windowConfig, VkPresentModeKHR presentMode, bool enableValidationLayers); + ModernDeferredRenderer(Vulkan::Window* window, VkPresentModeKHR presentMode, bool enableValidationLayers); ~ModernDeferredRenderer(); void CreateSwapChain() override; diff --git a/src/Vulkan/RayQuery/RayQueryRenderer.cpp b/src/Vulkan/RayQuery/RayQueryRenderer.cpp index 4df97366..499d0c65 100644 --- a/src/Vulkan/RayQuery/RayQueryRenderer.cpp +++ b/src/Vulkan/RayQuery/RayQueryRenderer.cpp @@ -43,9 +43,9 @@ namespace Vulkan::RayTracing } } - RayQueryRenderer::RayQueryRenderer(const char* rendererType, const WindowConfig& windowConfig, const VkPresentModeKHR presentMode, + RayQueryRenderer::RayQueryRenderer(Vulkan::Window* window,const VkPresentModeKHR presentMode, const bool enableValidationLayers) : - Vulkan::RayTracing::RayTraceBaseRenderer(rendererType, windowConfig, presentMode, enableValidationLayers) + Vulkan::RayTracing::RayTraceBaseRenderer(window, presentMode, enableValidationLayers) { } diff --git a/src/Vulkan/RayQuery/RayQueryRenderer.hpp b/src/Vulkan/RayQuery/RayQueryRenderer.hpp index b7e872e4..231d688a 100644 --- a/src/Vulkan/RayQuery/RayQueryRenderer.hpp +++ b/src/Vulkan/RayQuery/RayQueryRenderer.hpp @@ -31,9 +31,9 @@ namespace Vulkan::RayTracing VULKAN_NON_COPIABLE(RayQueryRenderer); - protected: + public: - RayQueryRenderer(const char* rendererType, const WindowConfig& windowConfig, VkPresentModeKHR presentMode, bool enableValidationLayers); + RayQueryRenderer(Vulkan::Window* window, VkPresentModeKHR presentMode, bool enableValidationLayers); virtual ~RayQueryRenderer(); void SetPhysicalDeviceImpl(VkPhysicalDevice physicalDevice, diff --git a/src/Vulkan/RayTrace/RayTracingRenderer.cpp b/src/Vulkan/RayTrace/RayTracingRenderer.cpp index 199600f3..e531724b 100644 --- a/src/Vulkan/RayTrace/RayTracingRenderer.cpp +++ b/src/Vulkan/RayTrace/RayTracingRenderer.cpp @@ -55,9 +55,9 @@ namespace Vulkan::RayTracing } } - RayTracingRenderer::RayTracingRenderer(const char* rendererType, const WindowConfig& windowConfig, const VkPresentModeKHR presentMode, + RayTracingRenderer::RayTracingRenderer( Vulkan::Window* window, const VkPresentModeKHR presentMode, const bool enableValidationLayers) : - RayTraceBaseRenderer(rendererType, windowConfig, presentMode, enableValidationLayers) + RayTraceBaseRenderer(window, presentMode, enableValidationLayers) { // try use amd gpu as denoise device } diff --git a/src/Vulkan/RayTrace/RayTracingRenderer.hpp b/src/Vulkan/RayTrace/RayTracingRenderer.hpp index 8c6352fa..d776d6a1 100644 --- a/src/Vulkan/RayTrace/RayTracingRenderer.hpp +++ b/src/Vulkan/RayTrace/RayTracingRenderer.hpp @@ -25,14 +25,11 @@ namespace Vulkan::RayTracing class RayTracingRenderer : public RayTraceBaseRenderer { public: - VULKAN_NON_COPIABLE(RayTracingRenderer); - - protected: - - RayTracingRenderer(const char* rendererType, const WindowConfig& windowConfig, VkPresentModeKHR presentMode, bool enableValidationLayers); + RayTracingRenderer(Vulkan::Window* window, VkPresentModeKHR presentMode, bool enableValidationLayers); virtual ~RayTracingRenderer(); - + + protected: void SetPhysicalDeviceImpl(VkPhysicalDevice physicalDevice, std::vector& requiredExtensions, VkPhysicalDeviceFeatures& deviceFeatures, diff --git a/src/Vulkan/RayTracing/RayTraceBaseRenderer.cpp b/src/Vulkan/RayTracing/RayTraceBaseRenderer.cpp index 08f985b9..1d3e9bb9 100644 --- a/src/Vulkan/RayTracing/RayTraceBaseRenderer.cpp +++ b/src/Vulkan/RayTracing/RayTraceBaseRenderer.cpp @@ -41,9 +41,9 @@ namespace Vulkan::RayTracing } } - RayTraceBaseRenderer::RayTraceBaseRenderer(const char* rendererType, const WindowConfig& windowConfig, const VkPresentModeKHR presentMode, + RayTraceBaseRenderer::RayTraceBaseRenderer(Vulkan::Window* window, const VkPresentModeKHR presentMode, const bool enableValidationLayers) : - Vulkan::VulkanBaseRenderer(rendererType, windowConfig, presentMode, enableValidationLayers) + Vulkan::VulkanBaseRenderer(window, presentMode, enableValidationLayers) { } @@ -86,8 +86,8 @@ namespace Vulkan::RayTracing void RayTraceBaseRenderer::OnDeviceSet() { + rayTracingProperties_.reset(new RayTracingProperties(Device())); Vulkan::VulkanBaseRenderer::OnDeviceSet(); - rayTracingProperties_.reset(new RayTracingProperties(Device())); } void RayTraceBaseRenderer::CreateAccelerationStructures() diff --git a/src/Vulkan/RayTracing/RayTraceBaseRenderer.hpp b/src/Vulkan/RayTracing/RayTraceBaseRenderer.hpp index 8e5df8f0..f3b62910 100644 --- a/src/Vulkan/RayTracing/RayTraceBaseRenderer.hpp +++ b/src/Vulkan/RayTracing/RayTraceBaseRenderer.hpp @@ -32,7 +32,7 @@ namespace Vulkan::RayTracing protected: - RayTraceBaseRenderer(const char* rendererType, const WindowConfig& windowConfig, VkPresentModeKHR presentMode, bool enableValidationLayers); + RayTraceBaseRenderer(Vulkan::Window* window, VkPresentModeKHR presentMode, bool enableValidationLayers); virtual ~RayTraceBaseRenderer(); void SetPhysicalDeviceImpl(VkPhysicalDevice physicalDevice, diff --git a/src/Vulkan/Vulkan.hpp b/src/Vulkan/Vulkan.hpp index 727bdc26..506ca705 100644 --- a/src/Vulkan/Vulkan.hpp +++ b/src/Vulkan/Vulkan.hpp @@ -27,7 +27,8 @@ ClassName& operator = (ClassName&&) = delete; \ ClassName(ClassName&&) = delete; \ ClassName& operator = (const ClassName&) = delete; \ ClassName& operator = (ClassName&&) = delete; \ - static const char* StaticClass() {return #ClassName;} + static const char* StaticClass() {return #ClassName;} \ + virtual const char* GetActualClassName() const {return #ClassName;} #define VULKAN_HANDLE(VulkanHandleType, name) \ public: \ diff --git a/src/Vulkan/VulkanBaseRenderer.cpp b/src/Vulkan/VulkanBaseRenderer.cpp index 52aaa038..9b87502e 100644 --- a/src/Vulkan/VulkanBaseRenderer.cpp +++ b/src/Vulkan/VulkanBaseRenderer.cpp @@ -28,35 +28,128 @@ #include "Options.hpp" #include "RenderImage.hpp" #include "SingleTimeCommands.hpp" -#include "TaskCoordinator.hpp" +#include "Strings.hpp" +#include "Version.hpp" #include "Vulkan/PipelineCommon/CommonComputePipeline.hpp" +namespace +{ + void PrintVulkanSdkInformation() + { + fmt::print("Vulkan SDK Header Version: {}\n\n", VK_HEADER_VERSION); + } + + void PrintVulkanInstanceInformation(const Vulkan::VulkanBaseRenderer& application, const bool benchmark) + { + if (benchmark) + { + return; + } + + puts("Vulkan Instance Extensions:"); + + for (const auto& extension : application.Extensions()) + { + fmt::print("- {} ({})\n", extension.extensionName, to_string(Vulkan::Version(extension.specVersion))); + } + + puts(""); + } + + void PrintVulkanLayersInformation(const Vulkan::VulkanBaseRenderer& application, const bool benchmark) + { + if (benchmark) + { + return; + } + + puts("Vulkan Instance Layers:"); + + for (const auto& layer : application.Layers()) + { + fmt::print("- {} ({}) : {}\n", layer.layerName, to_string(Vulkan::Version(layer.specVersion)), layer.description); + } + + puts(""); + } + + void PrintVulkanDevices(const Vulkan::VulkanBaseRenderer& application) + { + puts("Vulkan Devices:"); + + for (const auto& device : application.PhysicalDevices()) + { + VkPhysicalDeviceDriverProperties driverProp{}; + driverProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; + + VkPhysicalDeviceProperties2 deviceProp{}; + deviceProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + deviceProp.pNext = &driverProp; + vkGetPhysicalDeviceProperties2(device, &deviceProp); + VkPhysicalDeviceFeatures features; + vkGetPhysicalDeviceFeatures(device, &features); + + const auto& prop = deviceProp.properties; + + const Vulkan::Version vulkanVersion(prop.apiVersion); + const Vulkan::Version driverVersion(prop.driverVersion, prop.vendorID); + + fmt::print("- [{}] {} '{}' ({}: vulkan {} driver {} {} - {})\n", + prop.deviceID, Vulkan::Strings::VendorId(prop.vendorID), prop.deviceName, Vulkan::Strings::DeviceType(prop.deviceType), + to_string(vulkanVersion), driverProp.driverName, driverProp.driverInfo, to_string(driverVersion)); + } + + puts(""); + } + + void PrintVulkanSwapChainInformation(const Vulkan::VulkanBaseRenderer& application, const bool benchmark) + { + const auto& swapChain = application.SwapChain(); + + fmt::print("Swap Chain:\n- image count: {}\n- present mode: {}\n\n", swapChain.Images().size(), static_cast(swapChain.PresentMode())); + } + + void SetVulkanDevice(Vulkan::VulkanBaseRenderer& application, uint32_t gpuIdx) + { + const auto& physicalDevices = application.PhysicalDevices(); + VkPhysicalDevice pDevice = physicalDevices[gpuIdx <= physicalDevices.size() ? gpuIdx : 0 ]; + VkPhysicalDeviceProperties2 deviceProp{}; + deviceProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + vkGetPhysicalDeviceProperties2(pDevice, &deviceProp); + + fmt::print("Setting Device [{}]\n", deviceProp.properties.deviceName); + application.SetPhysicalDevice(pDevice); + + puts(""); + } +} + namespace Vulkan { -VulkanBaseRenderer::VulkanBaseRenderer(const char* rendererType, const WindowConfig& windowConfig, const VkPresentModeKHR presentMode, const bool enableValidationLayers) : - rendererType_(rendererType), +VulkanBaseRenderer::VulkanBaseRenderer(Vulkan::Window* window, const VkPresentModeKHR presentMode, const bool enableValidationLayers) : presentMode_(presentMode) { const auto validationLayers = enableValidationLayers ? std::vector{"VK_LAYER_KHRONOS_validation"} : std::vector{}; - - WindowConfig windowConfig_ = windowConfig; - windowConfig_.Title = windowConfig_.Title + " - " + GetRendererType(); - window_.reset(new class Window(windowConfig_)); + window_ = window; instance_.reset(new Instance(*window_, validationLayers, VK_API_VERSION_1_2)); debugUtilsMessenger_.reset(enableValidationLayers ? new DebugUtilsMessenger(*instance_, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) : nullptr); surface_.reset(new Surface(*instance_)); supportDenoiser_ = false; - supportScreenShot_ = windowConfig.NeedScreenShot; - forceSDR_ = windowConfig.ForceSDR; + forceSDR_ = GOption->ForceSDR; uptime = std::chrono::high_resolution_clock::now().time_since_epoch().count(); } VulkanGpuTimer::VulkanGpuTimer(VkDevice device, uint32_t totalCount, const VkPhysicalDeviceProperties& prop) { + if(GOption->Benchmark) + { + return; + } + device_ = device; time_stamps.resize(totalCount); timeStampPeriod_ = prop.limits.timestampPeriod; @@ -72,6 +165,11 @@ VulkanGpuTimer::VulkanGpuTimer(VkDevice device, uint32_t totalCount, const VkPhy VulkanGpuTimer::~VulkanGpuTimer() { + if(GOption->Benchmark) + { + return; + } + vkDestroyQueryPool(device_, query_pool_timestamps, nullptr); } @@ -88,7 +186,7 @@ VulkanBaseRenderer::~VulkanBaseRenderer() surface_.reset(); debugUtilsMessenger_.reset(); instance_.reset(); - window_.reset(); + window_ = nullptr; } const std::vector& VulkanBaseRenderer::Extensions() const @@ -142,54 +240,43 @@ void VulkanBaseRenderer::SetPhysicalDevice(VkPhysicalDevice physicalDevice) fmt::print("\n{} renderer initialized in {:.2f}ms{}\n", CONSOLE_GREEN_COLOR, uptime * 1e-6f, CONSOLE_DEFAULT_COLOR); } -void VulkanBaseRenderer::Run() +void VulkanBaseRenderer::Start() { - if (!device_) - { - Throw(std::logic_error("physical device has not been set")); - } - + // setup vulkan + + PrintVulkanSdkInformation(); + //PrintVulkanInstanceInformation(*GApplication, options.Benchmark); + //PrintVulkanLayersInformation(*GApplication, options.Benchmark); + PrintVulkanDevices(*this); + SetVulkanDevice(*this, GOption->GpuIdx); + PrintVulkanSwapChainInformation(*this, GOption->Benchmark); + currentFrame_ = 0; +} - window_->DrawFrame = [this]() { DrawFrame(); }; - window_->OnKey = [this](const int key, const int scancode, const int action, const int mods) { OnKey(key, scancode, action, mods); }; - window_->OnCursorPosition = [this](const double xpos, const double ypos) { OnCursorPosition(xpos, ypos); }; - window_->OnMouseButton = [this](const int button, const int action, const int mods) { OnMouseButton(button, action, mods); }; - window_->OnScroll = [this](const double xoffset, const double yoffset) { OnScroll(xoffset, yoffset); }; - window_->OnDropFile = [this](int path_count, const char* paths[]) { OnDropFile(path_count, paths); }; - window_->Run(); +void VulkanBaseRenderer::End() +{ device_->WaitIdle(); + gpuTimer_.reset(); } -void VulkanBaseRenderer::Start() +const Assets::Scene& VulkanBaseRenderer::GetScene() { - currentFrame_ = 0; - - window_->DrawFrame = [this]() { DrawFrame(); }; - window_->OnKey = [this](const int key, const int scancode, const int action, const int mods) { OnKey(key, scancode, action, mods); }; - window_->OnCursorPosition = [this](const double xpos, const double ypos) { OnCursorPosition(xpos, ypos); }; - window_->OnMouseButton = [this](const int button, const int action, const int mods) { OnMouseButton(button, action, mods); }; - window_->OnScroll = [this](const double xoffset, const double yoffset) { OnScroll(xoffset, yoffset); }; - window_->OnDropFile = [this](int path_count, const char* paths[]) { OnDropFile(path_count, paths); }; + return *scene_.lock(); } -void VulkanBaseRenderer::End() +void VulkanBaseRenderer::SetScene(std::shared_ptr scene) { - device_->WaitIdle(); - gpuTimer_.reset(); + scene_ = scene; } -bool VulkanBaseRenderer::Tick() +Assets::UniformBufferObject VulkanBaseRenderer::GetUniformBufferObject(const VkOffset2D offset, const VkExtent2D extent) const { -#if ANDROID - DrawFrame(); - return false; -#else - glfwPollEvents(); - DrawFrame(); - window_->attemptDragWindow(); - return glfwWindowShouldClose( window_->Handle() ) != 0; -#endif + if(DelegateGetUniformBufferObject) + { + return DelegateGetUniformBufferObject(offset, extent); + } + return {}; } void VulkanBaseRenderer::SetPhysicalDeviceImpl( @@ -198,10 +285,35 @@ void VulkanBaseRenderer::SetPhysicalDeviceImpl( VkPhysicalDeviceFeatures& deviceFeatures, void* nextDeviceFeatures) { + + deviceFeatures.fillModeNonSolid = true; + deviceFeatures.samplerAnisotropy = true; + + // Required extensions. windows only +#if WIN32 + requiredExtensions.insert(requiredExtensions.end(), + { + // VK_KHR_SHADER_CLOCK is required for heatmap + VK_KHR_SHADER_CLOCK_EXTENSION_NAME + }); + + // Opt-in into mandatory device features. + VkPhysicalDeviceShaderClockFeaturesKHR shaderClockFeatures = {}; + shaderClockFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR; + shaderClockFeatures.pNext = nextDeviceFeatures; + shaderClockFeatures.shaderSubgroupClock = true; + + deviceFeatures.shaderInt64 = true; +#endif + // support bindless material VkPhysicalDeviceDescriptorIndexingFeatures indexingFeatures = {}; indexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; +#if WIN32 + indexingFeatures.pNext = &shaderClockFeatures; +#else indexingFeatures.pNext = nextDeviceFeatures; +#endif indexingFeatures.runtimeDescriptorArray = true; indexingFeatures.shaderSampledImageArrayNonUniformIndexing = true; indexingFeatures.descriptorBindingPartiallyBound = true; @@ -227,6 +339,10 @@ void VulkanBaseRenderer::SetPhysicalDeviceImpl( void VulkanBaseRenderer::OnDeviceSet() { + if(DelegateOnDeviceSet) + { + DelegateOnDeviceSet(); + } } void VulkanBaseRenderer::CreateSwapChain() @@ -264,10 +380,20 @@ void VulkanBaseRenderer::CreateSwapChain() screenShotImageMemory_.reset(new DeviceMemory(screenShotImage_->AllocateMemory(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))); rtEditorViewport_.reset(new RenderImage(*device_, {1280,720}, swapChain_->Format(), VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)); + + if(DelegateCreateSwapChain) + { + DelegateCreateSwapChain(); + } } void VulkanBaseRenderer::DeleteSwapChain() { + if(DelegateDeleteSwapChain) + { + DelegateDeleteSwapChain(); + } + screenShotImageMemory_.reset(); screenShotImage_.reset(); commandBuffers_.reset(); @@ -439,8 +565,10 @@ void VulkanBaseRenderer::DrawFrame() ClearViewport(commandBuffer, currentImageIndex_); Render(commandBuffer, currentImageIndex_); - // vulkan command is submitted with the render pass, so, imgui cost should count in the render pass - RenderUI(commandBuffer, currentImageIndex_); + if(DelegatePostRender) + { + DelegatePostRender(commandBuffer, currentImageIndex_); + } } commandBuffers_->End(currentImageIndex_); diff --git a/src/Vulkan/VulkanBaseRenderer.hpp b/src/Vulkan/VulkanBaseRenderer.hpp index 4ad6258b..ef39ebc9 100644 --- a/src/Vulkan/VulkanBaseRenderer.hpp +++ b/src/Vulkan/VulkanBaseRenderer.hpp @@ -9,13 +9,15 @@ #include #include #include +#include #include #include "Image.hpp" +#include "Options.hpp" #define SCOPED_GPU_TIMER(name) ScopedGpuTimer scopedGpuTimer(commandBuffer, GpuTimer(), name) #define SCOPED_CPU_TIMER(name) ScopedCpuTimer scopedCpuTimer(GpuTimer(), name) - +#define BENCH_MARK_CHECK() if(GOption->Benchmark) return namespace Vulkan { namespace PipelineCommon @@ -46,6 +48,7 @@ namespace Vulkan void Reset(VkCommandBuffer commandBuffer) { + BENCH_MARK_CHECK(); vkCmdResetQueryPool(commandBuffer, query_pool_timestamps, 0, static_cast(time_stamps.size())); queryIdx = 0; started_ = true; @@ -53,6 +56,7 @@ namespace Vulkan void FrameEnd(VkCommandBuffer commandBuffer) { + BENCH_MARK_CHECK(); if(started_) { started_ = false; @@ -80,6 +84,7 @@ namespace Vulkan void Start(VkCommandBuffer commandBuffer, const char* name) { + BENCH_MARK_CHECK(); if( timer_query_map.find(name) == timer_query_map.end()) { timer_query_map[name] = std::make_tuple(0, 0); @@ -90,6 +95,7 @@ namespace Vulkan } void End(VkCommandBuffer commandBuffer, const char* name) { + BENCH_MARK_CHECK(); assert( timer_query_map.find(name) != timer_query_map.end() ); vkCmdWriteTimestamp(commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, query_pool_timestamps, queryIdx); std::get<1>(timer_query_map[name]) = queryIdx; @@ -97,6 +103,7 @@ namespace Vulkan } void StartCpuTimer(const char* name) { + BENCH_MARK_CHECK(); if( cpu_timer_query_map.find(name) == cpu_timer_query_map.end()) { cpu_timer_query_map[name] = std::make_tuple(0, 0); @@ -105,6 +112,7 @@ namespace Vulkan } void EndCpuTimer(const char* name) { + BENCH_MARK_CHECK(); assert( cpu_timer_query_map.find(name) != cpu_timer_query_map.end() ); std::get<1>(cpu_timer_query_map[name]) = std::chrono::high_resolution_clock::now().time_since_epoch().count(); } @@ -218,14 +226,10 @@ namespace Vulkan bool HasSwapChain() const { return swapChain_.operator bool(); } void SetPhysicalDevice(VkPhysicalDevice physicalDevice); - void Run(); void Start(); - bool Tick(); void End(); - - virtual void OnTouch(bool down, double xpos, double ypos) {} - virtual void OnTouchMove(double xpos, double ypos) {} + virtual bool GetFocusDistance(float& distance) const {return false;} virtual bool GetLastRaycastResult(Assets::RayCastResult& result) const {return false;} virtual void SetRaycastRay(glm::vec3 org, glm::vec3 dir) const {}; @@ -236,11 +240,10 @@ namespace Vulkan RenderImage& GetRenderImage() const {return *rtEditorViewport_;} - const std::string& GetRendererType() const {return rendererType_;} - - protected: + virtual void DrawFrame(); - VulkanBaseRenderer(const char* rendererType, const WindowConfig& windowConfig, VkPresentModeKHR presentMode, bool enableValidationLayers); + + VulkanBaseRenderer(Vulkan::Window* window, VkPresentModeKHR presentMode, bool enableValidationLayers); const class Device& Device() const { return *device_; } class CommandPool& CommandPool() { return *commandPool_; } @@ -251,8 +254,10 @@ namespace Vulkan const bool CheckerboxRendering() {return checkerboxRendering_;} class VulkanGpuTimer* GpuTimer() const {return gpuTimer_.get();} - virtual const Assets::Scene& GetScene() const = 0; - virtual Assets::UniformBufferObject GetUniformBufferObject(const VkOffset2D offset, const VkExtent2D extent) const = 0; + const Assets::Scene& GetScene(); + void SetScene(std::shared_ptr scene); + virtual Assets::UniformBufferObject GetUniformBufferObject(const VkOffset2D offset, const VkExtent2D extent) const; + virtual void SetPhysicalDeviceImpl( VkPhysicalDevice physicalDevice, @@ -263,36 +268,48 @@ namespace Vulkan virtual void OnDeviceSet(); virtual void CreateSwapChain(); virtual void DeleteSwapChain(); - virtual void DrawFrame(); virtual void Render(VkCommandBuffer commandBuffer, uint32_t imageIndex); - virtual void RenderUI(VkCommandBuffer commandBuffer, uint32_t imageIndex) {} - virtual void BeforeNextFrame() {} + virtual void BeforeNextFrame() + { + if(DelegateBeforeNextTick) + { + DelegateBeforeNextTick(); + } + } virtual void AfterRenderCmd() {} virtual void AfterPresent() {} virtual void OnPreLoadScene() {} virtual void OnPostLoadScene() {} - virtual void OnKey(int key, int scancode, int action, int mods) { } - virtual void OnCursorPosition(double xpos, double ypos) { } - virtual void OnMouseButton(int button, int action, int mods) { } - virtual void OnScroll(double xoffset, double yoffset) { } - virtual void OnDropFile(int path_count, const char* paths[]) { } + // Callbacks + std::function DelegateOnDeviceSet; + std::function DelegateCreateSwapChain; + std::function DelegateDeleteSwapChain; + std::function DelegateBeforeNextTick; + std::function DelegateGetUniformBufferObject; + std::function DelegatePostRender; + + // std::function OnScroll; + // std::function OnDropFile; + // std::function OnFocus; + + DeviceMemory* GetScreenShotMemory() const {return screenShotImageMemory_.get();} + + std::weak_ptr scene_; + bool isWireFrame_{}; bool checkerboxRendering_{}; bool supportRayTracing_ {}; bool supportDenoiser_ {}; int frameCount_{}; - bool supportScreenShot_{}; bool forceSDR_{}; bool visualDebug_{}; - - std::string rendererType_{}; - + protected: Assets::UniformBufferObject lastUBO; - DeviceMemory* GetScreenShotMemory() const {return screenShotImageMemory_.get();} + private: void UpdateUniformBuffer(uint32_t imageIndex); @@ -300,7 +317,7 @@ namespace Vulkan const VkPresentModeKHR presentMode_; - std::unique_ptr window_; + class Window* window_; std::unique_ptr instance_; std::unique_ptr debugUtilsMessenger_; std::unique_ptr surface_; diff --git a/src/Vulkan/Window.cpp b/src/Vulkan/Window.cpp index fbb0c7d1..c29b7638 100644 --- a/src/Vulkan/Window.cpp +++ b/src/Vulkan/Window.cpp @@ -231,23 +231,6 @@ bool Window::IsMinimized() const return size.height == 0 && size.width == 0; } -void Window::Run() -{ -#if !ANDROID - glfwSetTime(0.0); - - while (!glfwWindowShouldClose(window_)) - { - glfwPollEvents(); - - if (DrawFrame) - { - DrawFrame(); - } - } -#endif -} - void Window::WaitForEvents() const { #if !ANDROID diff --git a/src/Vulkan/Window.hpp b/src/Vulkan/Window.hpp index 33d3ce40..f1948b86 100644 --- a/src/Vulkan/Window.hpp +++ b/src/Vulkan/Window.hpp @@ -32,7 +32,6 @@ namespace Vulkan double GetTime() const; // Callbacks - std::function DrawFrame; std::function OnKey; std::function OnCursorPosition; std::function OnMouseButton; diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index ee3e32a9..00000000 --- a/src/main.cpp +++ /dev/null @@ -1,550 +0,0 @@ -#include "Vulkan/Enumerate.hpp" -#include "Vulkan/Strings.hpp" -#include "Vulkan/SwapChain.hpp" -#include "Vulkan/Version.hpp" -#include "Utilities/Console.hpp" -#include "Utilities/Exception.hpp" -#include "Options.hpp" -#include "Application.hpp" - -#include -#include -#include -#include - -#include "TaskCoordinator.hpp" -#include "Vulkan/RayQuery/RayQueryRenderer.hpp" -#include "Vulkan/RayTrace/RayTracingRenderer.hpp" -#include "Vulkan/HybridDeferred/HybridDeferredRenderer.hpp" -#include "Vulkan/LegacyDeferred/LegacyDeferredRenderer.hpp" -#include "Vulkan/ModernDeferred/ModernDeferredRenderer.hpp" -#include - -#define BUILDVER(X) std::string buildver(#X); -#include "build.version" - -namespace NextRenderer -{ - std::string GetBuildVersion() - { - return buildver; - } -} - -#if ANDROID -#include -#include -#include - -static void MakeExternalDirectory( android_app* app, std::string srcPath ) -{ - if( std::filesystem::exists(std::string("/sdcard/Android/data/com.gknextrenderer/files/") + srcPath) ) - { - return; - } - - std::filesystem::create_directories(std::filesystem::path(std::string("/sdcard/Android/data/com.gknextrenderer/files/") + srcPath)); - - AAssetDir* assetDir = AAssetManager_openDir( - app->activity->assetManager, srcPath.c_str()); - const char* filename; - while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL){ - AAsset* file = AAssetManager_open(app->activity->assetManager, (srcPath + "/" + filename).c_str(), - AASSET_MODE_BUFFER); - size_t fileLen = AAsset_getLength(file); - std::vector fileData; - fileData.resize(fileLen); - - AAsset_read(file, static_cast(fileData.data()), fileLen); - AAsset_close(file); - - std::string targetPath = std::string("/sdcard/Android/data/com.gknextrenderer/files/") + srcPath + "/" + filename; - - FILE* targetFile = fopen(targetPath.c_str(), "wb"); - fwrite(fileData.data(), 1, fileLen, targetFile); - fclose(targetFile); - } - AAssetDir_close(assetDir); -} - -class androidbuf : public std::streambuf { -public: - enum { bufsize = 512 }; // ... or some other suitable buffer size - androidbuf() { this->setp(buffer, buffer + bufsize - 1); } - -private: - int overflow(int c) - { - if (c == traits_type::eof()) { - *this->pptr() = traits_type::to_char_type(c); - this->sbumpc(); - } - return this->sync()? traits_type::eof(): traits_type::not_eof(c); - } - - int sync() - { - int rc = 0; - if (this->pbase() != this->pptr()) { - char writebuf[bufsize+1]; - memcpy(writebuf, this->pbase(), this->pptr() - this->pbase()); - writebuf[this->pptr() - this->pbase()] = '\0'; - - rc = __android_log_print(ANDROID_LOG_INFO, "vkdemo", "%s", writebuf) > 0; - this->setp(buffer, buffer + bufsize - 1); - } - return rc; - } - - char buffer[bufsize]; -}; -#endif - - -namespace -{ - UserSettings CreateUserSettings(const Options& options); - void PrintVulkanSdkInformation(); - void PrintVulkanInstanceInformation(const Vulkan::VulkanBaseRenderer& application, bool benchmark); - void PrintVulkanLayersInformation(const Vulkan::VulkanBaseRenderer& application, bool benchmark); - void PrintVulkanDevices(const Vulkan::VulkanBaseRenderer& application); - void PrintVulkanSwapChainInformation(const Vulkan::VulkanBaseRenderer& application, bool benchmark); - void SetVulkanDevice(Vulkan::VulkanBaseRenderer& application, uint32_t gpuIdx); -} - -std::unique_ptr GApplication = nullptr; - -void StartApplication(uint32_t rendererType, const Vulkan::WindowConfig& windowConfig, const UserSettings& userSettings, const Options& options) -{ - switch (rendererType) - { - case 0: - GApplication.reset(new NextRendererApplication( - userSettings, windowConfig, static_cast(options.Benchmark ? 0 : options.PresentMode))); - break; - case 1: - GApplication.reset(new NextRendererApplication( - userSettings, windowConfig, static_cast(options.Benchmark ? 0 : options.PresentMode))); - break; - case 2: - GApplication.reset(new NextRendererApplication( - userSettings, windowConfig, static_cast(options.Benchmark ? 0 : options.PresentMode))); - break; - case 3: - GApplication.reset(new NextRendererApplication( - userSettings, windowConfig, static_cast(options.Benchmark ? 0 : options.PresentMode))); - break; - case 4: - GApplication.reset(new NextRendererApplication( - userSettings, windowConfig, static_cast(options.Benchmark ? 0 : options.PresentMode))); - break; - default: - GApplication.reset(new NextRendererApplication( - userSettings, windowConfig, static_cast(options.Benchmark ? 0 : options.PresentMode))); - } - - fmt::print("Renderer: {}, BuildVer: {}\n", GApplication->GetRendererType(), NextRenderer::GetBuildVersion()); - - PrintVulkanSdkInformation(); - //PrintVulkanInstanceInformation(*GApplication, options.Benchmark); - //PrintVulkanLayersInformation(*GApplication, options.Benchmark); - PrintVulkanDevices(*GApplication); - - SetVulkanDevice(*GApplication, options.GpuIdx); - - PrintVulkanSwapChainInformation(*GApplication, options.Benchmark); -} - -#if ANDROID -void handle_cmd(android_app* app, int32_t cmd) { - switch (cmd) { - case APP_CMD_INIT_WINDOW: - // The window is being shown, get it ready. - { - MakeExternalDirectory(app, "assets/fonts"); - MakeExternalDirectory(app, "assets/models"); - MakeExternalDirectory(app, "assets/shaders"); - MakeExternalDirectory(app, "assets/textures"); - MakeExternalDirectory(app, "assets/locale"); - - const char* argv[] = { "gkNextRenderer", "--renderer=4", "--scene=1", "--load-scene=qx50.glb"}; - const Options options(4, argv); - GOption = &options; - UserSettings userSettings = CreateUserSettings(options); - const Vulkan::WindowConfig windowConfig - { - "gkNextRenderer", - options.Width, - options.Height, - options.Benchmark && options.Fullscreen, - options.Fullscreen, - !options.Fullscreen, - options.SaveFile, - app->window, - options.ForceSDR - }; - StartApplication(options.RendererType, windowConfig, userSettings, options); - __android_log_print(ANDROID_LOG_INFO, "vkdemo", - "start gknextrenderer: %d", options.RendererType); - GApplication->Start(); - } - break; - case APP_CMD_TERM_WINDOW: - // The window is being hidden or closed, clean it up. - { - - } - break; - default: - __android_log_print(ANDROID_LOG_INFO, "Vulkan Tutorials", - "event not handled: %d", cmd); - } -} - -static int32_t engine_handle_input(struct android_app* app) { - ImGuiIO& io = ImGui::GetIO(); - //auto* engine = (struct engine*)app->userData; - auto ib = android_app_swap_input_buffers(app); - if (ib && ib->motionEventsCount) { - for (int i = 0; i < ib->motionEventsCount; i++) { - auto *event = &ib->motionEvents[i]; - int32_t ptrIdx = 0; - switch (event->action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: - // Retrieve the index for the starting and the ending of any secondary pointers - ptrIdx = (event->action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> - AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_UP: - io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); - io.AddMousePosEvent(GameActivityPointerAxes_getAxisValue( - &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X) * 0.75, GameActivityPointerAxes_getAxisValue( - &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y) * 0.75); - io.AddMouseButtonEvent(0, event->action == AMOTION_EVENT_ACTION_DOWN); - - GApplication->OnTouch(event->action == AMOTION_EVENT_ACTION_DOWN, GameActivityPointerAxes_getAxisValue( - &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y) * 0.75, - GameActivityPointerAxes_getAxisValue( - &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X) * 0.75); - - break; - case AMOTION_EVENT_ACTION_MOVE: - // Process the move action: the new coordinates for all active touch pointers - // are inside the event->pointers[]. Compare with our internally saved - // coordinates to find out which pointers are actually moved. Note that there is - // no index embedded inside event->action for AMOTION_EVENT_ACTION_MOVE (there - // might be multiple pointers moved at the same time). - //... - io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); - io.AddMousePosEvent(GameActivityPointerAxes_getAxisValue( - &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X) * 0.75, - GameActivityPointerAxes_getAxisValue( - &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y) * 0.75); - - GApplication->OnTouchMove(GameActivityPointerAxes_getAxisValue( - &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y) * 0.75, - GameActivityPointerAxes_getAxisValue( - &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X) * 0.75); - break; - } - } - android_app_clear_motion_events(ib); - } - - // Process the KeyEvent in a similar way. - //... - -return 0; -} - -void android_main(struct android_app* app) -{ - std::cout.rdbuf(new androidbuf); - - app->onAppCmd = handle_cmd; - - // Used to poll the events in the main loop - int events; - android_poll_source* source; - - // Main loop - do { - if (ALooper_pollAll(GApplication != nullptr ? 1 : 0, nullptr, - &events, (void**)&source) >= 0) { - if (source != NULL) source->process(app, source); - } - - engine_handle_input(app); - - // render if vulkan is ready - if (GApplication != nullptr) { - GApplication->Tick(); - } - } while (app->destroyRequested == 0); - - delete std::cout.rdbuf(0); -} -#endif - -int main(int argc, const char* argv[]) noexcept -{ - try - { - const Options options(argc, argv); - GOption = &options; - UserSettings userSettings = CreateUserSettings(options); - const Vulkan::WindowConfig windowConfig - { - "gkNextRenderer " + NextRenderer::GetBuildVersion(), - options.Width, - options.Height, - options.Benchmark && options.Fullscreen, - options.Fullscreen, - !options.Fullscreen, - options.SaveFile, - nullptr, - options.ForceSDR - }; - - - uint32_t rendererType = options.RendererType; - -#if __APPLE__ - setenv("MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS", "1", 1); -#endif - if(options.RenderDoc) - { -#if __linux__ - setenv("ENABLE_VULKAN_RENDERDOC_CAPTURE", "1", 1); -#endif - -#if __APPLE__ - setenv("MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE", "~/capture/cap.gputrace", 1); - setenv("MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX", "0", 1); - setenv("MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX", "0", 1); - setenv("MTL_CAPTURE_ENABLED", "1", 1); - setenv("MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE","2",1); -#endif - } - -#if WIN32 && !defined(__MINGW32__) - HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD dwMode; - - GetConsoleMode(hOutput, &dwMode); - dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(hOutput, dwMode); -#endif - - StartApplication(rendererType, windowConfig, userSettings, options); - - { - GApplication->Start(); - while (1) - { - if( GApplication->Tick() ) - { - break; - } - } - GApplication->End(); - } - - GApplication.reset(); - - return EXIT_SUCCESS; - } - - catch (const Options::Help&) - { - return EXIT_SUCCESS; - } - - catch (const std::exception& exception) - { - Utilities::Console::Write(Utilities::Severity::Fatal, [&exception]() - { - const auto stacktrace = boost::get_error_info(exception); - - std::cerr << "FATAL: " << exception.what() << std::endl; - - if (stacktrace) - { - std::cerr << '\n' << *stacktrace << '\n'; - } - }); - } - - catch (...) - { - Utilities::Console::Write(Utilities::Severity::Fatal, []() - { - fmt::print(stderr, "FATAL: caught unhandled exception\n"); - }); - } - - return EXIT_FAILURE; -} - -namespace -{ - UserSettings CreateUserSettings(const Options& options) - { - SceneList::ScanScenes(); - - UserSettings userSettings{}; - - userSettings.Benchmark = options.Benchmark; - userSettings.BenchmarkNextScenes = options.BenchmarkNextScenes; - userSettings.BenchmarkMaxTime = options.BenchmarkMaxTime; - userSettings.BenchmarkMaxFrame = options.BenchmarkMaxFrame; - userSettings.SceneIndex = options.SceneIndex; - - if(options.SceneName != "") - { - std::string mappedSceneName = ""; - bool foundInAssets = false; - - //if found options.SceneName in key of Assets::sceneNames - set mappedSceneName to compare and find scene - Assets::uo_string_string_t::const_iterator got = Assets::sceneNames.find(options.SceneName); - if (got != Assets::sceneNames.end()) mappedSceneName = got->second; - - for( uint32_t i = 0; i < SceneList::AllScenes.size(); i++ ) - { - if( SceneList::AllScenes[i].first == options.SceneName || SceneList::AllScenes[i].first == mappedSceneName ) - { - userSettings.SceneIndex = i; - foundInAssets = true; - break; - } - } - - if(!foundInAssets) - { - userSettings.SceneIndex = SceneList::AddExternalScene(options.SceneName); - } - } - - userSettings.IsRayTraced = true; - userSettings.AccumulateRays = false; - userSettings.NumberOfSamples = options.Benchmark ? 1 : options.Samples; - userSettings.NumberOfBounces = options.Benchmark ? 4 : options.Bounces; - userSettings.MaxNumberOfBounces = options.MaxBounces; - userSettings.RR_MIN_DEPTH = options.RR_MIN_DEPTH; - userSettings.AdaptiveSample = options.AdaptiveSample; - userSettings.AdaptiveVariance = 6.0f; - userSettings.AdaptiveSteps = 8; - userSettings.TAA = true; - - userSettings.ShowSettings = !options.Benchmark; - userSettings.ShowOverlay = true; - - userSettings.ShowVisualDebug = false; - userSettings.HeatmapScale = 1.5f; - - userSettings.UseCheckerBoardRendering = false; - userSettings.TemporalFrames = options.Benchmark ? 256 : options.Temporal; - - userSettings.Denoiser = options.Denoiser; - - userSettings.PaperWhiteNit = 600.f; - - userSettings.SunRotation = 0.5f; - userSettings.SunLuminance = 500.f; - userSettings.SkyIntensity = 50.f; - - userSettings.AutoFocus = false; - - return userSettings; - } - - void PrintVulkanSdkInformation() - { - fmt::print("Vulkan SDK Header Version: {}\n\n", VK_HEADER_VERSION); - } - - void PrintVulkanInstanceInformation(const Vulkan::VulkanBaseRenderer& application, const bool benchmark) - { - if (benchmark) - { - return; - } - - puts("Vulkan Instance Extensions:"); - - for (const auto& extension : application.Extensions()) - { - fmt::print("- {} ({})\n", extension.extensionName, to_string(Vulkan::Version(extension.specVersion))); - } - - puts(""); - } - - void PrintVulkanLayersInformation(const Vulkan::VulkanBaseRenderer& application, const bool benchmark) - { - if (benchmark) - { - return; - } - - puts("Vulkan Instance Layers:"); - - for (const auto& layer : application.Layers()) - { - fmt::print("- {} ({}) : {}\n", layer.layerName, to_string(Vulkan::Version(layer.specVersion)), layer.description); - } - - puts(""); - } - - void PrintVulkanDevices(const Vulkan::VulkanBaseRenderer& application) - { - puts("Vulkan Devices:"); - - for (const auto& device : application.PhysicalDevices()) - { - VkPhysicalDeviceDriverProperties driverProp{}; - driverProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; - - VkPhysicalDeviceProperties2 deviceProp{}; - deviceProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - deviceProp.pNext = &driverProp; - vkGetPhysicalDeviceProperties2(device, &deviceProp); - VkPhysicalDeviceFeatures features; - vkGetPhysicalDeviceFeatures(device, &features); - - const auto& prop = deviceProp.properties; - - const Vulkan::Version vulkanVersion(prop.apiVersion); - const Vulkan::Version driverVersion(prop.driverVersion, prop.vendorID); - - fmt::print("- [{}] {} '{}' ({}: vulkan {} driver {} {} - {})\n", - prop.deviceID, Vulkan::Strings::VendorId(prop.vendorID), prop.deviceName, Vulkan::Strings::DeviceType(prop.deviceType), - to_string(vulkanVersion), driverProp.driverName, driverProp.driverInfo, to_string(driverVersion)); - } - - puts(""); - } - - void PrintVulkanSwapChainInformation(const Vulkan::VulkanBaseRenderer& application, const bool benchmark) - { - const auto& swapChain = application.SwapChain(); - - fmt::print("Swap Chain:\n- image count: {}\n- present mode: {}\n\n", swapChain.Images().size(), static_cast(swapChain.PresentMode())); - } - - void SetVulkanDevice(Vulkan::VulkanBaseRenderer& application, uint32_t gpuIdx) - { - const auto& physicalDevices = application.PhysicalDevices(); - VkPhysicalDevice pDevice = physicalDevices[gpuIdx <= physicalDevices.size() ? gpuIdx : 0 ]; - VkPhysicalDeviceProperties2 deviceProp{}; - deviceProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - vkGetPhysicalDeviceProperties2(pDevice, &deviceProp); - - fmt::print("Setting Device [{}]\n", deviceProp.properties.deviceName); - application.SetPhysicalDevice(pDevice); - - puts(""); - } -} diff --git a/vcpkg_windows.bat b/vcpkg_windows.bat index ab148f95..2f093900 100644 --- a/vcpkg_windows.bat +++ b/vcpkg_windows.bat @@ -9,11 +9,15 @@ IF EXIST vcpkg.windows ( ) ELSE ( git clone https://github.com/Microsoft/vcpkg.git vcpkg.windows || goto :error cd vcpkg.windows || goto :error + git checkout 2024.08.23 || goto :error + call bootstrap-vcpkg.bat || goto :error ) rem handle the vcpkg update, auto process -git checkout 2024.08.23 || goto :error -call bootstrap-vcpkg.bat || goto :error +IF "%1" == "forceinstall" ( + git checkout 2024.08.23 || goto :error + call bootstrap-vcpkg.bat || goto :error +) rem add if want avif libavif[aom]:x64-windows-static ^ vcpkg.exe install --recurse ^ @@ -31,6 +35,10 @@ vcpkg.exe install --recurse ^ fmt:x64-windows-static ^ cpp-base64:x64-windows-static || goto :error +IF "%1" == "avif" ( + vcpkg.exe install --recurse libavif[aom]:x64-windows-static || goto :error +) + cd .. cd ..