diff --git a/68_JpegLoading/CMakeLists.txt b/68_JpegLoading/CMakeLists.txt new file mode 100644 index 000000000..54aa0c43b --- /dev/null +++ b/68_JpegLoading/CMakeLists.txt @@ -0,0 +1,27 @@ +include(common RESULT_VARIABLE RES) +if(NOT RES) + message(FATAL_ERROR "common.cmake not found. Should be in {repo_root}/cmake directory") +endif() + +nbl_create_executable_project("" "" "" "" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}") + +if(NBL_EMBED_BUILTIN_RESOURCES) + set(_BR_TARGET_ ${EXECUTABLE_NAME}_builtinResourceData) + set(RESOURCE_DIR "app_resources") + + get_filename_component(_SEARCH_DIRECTORIES_ "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/src" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/include" ABSOLUTE) + + file(GLOB_RECURSE BUILTIN_RESOURCE_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}" CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}/*") + foreach(RES_FILE ${BUILTIN_RESOURCE_FILES}) + LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "${RES_FILE}") + endforeach() + + ADD_CUSTOM_BUILTIN_RESOURCES(${_BR_TARGET_} RESOURCES_TO_EMBED "${_SEARCH_DIRECTORIES_}" "${RESOURCE_DIR}" "nbl::this_example::builtin" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}") + + LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} ${_BR_TARGET_}) +endif() + +add_dependencies(${EXECUTABLE_NAME} argparse) +target_include_directories(${EXECUTABLE_NAME} PUBLIC $) \ No newline at end of file diff --git a/68_JpegLoading/main.cpp b/68_JpegLoading/main.cpp new file mode 100644 index 000000000..5ef9b637d --- /dev/null +++ b/68_JpegLoading/main.cpp @@ -0,0 +1,193 @@ +// Copyright (C) 2018-2024 - DevSH GrapMonoAssetManagerAndBuiltinResourceApplicationhics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#include "nbl/application_templates/MonoAssetManagerAndBuiltinResourceApplication.hpp" + +#include + +#include "nlohmann/json.hpp" +#include "argparse/argparse.hpp" + +using json = nlohmann::json; + +using namespace nbl; +using namespace core; +using namespace hlsl; +using namespace system; +using namespace asset; +using namespace ui; +using namespace video; + +class ThreadPool +{ +using task_t = std::function; +public: + ThreadPool(size_t workers = std::thread::hardware_concurrency()) + { + for (size_t i = 0; i < workers; i++) + { + m_workers.emplace_back([this] { + task_t task; + + while (1) + { + { + std::unique_lock lock(m_queueLock); + m_taskAvailable.wait(lock, [this] { return !m_tasks.empty() || m_shouldStop; }); + + if (m_shouldStop && m_tasks.empty()) { + return; + } + + task = std::move(m_tasks.front()); + m_tasks.pop(); + } + + task(); + } + }); + } + } + + ~ThreadPool() + { + m_shouldStop = true; + m_taskAvailable.notify_all(); + + for (auto& worker : m_workers) + { + worker.join(); + } + } + + void enqueue(task_t task) + { + { + std::lock_guard lock(m_queueLock); + m_tasks.emplace(std::move(task)); + } + m_taskAvailable.notify_one(); + } + private: + std::mutex m_queueLock; + std::condition_variable m_taskAvailable; + std::vector m_workers; + std::queue m_tasks; + std::atomic m_shouldStop = false; +}; + +class JpegLoaderApp final : public application_templates::MonoAssetManagerAndBuiltinResourceApplication +{ + using clock_t = std::chrono::steady_clock; + using clock_resolution_t = std::chrono::milliseconds; + using base_t = application_templates::MonoAssetManagerAndBuiltinResourceApplication; + public: + using base_t::base_t; + + inline bool onAppInitialized(smart_refctd_ptr&& system) override + { + argparse::ArgumentParser program("Color Space"); + + program.add_argument("--directory") + .required() + .help("Path to a directory where all JPEG files are stored (not recursive)"); + + program.add_argument("--output") + .default_value("output.json") + .help("Path to the file where the benchmark result will be stored"); + + try + { + program.parse_args({ argv.data(), argv.data() + argv.size() }); + } + catch (const std::exception& err) + { + std::cerr << err.what() << std::endl << program; // NOTE: std::cerr because logger isn't initialized yet + return false; + } + + if (!base_t::onAppInitialized(std::move(system))) + return false; + + options.directory = program.get("--directory"); + options.outputFile = program.get("--output"); + + // check if directory exists + if (!std::filesystem::exists(options.directory)) + { + logFail("Provided directory doesn't exist"); + return false; + } + + auto start = clock_t::now(); + std::vector files; + + { + ThreadPool tp; + + constexpr auto cachingFlags = static_cast(IAssetLoader::ECF_DONT_CACHE_REFERENCES & IAssetLoader::ECF_DONT_CACHE_TOP_LEVEL); + const IAssetLoader::SAssetLoadParams loadParams(0ull, nullptr, cachingFlags, IAssetLoader::ELPF_NONE, m_logger.get()); + + for (auto& item : std::filesystem::directory_iterator(options.directory)) + { + auto& path = item.path(); + if (path.has_extension() && path.extension() == ".jpg") + { + files.emplace_back(std::move(path.generic_string())); + + ISystem::future_t> future; + m_system->createFile(future, path, IFile::ECF_READ | IFile::ECF_MAPPABLE); + + if (auto pFile = future.acquire(); pFile && pFile->get()) + { + auto& file = *pFile; + tp.enqueue([=] { + m_logger->log("Loading %S", ILogger::ELL_INFO, path.c_str()); + m_assetMgr->getAsset(file.get(), path.generic_string(), loadParams); + }); + } + } + } + } + + auto stop = clock_t::now(); + auto time = std::chrono::duration_cast(stop - start).count(); + + m_logger->log("Process took %llu ms", ILogger::ELL_INFO, time); + + // Dump data to JSON + json j; + j["loaded_files"] = files; + j["duration_ms"] = time; + + std::ofstream output(options.outputFile); + if (!output.good()) + { + logFail("Failed to open %S", options.outputFile); + return false; + } + + output << j; + + return true; + } + + inline bool keepRunning() override + { + return false; + } + + inline void workLoopBody() override + { + + } + +private: + struct NBL_APP_OPTIONS + { + std::string directory; + std::string outputFile; + } options; +}; + +NBL_MAIN_FUNC(JpegLoaderApp) \ No newline at end of file diff --git a/68_JpegLoading/pipeline.groovy b/68_JpegLoading/pipeline.groovy new file mode 100644 index 000000000..ece6ffebc --- /dev/null +++ b/68_JpegLoading/pipeline.groovy @@ -0,0 +1,50 @@ +import org.DevshGraphicsProgramming.Agent +import org.DevshGraphicsProgramming.BuilderInfo +import org.DevshGraphicsProgramming.IBuilder + +class CJpegLoading extends IBuilder +{ + public CJpegLoading(Agent _agent, _info) + { + super(_agent, _info) + } + + @Override + public boolean prepare(Map axisMapping) + { + return true + } + + @Override + public boolean build(Map axisMapping) + { + IBuilder.CONFIGURATION config = axisMapping.get("CONFIGURATION") + IBuilder.BUILD_TYPE buildType = axisMapping.get("BUILD_TYPE") + + def nameOfBuildDirectory = getNameOfBuildDirectory(buildType) + def nameOfConfig = getNameOfConfig(config) + + agent.execute("cmake --build ${info.rootProjectPath}/${nameOfBuildDirectory}/${info.targetProjectPathRelativeToRoot} --target ${info.targetBaseName} --config ${nameOfConfig} -j12 -v") + + return true + } + + @Override + public boolean test(Map axisMapping) + { + return true + } + + @Override + public boolean install(Map axisMapping) + { + return true + } +} + +def create(Agent _agent, _info) +{ + return new CJpegLoading(_agent, _info) +} + +return this \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bf3eb696..e1195dd39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ if(NBL_BUILD_EXAMPLES) add_subdirectory(0_ImportanceSamplingEnvMaps EXCLUDE_FROM_ALL) #TODO: integrate back into 42 add_subdirectory(67_RayQueryGeometry EXCLUDE_FROM_ALL) + add_subdirectory(68_JpegLoading EXCLUDE_FROM_ALL) NBL_HOOK_COMMON_API("${NBL_COMMON_API_TARGETS}") endif() \ No newline at end of file