diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/CMakeLists.txt b/RenderingToolkit/GettingStarted/04_oidn_gsg/CMakeLists.txt new file mode 100644 index 0000000000..3ccc9186c9 --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.16) +project(OIDN_GSG LANGUAGES C CXX) + +set(ONEAPI_ROOT "") +if(DEFINED ENV{ONEAPI_ROOT}) + set(ONEAPI_ROOT "$ENV{ONEAPI_ROOT}") + message(STATUS "ONEAPI_ROOT FROM ENVIRONMENT: ${ONEAPI_ROOT}") +else() + if(WIN32) + set(ONEAPI_ROOT "C:/Program Files (x86)/Intel/oneAPI") + else() + set(ONEAPI_ROOT /opt/intel/oneapi) + endif() + message(STATUS "ONEAPI_ROOT DEFAULT: ${ONEAPI_ROOT}") +endif(DEFINED ENV{ONEAPI_ROOT}) +set(OIDN_ROOT ${ONEAPI_ROOT}/oidn/latest) +set(OIDN_INCLUDE_DIR ${OIDN_ROOT}/include) +set(OIDN_LIB_DIR ${OIDN_ROOT}/lib) + +find_package(OpenImageDenoise REQUIRED PATHS ${ONEAPI_ROOT}) +find_package(TBB REQUIRED PATHS ${ONEAPI_ROOT}) + +if(MSVC) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif(MSVC) + +add_subdirectory(src/common) +add_subdirectory(src/apps/utils) + +include_directories(${OIDN_INCLUDE_DIR} ${OIDN_ROOT} ${OIDN_GSG_SOURCE_DIR}/src) +link_directories(${OIDN_ROOT}/lib) + +add_executable(oidnDenoise src/apps/oidnDenoise.cpp) +target_link_libraries(oidnDenoise PRIVATE common utils OpenImageDenoise) + +install(TARGETS oidnDenoise + DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/LICENSE.txt b/RenderingToolkit/GettingStarted/04_oidn_gsg/LICENSE.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/README.md b/RenderingToolkit/GettingStarted/04_oidn_gsg/README.md new file mode 100644 index 0000000000..5c7107185c --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/README.md @@ -0,0 +1,140 @@ +# Getting Started Sample for Intel oneAPI Rendering Toolkit: Intel Open Image Denoise + + +Intel Open Image Denoise is an open source library of high-performance, high-quality, denoising filters for images rendered with ray tracing. Significantly reduce rendering times in ray tracing based rendering applications. + +| Minimum Requirements | Description +|:--- |:--- +| OS | Linux* Ubuntu* 18.04, CentOS 8 (or compatible); Windows 10; MacOS 10.15+ +| Hardware | Intel 64 Penryn or newer with SSE4.1 extensions, ARM64 with NEON extensions +| Compiler Toolchain | Windows* OS: MSVS 2019 installed with Windows* SDK and CMake*; Other platforms: C++11 compiler, a C99 compiler (ex: gcc/c++/clang), and CMake* +| Libraries | Install Intel oneAPI Rendering Toolkit including OSPRay, Embree, Open Volume Kernel Library, Intel Open Image Denoise +| Image Display Tool | A .ppm filetype viewer. Ex: [ImageMagick](https://www.imagemagick.org) +| Image Conversion Tool | A converter for .ppm, .pfm, and endian conversions. Ex: [ImageMagick](https://www.imagemagick.org) + +| Optimized Requirements | Description +| :--- | :--- +| Hardware | Intel 64 Skylake or newer with AVX512 extentions, ARM64 with NEON extensions + +| Objective | Description +|:--- |:--- +| What you will learn | How to build and run a basic rendering program using the Open Image Denoise API from the Render Kit. +| Time to complete | 5 minutes + + +## Purpose + +This getting started sample program, `oidnDenoise`, denoises a raytraced image. The output is written to disk as a .pfm image file. + + +## Key Implementation Details + +- The program input is a noisy image. In this example, the `accumulatedFrameCpp` image is used for input. Recall, this image was originally generated from the Intel OSPRay getting started sample, `ospTutorial`. +- The program writes a denoised .pfm image file to disk. +- Of course, oidnDenoise can denoise other, user-provided noisy input images. Along with the input image, the program can take in albedo and normal buffers corresponding to the same pixels of the input image. Inclusion of such auxialiary feature images can significantly improve denoising quality. See +- The Intel OSPRay Studio showcase application demonstrates in-source denoising with the Intel OSPRay library. The noisy image buffer and auxiliary buffers are readily emitted from the OSPRay API. All buffers are fed through the denoiser for a higher quality interactive experience. + +## License + +This code sample is licensed under the Apache 2.0 license. See +[LICENSE.txt](LICENSE.txt) for details. + +Third party program Licenses can be found here: [third-party-programs.txt](https://github.com/oneapi-src/oneAPI-samples/blob/master/third-party-programs.txt) + +## Build and Run + +First, build and run the sample Intel OSPRay getting started sample, `ospTutorial`, to generate input. Find it in the [01_ospray_gsg](../01_ospray_gsg) folder of this samples repository. + +### Windows OS: + + +Run a new **x64 Native Tools Command Prompt for MSVS 2019** + +``` +call \setvars.bat +cd \RenderingToolkit\GettingStarted\04_oidn_gsg +mkdir build +cd build +cmake .. +cmake --build . --config Release +cd Release +``` + +Convert the accumulatedFrameCpp.ppm image to LSB data ordering and .pfm format. Example conversion with ImageMagick convert: + +``` +\magick.exe convert \01_ospray_gsg\build\Release\accumulatedFrameCpp.ppm -endian LSB PFM:accumulatedFrameCpp.pfm +``` + +Denoise the image: + +``` +oidnDenoise.exe -hdr accumulatedFrameCpp.pfm -o denoised.pfm +``` + +Review the output for visual comparison to the input. Example view with ImageMagick display: + +``` +\imdisplay.exe denoised.pfm +``` + +### Linux OS: + +Start a new Terminal session +``` +source /setvars.sh +cd /RenderingToolkit/GettingStarted/04_oidn_gsg +mkdir build +cd build +cmake .. +cmake --build . +``` + +Convert the accumulatedFrameCpp.ppm image to LSB data ordering and .pfm format. Example conversion with ImageMagick convert: +``` +/convert-im6 /01_ospray_gsg/build/accumulatedFrameCpp.ppm -endian LSB PFM:accumulatedFrameCpp.pfm +``` + +Denoise the image: + +``` +./oidnDenoise -hdr accumulatedFrameCpp.pfm -o denoised.pfm +``` + +Review the output for visual comparison to the input. Example view with ImageMagick display: + +``` +/display-im6 denoised.pfm +``` + + + +### MacOS: + +Start a new Terminal session + +``` +source /setvars.sh +cd /RenderingToolkit/GettingStarted/04_oidn_gsg +mkdir build +cd build +cmake .. +cmake --build . +``` + +Convert the accumulatedFrameCpp.ppm image to LSB data ordering and .pfm format. Example conversion with ImageMagick convert: +``` +/magick convert /01_ospray_gsg/build/accumulatedFrameCpp.ppm -endian LSB PFM:accumulatedFrameCpp.pfm +``` + +Denoise the image: + +``` +./oidnDenoise -hdr accumulatedFrameCpp.pfm -o denoised.pfm +``` + +Review the output for visual comparison to the input. Example view with ImageMagick display: + +``` +/imdisplay denoised.pfm +``` diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/accumulatedFrameCpp.pfm b/RenderingToolkit/GettingStarted/04_oidn_gsg/accumulatedFrameCpp.pfm new file mode 100644 index 0000000000..0cf85bf88b Binary files /dev/null and b/RenderingToolkit/GettingStarted/04_oidn_gsg/accumulatedFrameCpp.pfm differ diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/sample.json b/RenderingToolkit/GettingStarted/04_oidn_gsg/sample.json new file mode 100644 index 0000000000..7add0c29d2 --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/sample.json @@ -0,0 +1,56 @@ +{ + "guid": "41F82C06-A9FA-4521-B87A-8F7304CB6631", + "name": "Intel Open Image Denoise Getting Started", + "categories": ["Toolkit/oneAPI Libraries/Open Image Denoise"], + "description": "This introductory 'hello rendering toolkit' sample program demonstrates how to denoise a raytraced image with Intel Open Image Denoise", + "builder": ["cli"], + "languages": [{"cpp":{}}], + "dependencies": ["tbb","rkcommon"], + "os":["linux", "windows", "darwin"], + "targetDevice": ["CPU"], + "ciTests": { + "linux": [ + { + "id": "Intel_OIDN_oidnDenoise_lin", + "steps": [ + "mkdir build", + "cd build", + "cmake ..", + "cmake --build . ", + "cp ../accumulatedFrameCpp.pfm .", + "./oidnDenoise -hdr accumulatedFrameCpp.pfm -o denoised.pfm" + ] + } + ], + "windows":[ + { + "id": "Intel_OIDN_oidnDenoise_win", + "steps":[ + "mkdir build", + "cd build", + "cmake ..", + "cmake --build . --config Release", + "cd Release", + "copy ..\\..\\accumulatedFrameCpp.pfm .", + ".\\oidnDenoise.exe -hdr accumulatedFrameCpp.pfm -o denoised.pfm" + ] + + } + ], + "darwin": [ + { + "id": "Intel_OIDN_oidnDenoise_mac", + "steps": [ + "mkdir build", + "cd build", + "cmake ..", + "cmake --build . ", + "cp ../accumulatedFrameCpp.pfm .", + "export DYLD_LIBRARY_PATH=${ONEAPI_ROOT}/openvkl/latest/lib:${ONEAPI_ROOT}/rkcommon/latest/lib:${ONEAPI_ROOT}/tbb/latest/lib:${ONEAPI_ROOT}/embree/latest/lib:${ONEAPI_ROOT}/oidn/latest/lib && ./oidnDenoise -hdr accumulatedFrameCpp.pfm -o denoised.pfm" + ] + } + ] + + + } +} diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/oidnDenoise.cpp b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/oidnDenoise.cpp new file mode 100644 index 0000000000..66b0cabffa --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/oidnDenoise.cpp @@ -0,0 +1,350 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include +#include +#include +#include +#include + +#ifdef VTUNE +#include +#endif + +#include + +#include "apps/utils/arg_parser.h" +#include "apps/utils/image_io.h" +#include "common/timer.h" + +OIDN_NAMESPACE_USING +using namespace oidn; + +void printUsage() { + std::cout << "Intel(R) Open Image Denoise" << std::endl; + std::cout << "usage: oidnDenoise [-f/--filter RT|RTLightmap]" << std::endl + << " [--hdr color.pfm] [--ldr color.pfm] " + "[--srgb] [--dir directional.pfm]" + << std::endl + << " [--alb albedo.pfm] [--nrm normal.pfm] " + "[--clean_aux]" + << std::endl + << " [--is/--input_scale value]" << std::endl + << " [-o/--output output.pfm] [-r/--ref " + "reference_output.pfm]" + << std::endl + << " [-w/--weights weights.tza]" << std::endl + << " [--threads n] [--affinity 0|1] [--maxmem " + "MB] [--inplace]" + << std::endl + << " [--bench ntimes] [-v/--verbose 0-3]" + << std::endl + << " [-h/--help]" << std::endl; +} + +void errorCallback(void* userPtr, Error error, const char* message) { + throw std::runtime_error(message); +} + +volatile bool isCancelled = false; + +void signalHandler(int signal) { isCancelled = true; } + +bool progressCallback(void* userPtr, double n) { + if (isCancelled) { + std::cout << std::endl; + return false; + } + std::cout << "\rDenoising " << int(n * 100.) << "%" << std::flush; + return true; +} + +std::vector loadFile(const std::string& filename) { + std::ifstream file(filename, std::ios::binary); + if (file.fail()) throw std::runtime_error("cannot open file: " + filename); + file.seekg(0, file.end); + const size_t size = file.tellg(); + file.seekg(0, file.beg); + std::vector buffer(size); + file.read(buffer.data(), size); + if (file.fail()) throw std::runtime_error("error reading from file"); + return buffer; +} + +int main(int argc, char* argv[]) { + std::string filterType = "RT"; + std::string colorFilename, albedoFilename, normalFilename; + std::string outputFilename, refFilename; + std::string weightsFilename; + bool hdr = false; + bool srgb = false; + bool directional = false; + float inputScale = std::numeric_limits::quiet_NaN(); + bool cleanAux = false; + int numBenchmarkRuns = 0; + int numThreads = -1; + int setAffinity = -1; + int maxMemoryMB = -1; + bool inplace = false; + int verbose = -1; + + // Parse the arguments + if (argc == 1) { + printUsage(); + return 1; + } + + try { + ArgParser args(argc, argv); + while (args.hasNext()) { + std::string opt = args.getNextOpt(); + if (opt == "f" || opt == "filter") + filterType = args.getNextValue(); + else if (opt == "hdr") { + colorFilename = args.getNextValue(); + hdr = true; + } else if (opt == "ldr") { + colorFilename = args.getNextValue(); + hdr = false; + } else if (opt == "srgb") + srgb = true; + else if (opt == "dir") { + colorFilename = args.getNextValue(); + directional = true; + } else if (opt == "alb" || opt == "albedo") + albedoFilename = args.getNextValue(); + else if (opt == "nrm" || opt == "normal") + normalFilename = args.getNextValue(); + else if (opt == "o" || opt == "out" || opt == "output") + outputFilename = args.getNextValue(); + else if (opt == "r" || opt == "ref" || opt == "reference") + refFilename = args.getNextValue(); + else if (opt == "is" || opt == "input_scale" || opt == "inputScale" || + opt == "inputscale") + inputScale = args.getNextValueFloat(); + else if (opt == "clean_aux" || opt == "cleanAux") + cleanAux = true; + else if (opt == "w" || opt == "weights") + weightsFilename = args.getNextValue(); + else if (opt == "bench" || opt == "benchmark") + numBenchmarkRuns = std::max(args.getNextValueInt(), 0); + else if (opt == "threads") + numThreads = args.getNextValueInt(); + else if (opt == "affinity") + setAffinity = args.getNextValueInt(); + else if (opt == "maxmem" || opt == "maxMemoryMB") + maxMemoryMB = args.getNextValueInt(); + else if (opt == "inplace") + inplace = true; + else if (opt == "v" || opt == "verbose") + verbose = args.getNextValueInt(); + else if (opt == "h" || opt == "help") { + printUsage(); + return 1; + } else + throw std::invalid_argument("invalid argument"); + } + + if (!refFilename.empty() && numBenchmarkRuns > 0) + throw std::runtime_error( + "reference and benchmark modes cannot be enabled at the same time"); + +#if defined(OIDN_X64) + // Set MXCSR flags + if (!refFilename.empty()) { + // In reference mode we have to disable the FTZ and DAZ flags to get + // accurate results + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF); + } else { + // Enable the FTZ and DAZ flags to maximize performance + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); + } +#endif + + // Load the input image + std::shared_ptr input, ref; + std::shared_ptr color, albedo, normal; + + std::cout << "Loading input" << std::endl; + + if (!albedoFilename.empty()) + input = albedo = loadImage(albedoFilename, 3, false); + + if (!normalFilename.empty()) input = normal = loadImage(normalFilename, 3); + + if (!colorFilename.empty()) + input = color = loadImage(colorFilename, 3, srgb); + + if (!input) throw std::runtime_error("no input image specified"); + + if (!refFilename.empty()) { + ref = loadImage(refFilename, 3, srgb); + if (ref->dims() != input->dims()) + throw std::runtime_error("invalid reference output image"); + } + + const int width = input->width; + const int height = input->height; + std::cout << "Resolution: " << width << "x" << height << std::endl; + + // Initialize the output image + std::shared_ptr output; + if (inplace) + output = input; + else + output = std::make_shared(width, height, 3); + + // Load the filter weights if specified + std::vector weights; + if (!weightsFilename.empty()) { + std::cout << "Loading filter weights" << std::endl; + weights = loadFile(weightsFilename); + } + + // Initialize the denoising filter + std::cout << "Initializing" << std::endl; + Timer timer; + + DeviceRef device = newDevice(); + + const char* errorMessage; + if (device.getError(errorMessage) != Error::None) + throw std::runtime_error(errorMessage); + device.setErrorFunction(errorCallback); + + if (numThreads > 0) device.set("numThreads", numThreads); + if (setAffinity >= 0) device.set("setAffinity", bool(setAffinity)); + if (verbose >= 0) device.set("verbose", verbose); + device.commit(); + + const double deviceInitTime = timer.query(); + timer.reset(); + + FilterRef filter = device.newFilter(filterType.c_str()); + + if (color) + filter.setImage("color", color->data(), Format::Float3, color->width, + color->height); + if (albedo) + filter.setImage("albedo", albedo->data(), Format::Float3, albedo->width, + albedo->height); + if (normal) + filter.setImage("normal", normal->data(), Format::Float3, normal->width, + normal->height); + + filter.setImage("output", output->data(), Format::Float3, output->width, + output->height); + + if (filterType == "RT") { + if (hdr) filter.set("hdr", true); + if (srgb) filter.set("srgb", true); + } else if (filterType == "RTLightmap") { + if (directional) filter.set("directional", true); + } + + if (std::isfinite(inputScale)) filter.set("inputScale", inputScale); + + if (cleanAux) filter.set("cleanAux", cleanAux); + + if (maxMemoryMB >= 0) filter.set("maxMemoryMB", maxMemoryMB); + + if (!weights.empty()) + filter.setData("weights", weights.data(), weights.size()); + + const bool showProgress = !ref && numBenchmarkRuns == 0 && verbose <= 2; + if (showProgress) { + filter.setProgressMonitorFunction(progressCallback); + signal(SIGINT, signalHandler); + } + + filter.commit(); + + const double filterInitTime = timer.query(); + + const int versionMajor = device.get("versionMajor"); + const int versionMinor = device.get("versionMinor"); + const int versionPatch = device.get("versionPatch"); + + std::cout << " device=CPU" + << ", version=" << versionMajor << "." << versionMinor << "." + << versionPatch << ", msec=" << (1000. * deviceInitTime) + << std::endl + << " filter=" << filterType + << ", msec=" << (1000. * filterInitTime) << std::endl; + + // Denoise the image + if (!showProgress) std::cout << "Denoising" << std::endl; + timer.reset(); + + filter.execute(); + + const double denoiseTime = timer.query(); + if (showProgress) std::cout << std::endl; + if (verbose <= 2) + std::cout << " msec=" << (1000. * denoiseTime) << std::endl; + + if (showProgress) { + filter.setProgressMonitorFunction(nullptr); + signal(SIGINT, SIG_DFL); + } + + if (!outputFilename.empty()) { + // Save output image + std::cout << "Saving output" << std::endl; + saveImage(outputFilename, *output, srgb); + } + + if (ref) { + // Verify the output values + std::cout << "Verifying output" << std::endl; + + size_t numErrors; + float maxError; + std::tie(numErrors, maxError) = compareImage(*output, *ref, 1e-4); + + std::cout << " values=" << output->size() << ", errors=" << numErrors + << ", maxerror=" << maxError << std::endl; + + if (numErrors > 0) { + // Save debug images + std::cout << "Saving debug images" << std::endl; + saveImage("denoise_in.ppm", *input, srgb); + saveImage("denoise_out.ppm", *output, srgb); + saveImage("denoise_ref.ppm", *ref, srgb); + + throw std::runtime_error("output does not match the reference"); + } + } + + if (numBenchmarkRuns > 0) { + // Benchmark loop +#ifdef VTUNE + __itt_resume(); +#endif + + std::cout << "Benchmarking: " + << "ntimes=" << numBenchmarkRuns << std::endl; + timer.reset(); + + for (int i = 0; i < numBenchmarkRuns; ++i) filter.execute(); + + const double totalTime = timer.query(); + std::cout << " sec=" << totalTime + << ", msec/image=" << (1000. * totalTime / numBenchmarkRuns) + << std::endl; + +#ifdef VTUNE + __itt_pause(); +#endif + } + } catch (std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + return 0; +} diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/CMakeLists.txt b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/CMakeLists.txt new file mode 100644 index 0000000000..f870cec05e --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(utils STATIC + image_io.h + image_io.cpp +) + +target_link_libraries(utils PUBLIC common) diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/arg_parser.h b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/arg_parser.h new file mode 100644 index 0000000000..5114856f91 --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/arg_parser.h @@ -0,0 +1,56 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include +#include + +namespace oidn { + +// Command-line argument parser +class ArgParser { + private: + int argc; + char** argv; + int pos; + + public: + ArgParser(int argc, char* argv[]) : argc(argc), argv(argv), pos(1) {} + + bool hasNext() const { return pos < argc; } + + std::string getNext() { + if (pos < argc) + return argv[pos++]; + else + throw std::invalid_argument("argument expected"); + } + + std::string getNextOpt() { + std::string str = getNext(); + if (str.empty() || str[0] != '-') + throw std::invalid_argument("option expected"); + return str.substr(str.find_first_not_of("-")); + } + + std::string getNextValue() { + std::string str = getNext(); + if (!str.empty() && str[0] == '-') + throw std::invalid_argument("value expected"); + return str; + } + + int getNextValueInt() { + std::string str = getNextValue(); + return atoi(str.c_str()); + } + + float getNextValueFloat() { + std::string str = getNextValue(); + return atof(str.c_str()); + } +}; + +} // namespace oidn diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/image_io.cpp b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/image_io.cpp new file mode 100644 index 0000000000..ef2216890a --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/image_io.cpp @@ -0,0 +1,281 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "image_io.h" + +#include +#include +#include + +#if defined(OIDN_USE_OPENIMAGEIO) +#include +#endif + +namespace oidn { + +namespace { +inline float srgbForward(float y) { + return (y <= 0.0031308f) ? (12.92f * y) + : (1.055f * std::pow(y, 1.f / 2.4f) - 0.055f); +} + +inline float srgbInverse(float x) { + return (x <= 0.04045f) ? (x / 12.92f) : std::pow((x + 0.055f) / 1.055f, 2.4f); +} + +void srgbForward(ImageBuffer& image) { + for (size_t i = 0; i < image.size(); ++i) image[i] = srgbForward(image[i]); +} + +void srgbInverse(ImageBuffer& image) { + for (size_t i = 0; i < image.size(); ++i) image[i] = srgbInverse(image[i]); +} + +std::string getExtension(const std::string& filename) { + const size_t pos = filename.find_last_of('.'); + if (pos == std::string::npos) + return ""; // no extension + else { + std::string ext = filename.substr(pos + 1); + for (auto& c : ext) c = tolower(c); + return ext; + } +} + +std::shared_ptr loadImagePFM(const std::string& filename, + int numChannels) { + // Open the file + std::ifstream file(filename, std::ios::binary); + if (file.fail()) + throw std::runtime_error("cannot open image file: " + filename); + + // Read the header + std::string id; + file >> id; + int C; + if (id == "PF") + C = 3; + else if (id == "Pf") + C = 1; + else + throw std::runtime_error("invalid PFM image"); + + if (numChannels == 0) + numChannels = C; + else if (C < numChannels) + throw std::runtime_error("not enough image channnels"); + + int H, W; + file >> W >> H; + + float scale; + file >> scale; + + file.get(); // skip newline + + if (file.fail()) throw std::runtime_error("invalid PFM image"); + + if (scale >= 0.f) + throw std::runtime_error("big-endian PFM images are not supported"); + scale = fabs(scale); + + // Read the pixels + auto image = std::make_shared(W, H, numChannels); + + for (int h = 0; h < H; ++h) { + for (int w = 0; w < W; ++w) { + for (int c = 0; c < C; ++c) { + float x; + file.read((char*)&x, sizeof(float)); + if (c < numChannels) + (*image)[(size_t(H - 1 - h) * W + w) * numChannels + c] = x * scale; + } + } + } + + if (file.fail()) throw std::runtime_error("invalid PFM image"); + + return image; +} + +void saveImagePFM(const std::string& filename, const ImageBuffer& image) { + const int H = image.height; + const int W = image.width; + const int C = image.numChannels; + + // Open the file + std::ofstream file(filename, std::ios::binary); + if (file.fail()) + throw std::runtime_error("cannot open image file: " + filename); + + // Write the header + file << "PF" << std::endl; + file << W << " " << H << std::endl; + file << "-1.0" << std::endl; + + // Write the pixels + for (int h = 0; h < H; ++h) { + for (int w = 0; w < W; ++w) { + for (int c = 0; c < 3; ++c) { + const float x = image[(size_t(H - 1 - h) * W + w) * C + c]; + file.write((char*)&x, sizeof(float)); + } + } + } +} + +void saveImagePPM(const std::string& filename, const ImageBuffer& image) { + if (image.numChannels != 3) + throw std::invalid_argument("image must have 3 channels"); + const int H = image.height; + const int W = image.width; + const int C = image.numChannels; + + // Open the file + std::ofstream file(filename, std::ios::binary); + if (file.fail()) + throw std::runtime_error("cannot open image file: " + filename); + + // Write the header + file << "P6" << std::endl; + file << W << " " << H << std::endl; + file << "255" << std::endl; + + // Write the pixels + for (int i = 0; i < W * H; ++i) { + for (int c = 0; c < 3; ++c) { + const float x = image[i * C + c]; + const int ch = std::min(std::max(int(x * 255.f), 0), 255); + file.put(char(ch)); + } + } +} +} // namespace + +#ifdef OIDN_USE_OPENIMAGEIO +std::shared_ptr loadImageOIIO(const std::string& filename, + int numChannels) { + auto in = OIIO::ImageInput::open(filename); + if (!in) throw std::runtime_error("cannot open image file: " + filename); + + const OIIO::ImageSpec& spec = in->spec(); + if (numChannels == 0) + numChannels = spec.nchannels; + else if (spec.nchannels < numChannels) + throw std::runtime_error("not enough image channels"); + auto image = + std::make_shared(spec.width, spec.height, numChannels); + if (!in->read_image(0, 0, 0, numChannels, OIIO::TypeDesc::FLOAT, + image->data())) + throw std::runtime_error("failed to read image data"); + in->close(); + +#if OIIO_VERSION < 10903 + OIIO::ImageInput::destroy(in); +#endif + return image; +} + +void saveImageOIIO(const std::string& filename, const ImageBuffer& image) { + auto out = OIIO::ImageOutput::create(filename); + if (!out) + throw std::runtime_error("cannot save unsupported image file format: " + + filename); + + OIIO::ImageSpec spec(image.width, image.height, image.numChannels, + OIIO::TypeDesc::FLOAT); + + if (!out->open(filename, spec)) + throw std::runtime_error("cannot create image file: " + filename); + if (!out->write_image(OIIO::TypeDesc::FLOAT, image.data())) + throw std::runtime_error("failed to write image data"); + out->close(); + +#if OIIO_VERSION < 10903 + OIIO::ImageOutput::destroy(out); +#endif +} +#endif + +std::shared_ptr loadImage(const std::string& filename, + int numChannels) { + const std::string ext = getExtension(filename); + std::shared_ptr image; + + if (ext == "pfm") + image = loadImagePFM(filename, numChannels); + else +#if OIDN_USE_OPENIMAGEIO + image = loadImageOIIO(filename, numChannels); +#else + throw std::runtime_error("cannot load unsupported image file format: " + + filename); +#endif + + return image; +} + +void saveImage(const std::string& filename, const ImageBuffer& image) { + const std::string ext = getExtension(filename); + if (ext == "pfm") + saveImagePFM(filename, image); + else if (ext == "ppm") + saveImagePPM(filename, image); + else +#if OIDN_USE_OPENIMAGEIO + saveImageOIIO(filename, image); +#else + throw std::runtime_error("cannot write unsupported image file format: " + + filename); +#endif +} + +bool isSrgbImage(const std::string& filename) { + const std::string ext = getExtension(filename); + return ext != "pfm" && ext != "exr" && ext != "hdr"; +} + +std::shared_ptr loadImage(const std::string& filename, + int numChannels, bool srgb) { + auto image = loadImage(filename, numChannels); + if (!srgb && isSrgbImage(filename)) srgbInverse(*image); + return image; +} + +void saveImage(const std::string& filename, const ImageBuffer& image, + bool srgb) { + if (!srgb && isSrgbImage(filename)) { + ImageBuffer newImage = image; + srgbForward(newImage); + saveImage(filename, newImage); + } else { + saveImage(filename, image); + } +} + +std::tuple compareImage(const ImageBuffer& image, + const ImageBuffer& ref, + float threshold) { + assert(ref.dims() == image.dims()); + + size_t numErrors = 0; + float maxError = 0; + + for (size_t i = 0; i < image.size(); ++i) { + const float actual = image[i]; + const float expect = ref[i]; + + float error = std::abs(expect - actual); + if (expect != 0) error = std::min(error, error / expect); + + maxError = std::max(maxError, error); + if (error > threshold) { + // std::cerr << "i=" << i << " expect=" << expect << " actual=" << actual; + ++numErrors; + } + } + + return std::make_tuple(numErrors, maxError); +} + +} // namespace oidn diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/image_io.h b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/image_io.h new file mode 100644 index 0000000000..894de39e9c --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/apps/utils/image_io.h @@ -0,0 +1,61 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include +#include +#include +#include + +namespace oidn { + +struct ImageBuffer { + std::vector buffer; + int width; + int height; + int numChannels; + + ImageBuffer() : width(0), height(0), numChannels(0) {} + + ImageBuffer(int width, int height, int numChannels) + : buffer(size_t(width) * height * numChannels), + width(width), + height(height), + numChannels(numChannels) {} + + operator bool() const { return data() != nullptr; } + + const float& operator[](size_t i) const { return buffer[i]; } + float& operator[](size_t i) { return buffer[i]; } + + const float* data() const { return buffer.data(); } + float* data() { return buffer.data(); } + + size_t size() const { return buffer.size(); } + std::array dims() const { return {width, height, numChannels}; } +}; + +// Loads an image with an optionally specified number of channels (loads all +// channels by default) +std::shared_ptr loadImage(const std::string& filename, + int numChannels = 0); + +// Loads an image with/without sRGB to linear conversion +std::shared_ptr loadImage(const std::string& filename, + int numChannels, bool srgb); + +// Saves an image +void saveImage(const std::string& filename, const ImageBuffer& image); + +// Saves an image with/without linear to sRGB conversion +void saveImage(const std::string& filename, const ImageBuffer& image, + bool srgb); + +// Compares an image to a reference image and returns the number of errors +// and the maximum error value +std::tuple compareImage(const ImageBuffer& image, + const ImageBuffer& ref, float threshold); + +} // namespace oidn diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/CMakeLists.txt b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/CMakeLists.txt new file mode 100644 index 0000000000..358646e9a9 --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/CMakeLists.txt @@ -0,0 +1,29 @@ +set(ONEAPI_ROOT "") +if($ENV{ONEAPI_ROOT}) + set(ONEAPI_ROOT $ENV{ONEAPI_ROOT}) +else() + if(WIN32) + set(ONEAPI_ROOT "C:/Program Files (x86)/Intel/oneAPI") + else() + set(ONEAPI_ROOT /opt/intel/oneapi) + endif() +endif($ENV{ONEAPI_ROOT}) +set(OIDN_ROOT ${ONEAPI_ROOT}/oidn/latest) +set(OIDN_INCLUDE_DIR ${OIDN_ROOT}/include) + +add_library(common STATIC + platform.h + platform.cpp + timer.h +) + +target_include_directories(common + PUBLIC + ${OIDN_ROOT} +) + +#target_link_libraries(common +# PUBLIC +# ${CMAKE_THREAD_LIBS_INIT} +# TBB +#) diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/platform.cpp b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/platform.cpp new file mode 100644 index 0000000000..f027da8ac3 --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/platform.cpp @@ -0,0 +1,105 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "platform.h" + +namespace oidn { + +// --------------------------------------------------------------------------- +// Common functions +// --------------------------------------------------------------------------- + +void* alignedMalloc(size_t size, size_t alignment) { + if (size == 0) return nullptr; + + assert((alignment & (alignment - 1)) == 0); +#if defined(OIDN_X64) + void* ptr = _mm_malloc(size, alignment); +#else + void* ptr; + if (posix_memalign(&ptr, max(alignment, sizeof(void*)), size) != 0) + ptr = nullptr; +#endif + + if (ptr == nullptr) throw std::bad_alloc(); + + return ptr; +} + +void alignedFree(void* ptr) { + if (ptr) +#if defined(OIDN_X64) + _mm_free(ptr); +#else + free(ptr); +#endif +} + +// --------------------------------------------------------------------------- +// System information +// --------------------------------------------------------------------------- + +std::string getPlatformName() { + std::string name; + +#if defined(__linux__) + name = "Linux"; +#elif defined(__FreeBSD__) + name = "FreeBSD"; +#elif defined(__CYGWIN__) + name = "Cygwin"; +#elif defined(_WIN32) + name = "Windows"; +#elif defined(__APPLE__) + name = "macOS"; +#elif defined(__unix__) + name = "Unix"; +#else + return "Unknown"; +#endif + +#if defined(__x86_64__) || defined(_M_X64) || defined(__ia64__) || \ + defined(__aarch64__) + name += " (64-bit)"; +#else + name += " (32-bit)"; +#endif + + return name; +} + +std::string getCompilerName() { +#if defined(__INTEL_COMPILER) + int major = __INTEL_COMPILER / 100 % 100; + int minor = __INTEL_COMPILER % 100 / 10; + std::string version = "Intel Compiler "; + version += toString(major); + version += "." + toString(minor); +#if defined(__INTEL_COMPILER_UPDATE) + version += "." + toString(__INTEL_COMPILER_UPDATE); +#endif + return version; +#elif defined(__clang__) + return "Clang " __clang_version__; +#elif defined(__GNUC__) + return "GCC " __VERSION__; +#elif defined(_MSC_VER) + std::string version = toString(_MSC_FULL_VER); + version.insert(4, "."); + version.insert(9, "."); + version.insert(2, "."); + return "Visual C++ Compiler " + version; +#else + return "Unknown"; +#endif +} + +std::string getBuildName() { +#if defined(NDEBUG) + return "Release"; +#else + return "Debug"; +#endif +} + +} // namespace oidn diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/platform.h b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/platform.h new file mode 100644 index 0000000000..6d959c3540 --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/platform.h @@ -0,0 +1,169 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- + +#if defined(__x86_64__) || defined(_M_X64) +#define OIDN_X64 +#elif defined(__aarch64__) +#define OIDN_ARM64 +#endif + +#if defined(_WIN32) +// Windows +#if !defined(__noinline) +#define __noinline __declspec(noinline) +#endif +#else +// Unix +#if !defined(__forceinline) +#define __forceinline inline __attribute__((always_inline)) +#endif +#if !defined(__noinline) +#define __noinline __attribute__((noinline)) +#endif +#endif + +#ifndef UNUSED +#define UNUSED(x) ((void)x) +#endif +#ifndef MAYBE_UNUSED +#define MAYBE_UNUSED(x) UNUSED(x) +#endif + +// --------------------------------------------------------------------------- +// Includes +// --------------------------------------------------------------------------- + +#if defined(_WIN32) +#if !defined(WIN32_LEAN_AND_MEAN) +#define WIN32_LEAN_AND_MEAN +#endif +#if !defined(NOMINMAX) +#define NOMINMAX +#endif +#include +#elif defined(__APPLE__) +#include +#endif + +#if defined(OIDN_X64) +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "include/OpenImageDenoise/oidn.hpp" + +namespace oidn { + +// Introduce all names from the API namespace +OIDN_NAMESPACE_USING + +// --------------------------------------------------------------------------- +// Error handling and debugging +// --------------------------------------------------------------------------- + +struct Verbose { + int verbose; + + Verbose(int v = 0) : verbose(v) {} + __forceinline bool isVerbose(int v = 1) const { return v <= verbose; } +}; + +#define OIDN_WARNING(message) \ + { \ + if (isVerbose()) std::cerr << "Warning: " << message << std::endl; \ + } +#define OIDN_FATAL(message) throw std::runtime_error(message); + +// --------------------------------------------------------------------------- +// Common functions +// --------------------------------------------------------------------------- + +using std::max; +using std::min; + +template +__forceinline T clamp(const T& value, const T& minValue, const T& maxValue) { + return min(max(value, minValue), maxValue); +} + +constexpr size_t memoryAlignment = 128; + +void* alignedMalloc(size_t size, size_t alignment = memoryAlignment); +void alignedFree(void* ptr); + +template +inline std::string toString(const T& a) { + std::stringstream sm; + sm << a; + return sm.str(); +} + +template +inline T fromString(const std::string& str) { + std::stringstream sm(str); + T a{}; + sm >> a; + return a; +} + +template <> +inline std::string fromString(const std::string& str) { + return str; +} + +#if defined(__APPLE__) +template +inline bool getSysctl(const char* name, T& value) { + int64_t result = 0; + size_t size = sizeof(result); + + if (sysctlbyname(name, &result, &size, nullptr, 0) != 0) return false; + + value = T(result); + return true; +} +#endif + +template +inline bool getEnvVar(const std::string& name, T& value) { + auto* str = getenv(name.c_str()); + bool found = (str != nullptr); + if (found) value = fromString(str); + return found; +} + +inline bool isEnvVar(const std::string& name) { + auto* str = getenv(name.c_str()); + return (str != nullptr); +} + +// --------------------------------------------------------------------------- +// System information +// --------------------------------------------------------------------------- + +std::string getPlatformName(); +std::string getCompilerName(); +std::string getBuildName(); + +} // namespace oidn diff --git a/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/timer.h b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/timer.h new file mode 100644 index 0000000000..c3314b6cb0 --- /dev/null +++ b/RenderingToolkit/GettingStarted/04_oidn_gsg/src/common/timer.h @@ -0,0 +1,31 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "platform.h" + +namespace oidn { + +class Timer { + private: + using clock = std::chrono::high_resolution_clock; + + std::chrono::time_point start; + + public: + Timer() { reset(); } + + void reset() { start = clock::now(); } + + double query() const { + auto end = clock::now(); + return std::chrono::duration_cast>(end - + start) + .count(); + } +}; + +} // namespace oidn