{"id":15189833,"url":"https://github.com/renderkit/oidn","last_synced_at":"2026-01-16T08:19:07.706Z","repository":{"id":38359702,"uuid":"168025831","full_name":"RenderKit/oidn","owner":"RenderKit","description":"Intel® Open Image Denoise library","archived":false,"fork":false,"pushed_at":"2024-10-29T12:37:14.000Z","size":28988,"stargazers_count":1790,"open_issues_count":34,"forks_count":164,"subscribers_count":49,"default_branch":"master","last_synced_at":"2024-10-29T15:04:36.695Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.openimagedenoise.org/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RenderKit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-28T19:48:52.000Z","updated_at":"2024-10-29T11:25:30.000Z","dependencies_parsed_at":"2023-10-12T04:17:14.217Z","dependency_job_id":"3db3d92f-e916-4aee-8975-3f183651814f","html_url":"https://github.com/RenderKit/oidn","commit_stats":null,"previous_names":["renderkit/oidn","openimagedenoise/oidn"],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RenderKit%2Foidn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RenderKit%2Foidn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RenderKit%2Foidn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RenderKit%2Foidn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RenderKit","download_url":"https://codeload.github.com/RenderKit/oidn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248469124,"owners_count":21108961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-27T20:02:16.666Z","updated_at":"2026-01-16T08:19:07.688Z","avatar_url":"https://github.com/RenderKit.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Intel® Open Image Denoise\n\nThis is release v2.4.1 of Intel Open Image Denoise. For changes and new\nfeatures see the [changelog](CHANGELOG.md). Visit\nhttps://www.openimagedenoise.org for more information.\n\n# Overview\n\nIntel Open Image Denoise is an open source library of high-performance,\nhigh-quality denoising filters for images rendered with ray tracing.\nIntel Open Image Denoise is part of the [Intel® Rendering\nToolkit](https://software.intel.com/en-us/oneapi/render-kit) and is\nreleased under the permissive [Apache 2.0\nlicense](http://www.apache.org/licenses/LICENSE-2.0). It has been\nrecognized with a [Technical Achievement\nAward](https://press.oscars.org/news/14-achievements-be-honored-scientific-and-technical-awardsr)\nby the Academy of Motion Picture Arts and Sciences in 2025 for its\ncontribution to the motion picture industry.\n\nThe purpose of Intel Open Image Denoise is to provide an open,\nhigh-quality, efficient, and easy-to-use denoising library that allows\none to significantly reduce rendering times in ray tracing based\nrendering applications. It filters out the Monte Carlo noise inherent to\nstochastic ray tracing methods like path tracing, reducing the amount of\nnecessary samples per pixel by even multiple orders of magnitude\n(depending on the desired closeness to the ground truth). A simple but\nflexible C/C++ API ensures that the library can be easily integrated\ninto most existing or new rendering solutions.\n\nAt the heart of the Intel Open Image Denoise library is a collection of\nefficient deep learning based denoising filters, which were trained to\nhandle a wide range of samples per pixel (spp), from 1 spp to almost\nfully converged. Thus it is suitable for both preview and final-frame\nrendering. The filters can denoise images either using only the noisy\ncolor (*beauty*) buffer, or, to preserve as much detail as possible, can\noptionally utilize auxiliary feature buffers as well (e.g. albedo,\nnormal). Such buffers are supported by most renderers as arbitrary\noutput variables (AOVs) or can be usually implemented with little\neffort.\n\nAlthough the library ships with a set of pre-trained filter models, it\nis not mandatory to use these. To optimize a filter for a specific\nrenderer, sample count, content type, scene, etc., it is possible to\ntrain the model using the included training toolkit and user-provided\nimage datasets.\n\nIntel Open Image Denoise supports a wide variety of CPUs and GPUs from\ndifferent vendors:\n\n  - Intel® 64 architecture compatible CPUs (with at least SSE4.1)\n\n  - ARM64 (AArch64) architecture CPUs (e.g. Apple silicon CPUs)\n\n  - Intel Xe, Xe2, and Xe3 architecture dedicated and integrated GPUs,\n    including Intel® Arc™ B-Series Graphics, Intel® Arc™ A-Series\n    Graphics, Intel® Arc™ Pro Series Graphics, Intel® Data Center GPU\n    Flex Series, Intel® Data Center GPU Max Series, Intel® Iris® Xe\n    Graphics, Intel® Core™ Ultra Processors with Intel® Arc™ Graphics,\n    11th-14th Gen Intel® Core™ processor graphics, and related Intel\n    Pentium® and Celeron® processors (Xe-LP, Xe-LPG, Xe-LPG+, Xe-HPG,\n    Xe-HPC, Xe2-LPG, Xe2-HPG, Xe3-LPG, and Xe3p-XPC microarchitectures)\n\n  - NVIDIA GPUs with Turing, Ampere, Ada Lovelace, Hopper, and Blackwell\n    architectures\n\n  - AMD GPUs with RDNA 2, RDNA 3, RDNA 3.5, and RDNA 4 architectures\n\n  - Apple silicon GPUs (M1 and newer)\n\nIt runs on most machines ranging from laptops to workstations and\ncompute nodes in HPC systems. It is efficient enough to be suitable not\nonly for offline rendering, but, depending on the hardware used, also\nfor interactive or even real-time ray tracing.\n\nIntel Open Image Denoise exploits modern instruction sets like SSE4,\nAVX2, AVX-512, Intel® Advanced Matrix Extensions (Intel® AMX), and NEON\non CPUs, Intel® Xe Matrix Extensions (Intel® XMX) on Intel GPUs, and\nvarious other AI acceleration capabilities on NVIDIA, AMD, and Apple\nGPUs.\n\n## System Requirements\n\nYou need an Intel® 64 (with SSE4.1) or ARM64 architecture compatible CPU\nto run Intel Open Image Denoise, and you need a 64-bit Windows, Linux,\nor macOS operating system as well.\n\nFor Intel GPU support, please also install the latest Intel graphics\ndrivers:\n\n  - Windows: [Intel® Graphics\n    Driver](https://www.intel.com/content/www/us/en/download-center/home.html)\n    31.0.101.4953 or newer\n\n  - Linux: [Intel® software for General Purpose GPU\n    capabilities](https://dgpu-docs.intel.com/driver/overview/overview.html)\n    release 20230323 or newer\n\nUsing older driver versions is *not* supported and Intel Open Image\nDenoise might run with only limited capabilities, have suboptimal\nperformance or might be unstable. Also, Resizable BAR *must* be enabled\nin the BIOS for Intel dedicated GPUs if running on Linux, and strongly\nrecommended if running on Windows.\n\nFor NVIDIA GPU support, please also install the latest [NVIDIA graphics\ndrivers](https://www.nvidia.com/en-us/geforce/drivers/):\n\n  - Windows: Version 528.33 or newer\n\n  - Linux: Version 525.60.13 or newer\n\nFor AMD GPU support, please also install the latest [AMD graphics\ndrivers](https://www.amd.com/en/support):\n\n  - Windows: AMD Software: Adrenalin Edition 25.3.1 or newer\n\n  - Linux: [Radeon Software for\n    Linux](https://www.amd.com/en/support/download/linux-drivers.html)\n    version 25.30.1 or newer\n\nFor Apple GPU support, macOS Ventura or newer is required.\n\n## Support and Contact\n\nIntel Open Image Denoise is under active development, and though we do\nour best to guarantee stable release versions a certain number of bugs,\nas-yet-missing features, inconsistencies, or any other issues are still\npossible. Should you find any such issues please report them immediately\nvia the [Intel Open Image Denoise GitHub Issue\nTracker](https://github.com/OpenImageDenoise/oidn/issues) (or, if you\nshould happen to have a fix for it, you can also send us a pull\nrequest); for missing features please contact us via email at\n\u003copenimagedenoise@googlegroups.com\u003e.\n\nJoin our [mailing\nlist](https://groups.google.com/d/forum/openimagedenoise/) to receive\nrelease announcements and major news regarding Intel Open Image Denoise.\n\n## Citation\n\nIf you use Intel Open Image Denoise in a research publication, please\ncite the project using the following BibTeX entry:\n\n``` bibtex\n@misc{OpenImageDenoise,\n  author = {Attila T. {\\'A}fra},\n  title  = {{Intel\\textsuperscript{\\textregistered} Open Image Denoise}},\n  year   = {2026},\n  note   = {\\url{https://www.openimagedenoise.org}}\n}\n```\n\n# Compilation\n\nThe latest Intel Open Image Denoise sources are always available at the\n[Intel Open Image Denoise GitHub\nrepository](http://github.com/OpenImageDenoise/oidn). The default\n`master` branch should always point to the latest tested bugfix release.\n\n## Prerequisites\n\nYou can clone the latest Intel Open Image Denoise sources using Git with\nthe [Git Large File Storage (LFS)](https://git-lfs.github.com/)\nextension installed:\n\n    git clone --recursive https://github.com/OpenImageDenoise/oidn.git\n\nPlease note that installing the Git LFS extension is *required* to\ncorrectly clone the repository. Cloning without Git LFS will seemingly\nsucceed but actually some of the files will be invalid and thus\ncompilation will fail.\n\nIntel Open Image Denoise currently supports 64-bit Linux, Windows, and\nmacOS operating systems. Before you can build Intel Open Image Denoise\nyou need the following basic prerequisites:\n\n  - [CMake](http://www.cmake.org) 3.15 or newer\n\n  - A C++11 compiler (we recommend using a Clang-based compiler but also\n    support GCC and Microsoft Visual Studio 2015 and newer)\n\n  - Python 3\n\nTo build support for different types of CPUs and GPUs, the following\nadditional prerequisites are needed:\n\n#### CPU device:\n\n  - [Intel® SPMD Program Compiler (ISPC)](http://ispc.github.io) 1.29.1\n    or newer. Please obtain a release of ISPC from the [ISPC downloads\n    page](https://ispc.github.io/downloads.html). The build system looks\n    for ISPC in the `PATH` and in the directory right “next to” the\n    checked-out Intel Open Image Denoise sources. For example, if Intel\n    Open Image Denoise is in `~/Projects/oidn`, ISPC will also be\n    searched in `~/Projects/ispc-v1.29.1-linux`. Alternatively set the\n    CMake variable `ISPC_EXECUTABLE` to the location of the ISPC\n    compiler.\n\n  - [Intel® Threading Building\n    Blocks](https://github.com/uxlfoundation/oneTBB) (TBB) 2017 or newer\n\n#### SYCL device for Intel GPUs:\n\n  - oneAPI DPC++ Compiler, one of the following versions (other versions\n    might work as well but have *not* been validated with Intel Open\n    Image Denoise):\n    \n      - [oneAPI DPC++\n        Compiler 6.2.1](https://github.com/intel/llvm/releases/tag/v6.2.1).\n        This is the open source version of the compiler.\n      - [Intel® oneAPI DPC++/C++\n        Compiler](https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler.html)\n        2025.3 or newer\n\n  - *Optional*: Intel® Graphics Offline Compiler for OpenCL™ Code\n    (OCLOC), if building with `OIDN_DEVICE_SYCL_AOT` enabled\n    \n      - Windows: Version [2025.3.3\n        / 32.0.101.8331](https://registrationcenter-download.intel.com/akdlm/IRC_NAS/cb17f6e4-6e61-47c7-bb27-1008b23f1c7b/intel-ocloc-2025.3.3.4_offline.exe)\n        or newer as a [standalone component of Intel® oneAPI\n        Toolkits](https://www.intel.com/content/www/us/en/developer/articles/tool/oneapi-standalone-components.html),\n        which must be extracted and its contents added to the `PATH`.\n        Also included with [Intel® oneAPI Base\n        Toolkit](https://www.intel.com/content/www/us/en/developer/tools/oneapi/toolkits.html#base-kit).\n    \n      - Linux: Included with [Intel® software for General Purpose GPU\n        capabilities](https://dgpu-docs.intel.com) release\n        [LTS 2523.x](https://dgpu-docs.intel.com/releases/LTS-release-notes.html#release-2025-12-11)\n        or newer (install at least `intel-opencl-icd` on Ubuntu,\n        `intel-ocloc` on RHEL or SLES). For more recent versions please\n        refer to [Intel® Graphics Compute Runtime for oneAPI Level Zero\n        and OpenCL™ Driver](https://github.com/intel/compute-runtime).\n\n  - If using Intel® oneAPI DPC++/C++ Compiler:\n    [CMake](http://www.cmake.org) 3.25.2 or newer\n\n  - [Ninja](https://ninja-build.org) or Make as the CMake generator. The\n    Visual Studio generator is *not* supported.\n\n#### CUDA device for NVIDIA GPUs:\n\n  - [CMake](http://www.cmake.org) 3.18 or newer\n\n  - [NVIDIA CUDA Toolkit](https://developer.nvidia.com/cuda-toolkit)\n    12.8 or newer\n\n#### HIP device for AMD GPUs:\n\n  - [CMake](http://www.cmake.org) 3.21 or newer\n\n  - [Ninja](https://ninja-build.org) or Make as the CMake generator. The\n    Visual Studio generator is *not* supported.\n\n  - [AMD ROCm (HIP SDK)](https://rocm.docs.amd.com) v6.4.2 or newer.\n\n#### Metal device for Apple GPUs:\n\n  - [CMake](http://www.cmake.org) 3.21 or newer\n\n  - [Xcode](https://developer.apple.com/xcode/) 15.0 or newer\n\nDepending on your operating system, you can install some required\ndependencies (e.g., TBB) using `yum` or `apt-get` on Linux,\n[Homebrew](https://brew.sh) or [MacPorts](https://www.macports.org) on\nmacOS, and [`vcpkg`](https://vcpkg.io) on Windows. For the other\ndependencies please download the necessary packages or installers and\nfollow the included instructions.\n\n## Compiling on Linux/macOS\n\nIf you are building with SYCL support on Linux, make sure that the DPC++\ncompiler is properly set up. The open source oneAPI DPC++ Compiler can\nbe downloaded and simply extracted. However, before using the compiler,\nthe environment must be set up as described in the [Get Started\nGuide](https://github.com/intel/llvm/blob/sycl/sycl/doc/GetStartedGuide.md).\n\nAlternatively, if you have installed Intel® oneAPI DPC++/C++ Compiler\ninstead, you can set up the compiler by sourcing the `vars.sh` script in\nthe `env` directory of the compiler install directory, for example,\n\n    source /opt/intel/oneAPI/compiler/latest/env/vars.sh\n\nThis script will put the `icx` and `icpx` compiler executables from the\nIntel(R) oneAPI DPC++/C++ Compiler in your `PATH`.\n\n  - Create a build directory, and go into it using a command prompt\n    \n        mkdir oidn/build\n        cd oidn/build\n    \n    (We do recommend having separate build directories for different\n    configurations such as release, debug, etc.).\n\n  - CMake will use the default compiler, which on most Linux machines is\n    `gcc`, but it can be switched to `clang` by executing the following:\n    \n        cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ..\n    \n    If you are building with SYCL support, you must set the DPC++\n    compiler (`clang`/`clang++` or `icx`/`icpx`) as the C/C++ compiler\n    here. Note that the compiler variables cannot be changed after the\n    first `cmake` or `ccmake` run.\n\n  - Open the CMake configuration dialog\n    \n        ccmake ..\n\n  - Make sure to properly set the build mode and enable the components\n    and options you need. By default only CPU support is built, so SYCL\n    and other device support must be enabled manually (e.g. with the\n    `OIDN_DEVICE_SYCL` option). Then type ’c’onfigure and ’g’enerate.\n    When back on the command prompt, build the library using\n    \n        ninja\n\n## Compiling on Windows\n\nIf you are building with SYCL support, make sure that the DPC++ compiler\nis properly set up. The open source oneAPI DPC++ Compiler can be\ndownloaded and simply extracted. However, before using the compiler, the\nenvironment must be set up as described in the [Get Started\nGuide](https://github.com/intel/llvm/blob/sycl/sycl/doc/GetStartedGuide.md).\n\nAlternatively, if you have installed Intel® oneAPI DPC++/C++ Compiler\ninstead, you can either open a regular “Command Prompt” and execute the\n`vars.bat` script in the `env` directory of the compiler install\ndirectory, for example\n\n    C:\\Program Files (x86)\\Intel\\oneAPI\\compiler\\latest\\env\\vars.bat\n\nor simply open the installed “Intel oneAPI command prompt for Intel 64\nfor Visual Studio”. Either way, the `icx` compiler executable from the\nIntel® oneAPI DPC++/C++ Compiler will be added to your `PATH`.\n\nOn Windows we highly recommend to use Ninja as the CMake generator\nbecause not all devices can be built using the Visual Studio generator\n(e.g. SYCL).\n\n  - Create a build directory, and go into it using a Visual Studio\n    command prompt\n    \n        mkdir oidn/build\n        cd oidn/build\n    \n    (We do recommend having separate build directories for different\n    configurations such as release, debug, etc.).\n\n  - CMake will use the default compiler, which on most Windows machines\n    is MSVC, but it can be switched to `clang` by executing the\n    following:\n    \n        cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ..\n    \n    If you are building with SYCL support, you must set the DPC++\n    compiler (`clang`/`clang++` or `icx`) as the C/C++ compiler here.\n    Note that the compiler variables cannot be changed after the first\n    `cmake` or `cmake-gui` run.\n\n  - Open the CMake GUI (`cmake-gui.exe`)\n    \n        cmake-gui ..\n\n  - Make sure to properly set the build mode and enable the components\n    and options you need. By default only CPU support is built, so SYCL\n    and other device support must be enabled manually\n    (e.g. `OIDN_DEVICE_SYCL` option). Then click on Configure and\n    Generate. When back on the command prompt, build the library using\n    \n        ninja\n\n## CMake Configuration\n\nThe following list describes the options that can be configured in\nCMake:\n\n  - `CMAKE_BUILD_TYPE`: Can be used to switch between Debug mode\n    (Debug), Release mode (Release) (default), and Release mode with\n    enabled assertions and debug symbols (RelWithDebInfo).\n\n  - `OIDN_STATIC_LIB`: Build Open Image Denoise as a static (if only CPU\n    support is enabled) or a hybrid static/shared (if GPU support is\n    enabled as well) library.\n\n  - `OIDN_LIBRARY_NAME`: Specifies the base name of the Open Image\n    Denoise library files (`OpenImageDenoise` by default).\n\n  - `OIDN_LIBRARY_VERSIONED`: Enable versioning of the Open Image\n    Denoise library files, where available (ON by default).\n\n  - `OIDN_API_NAMESPACE`: Specifies a namespace to put all Open Image\n    Denoise API symbols inside. This is also added as an outer namespace\n    for the C++ wrapper API. By default no namespace is used and plain C\n    symbols are exported.\n\n  - `OIDN_DEVICE_CPU`: Enable CPU device support (ON by default).\n\n  - `OIDN_DEVICE_SYCL`: Enable SYCL device support for Intel GPUs (OFF\n    by default).\n\n  - `OIDN_DEVICE_SYCL_AOT`: Enable ahead-of-time (AOT) compilation for\n    SYCL kernels (OFF by default). Turning this on adds dependency on\n    OCLOC at build time and increases binary size but decreases\n    initialization time at runtime.\n\n  - `OIDN_DEVICE_CUDA`: Enable CUDA device support for NVIDIA GPUs (OFF\n    by default).\n\n  - `OIDN_DEVICE_CUDA_API`: Use the CUDA driver API (`Driver`, default),\n    the static CUDA runtime library (`RuntimeStatic`), or the shared\n    CUDA runtime library (`RuntimeShared`).\n\n  - `OIDN_DEVICE_HIP`: Enable HIP device support for AMD GPUs (OFF by\n    default).\n\n  - `OIDN_DEVICE_METAL`: Enable Metal device support for Apple GPUs (OFF\n    by default).\n\n  - `OIDN_FILTER_RT`: Include the trained weights of the `RT` filter in\n    the build (ON by default). Turning this OFF significantly decreases\n    the size of the library binary, while the filter remains functional\n    if the weights are set by the user at runtime.\n\n  - `OIDN_FILTER_RTLIGHTMAP`: Include the trained weights of the\n    `RTLightmap` filter in the build (ON by default).\n\n  - `OIDN_APPS`: Enable building example and test applications (ON by\n    default).\n\n  - `OIDN_APPS_OPENIMAGEIO`: Enable\n    [OpenImageIO](http://openimageio.org/) 2.1 or later support in the\n    example and test applications to be able to load/save OpenEXR, PNG,\n    and other image file formats (OFF by default).\n\n  - `OIDN_INSTALL_DEPENDENCIES`: Enable installing the dependencies\n    (e.g. TBB, SYCL runtime) as well.\n\n  - `OIDN_DEPENDENTLOADFLAG`: Value for `DEPENDENTLOADFLAG` linker flag\n    on Windows. For more information, see\n    [SECURITY.md](SECURITY.md#security-considerations)\n\n  - `TBB_ROOT`: The path to the TBB installation (autodetected by\n    default).\n\n  - `ROCM_PATH`: The path to the ROCm installation (autodetected by\n    default).\n\n  - `OpenImageIO_ROOT`: The path to the OpenImageIO installation\n    (autodetected by default).\n\n# Documentation\n\nThe following\n[documentation](https://github.com/OpenImageDenoise/oidn/blob/master/readme.pdf \"Intel Open Image Denoise Documentation\")\nof Intel Open Image Denoise can also be found as a [pdf\ndocument](https://github.com/OpenImageDenoise/oidn/blob/master/readme.pdf \"Intel Open Image Denoise Documentation\").\n\n# Open Image Denoise API\n\nOpen Image Denoise provides a C99 API (also compatible with C++) and a\nC++11 wrapper API as well. For simplicity, this document mostly refers\nto the C99 version of the API.\n\nThe API is designed in an object-oriented manner, e.g. it contains\ndevice objects (`OIDNDevice` type), buffer objects (`OIDNBuffer` type),\nand filter objects (`OIDNFilter` type). All objects are\nreference-counted, and handles can be released by calling the\nappropriate release function (e.g. `oidnReleaseDevice`) or retained by\nincrementing the reference count (e.g. `oidnRetainDevice`).\n\nAn important aspect of objects is that setting their parameters do not\nhave an immediate effect (with a few exceptions). Instead, objects with\nupdated parameters are in an unusable state until the parameters get\nexplicitly committed to a given object. The commit semantic allows for\nbatching up multiple small changes, and specifies exactly when changes\nto objects will occur.\n\nAll API calls are thread-safe, but operations that use the same device\nwill be serialized, so the amount of API calls from different threads\nshould be minimized.\n\n## Examples\n\nTo have a quick overview of the C99 and C++11 APIs, see the following\nsimple example code snippets.\n\n### Basic Denoising (C99 API)\n\n``` cpp\n#include \u003cOpenImageDenoise/oidn.h\u003e\n...\n\n// Create an Open Image Denoise device\nOIDNDevice device = oidnNewDevice(OIDN_DEVICE_TYPE_DEFAULT); // CPU or GPU if available\n// OIDNDevice device = oidnNewDevice(OIDN_DEVICE_TYPE_CPU);\noidnCommitDevice(device);\n\n// Create buffers for input/output images accessible by both host (CPU) and device (CPU/GPU)\nOIDNBuffer colorBuf  = oidnNewBuffer(device, width * height * 3 * sizeof(float));\nOIDNBuffer albedoBuf = ...\n\n// Create a filter for denoising a beauty (color) image using optional auxiliary images too\n// This can be an expensive operation, so try not to create a new filter for every image!\nOIDNFilter filter = oidnNewFilter(device, \"RT\"); // generic ray tracing filter\noidnSetFilterImage(filter, \"color\",  colorBuf,\n                   OIDN_FORMAT_FLOAT3, width, height, 0, 0, 0); // beauty\noidnSetFilterImage(filter, \"albedo\", albedoBuf,\n                   OIDN_FORMAT_FLOAT3, width, height, 0, 0, 0); // auxiliary\noidnSetFilterImage(filter, \"normal\", normalBuf,\n                   OIDN_FORMAT_FLOAT3, width, height, 0, 0, 0); // auxiliary\noidnSetFilterImage(filter, \"output\", colorBuf,\n                   OIDN_FORMAT_FLOAT3, width, height, 0, 0, 0); // denoised beauty\noidnSetFilterBool(filter, \"hdr\", true); // beauty image is HDR\noidnCommitFilter(filter);\n\n// Fill the input image buffers\nfloat* colorPtr = (float*)oidnGetBufferData(colorBuf);\n...\n\n// Filter the beauty image\noidnExecuteFilter(filter);\n\n// Check for errors\nconst char* errorMessage;\nif (oidnGetDeviceError(device, \u0026errorMessage) != OIDN_ERROR_NONE)\n  printf(\"Error: %s\\n\", errorMessage);\n\n// Cleanup\noidnReleaseBuffer(colorBuf);\n...\noidnReleaseFilter(filter);\noidnReleaseDevice(device);\n```\n\n### Basic Denoising (C++11 API)\n\n``` cpp\n#include \u003cOpenImageDenoise/oidn.hpp\u003e\n...\n\n// Create an Open Image Denoise device\noidn::DeviceRef device = oidn::newDevice(); // CPU or GPU if available\n// oidn::DeviceRef device = oidn::newDevice(oidn::DeviceType::CPU);\ndevice.commit();\n\n// Create buffers for input/output images accessible by both host (CPU) and device (CPU/GPU)\noidn::BufferRef colorBuf  = device.newBuffer(width * height * 3 * sizeof(float));\noidn::BufferRef albedoBuf = ...\n\n// Create a filter for denoising a beauty (color) image using optional auxiliary images too\n// This can be an expensive operation, so try no to create a new filter for every image!\noidn::FilterRef filter = device.newFilter(\"RT\"); // generic ray tracing filter\nfilter.setImage(\"color\",  colorBuf,  oidn::Format::Float3, width, height); // beauty\nfilter.setImage(\"albedo\", albedoBuf, oidn::Format::Float3, width, height); // auxiliary\nfilter.setImage(\"normal\", normalBuf, oidn::Format::Float3, width, height); // auxiliary\nfilter.setImage(\"output\", colorBuf,  oidn::Format::Float3, width, height); // denoised beauty\nfilter.set(\"hdr\", true); // beauty image is HDR\nfilter.commit();\n\n// Fill the input image buffers\nfloat* colorPtr = (float*)colorBuf.getData();\n...\n\n// Filter the beauty image\nfilter.execute();\n\n// Check for errors\nconst char* errorMessage;\nif (device.getError(errorMessage) != oidn::Error::None)\n  std::cout \u003c\u003c \"Error: \" \u003c\u003c errorMessage \u003c\u003c std::endl;\n```\n\n### Denoising with Prefiltering (C++11 API)\n\n``` cpp\n// Create a filter for denoising a beauty (color) image using prefiltered auxiliary images too\noidn::FilterRef filter = device.newFilter(\"RT\"); // generic ray tracing filter\nfilter.setImage(\"color\",  colorBuf,  oidn::Format::Float3, width, height); // beauty\nfilter.setImage(\"albedo\", albedoBuf, oidn::Format::Float3, width, height); // auxiliary\nfilter.setImage(\"normal\", normalBuf, oidn::Format::Float3, width, height); // auxiliary\nfilter.setImage(\"output\", outputBuf, oidn::Format::Float3, width, height); // denoised beauty\nfilter.set(\"hdr\", true); // beauty image is HDR\nfilter.set(\"cleanAux\", true); // auxiliary images will be prefiltered\nfilter.commit();\n\n// Create a separate filter for denoising an auxiliary albedo image (in-place)\noidn::FilterRef albedoFilter = device.newFilter(\"RT\"); // same filter type as for beauty\nalbedoFilter.setImage(\"albedo\", albedoBuf, oidn::Format::Float3, width, height);\nalbedoFilter.setImage(\"output\", albedoBuf, oidn::Format::Float3, width, height);\nalbedoFilter.commit();\n\n// Create a separate filter for denoising an auxiliary normal image (in-place)\noidn::FilterRef normalFilter = device.newFilter(\"RT\"); // same filter type as for beauty\nnormalFilter.setImage(\"normal\", normalBuf, oidn::Format::Float3, width, height);\nnormalFilter.setImage(\"output\", normalBuf, oidn::Format::Float3, width, height);\nnormalFilter.commit();\n\n// Prefilter the auxiliary images\nalbedoFilter.execute();\nnormalFilter.execute();\n\n// Filter the beauty image\nfilter.execute();\n```\n\n## Upgrading from Open Image Denoise 1.x\n\nOpen Image Denoise 2 introduces GPU support, which requires implementing\nsome minor changes in applications. There are also small API changes,\nadditions and improvements in this new version. In this section we\nsummarize the necessary code modifications and also briefly mention the\nnew features that users might find useful when upgrading to version 2.x.\nFor a full description of the changes and new functionality, please see\nthe API reference.\n\n### Buffers\n\nThe most important required change is related to how data is passed to\nOpen Image Denoise. If the application is explicitly using only the CPU\n(by specifying `OIDN_DEVICE_TYPE_CPU`), no changes should be necessary.\nBut if it wants to support GPUs as well, passing pointers to memory\nallocated with the system allocator (e.g. `malloc`) would raise an error\nbecause GPUs cannot access such memory in almost all cases.\n\nTo ensure compatibility with any kind of device, including GPUs, the\napplication should use `OIDNBuffer` objects to store all image data\npassed to the library. Memory allocated using buffers is by default\naccessible by both the host (CPU) and the device (CPU or GPU).\n\nIdeally, the application should directly read and write image data\nto/from such buffers to avoid redundant and inefficient data copying. If\nthis cannot be implemented, the application should try to minimize the\noverhead of copying as much as possible:\n\n  - Data should be copied to/from buffers only if the data in system\n    memory indeed cannot be accessed by the device. This can be\n    determined by simply querying the `systemMemorySupported` device\n    parameter. If system allocated memory is accessible by the device,\n    no buffers are necessary and filter image parameters can be set with\n    `oidnSetSharedFilterImage`.\n\n  - If the image data cannot be accessed by the device, buffers must be\n    created and the data must be copied to/from these buffers. These\n    buffers should be directly passed to filters as image parameters\n    instead of the original pointers using `oidnSetFilterImage`.\n\n  - Data should be copied asynchronously using using the new\n    `oidnReadBufferAsync` and `oidnWriteBufferAsync` functions, which\n    may achieve higher performance than plain `memcpy`.\n\n  - If image data must be copied, using the default buffer allocation\n    may not be the most efficient method. If the device memory is not\n    physically shared with the host memory (e.g. for dedicated GPUs),\n    higher performance may be achieved by creating the buffers with\n    device storage (`OIDN_STORAGE_DEVICE`) using the new\n    `oidnNewBufferWithStorage` function. This way, the buffer data\n    cannot be directly accessed by the host anymore but this should not\n    matter because the data must be copied from some other memory\n    location anyway. However, this ensures that the data is stored only\n    in high-performance device memory, and the user has full control\n    over when and how the data is transferred between host and device.\n\nThe `oidnMapBuffer` and `oidnUnmapBuffer` functions have been removed\nfrom the API due to these not being supported by any of the device\nbackends. Please use `oidnReadBuffer(Async)` and\n`oidnWriteBuffer(Async)` instead.\n\n### Interop with Compute (SYCL, CUDA, HIP) and Graphics (DX, Vulkan, Metal) APIs\n\nIf the application is explicitly using a particular device type which\nsupports unified memory allocations, e.g. SYCL or CUDA, it may directly\npass pointers allocated using the native allocator of the respective\ncompute API (e.g. `sycl::malloc_device`, `cudaMalloc`) instead of using\nbuffers. This way, it is the responsibility of the user to correctly\nallocate the memory for the device.\n\nIn such cases, it often necessary to have more control over the device\ncreation as well, to ensure that filtering is running on the intended\ndevice and command queues or streams from the application can be shared\nto improve performance. If the application is using the same compute or\ngraphics API as the Open Image Denoise device, this can be achieved by\ncreating devices with `oidnNewSYCLDevice`, `oidnNewCUDADevice`, etc. For\nsome APIs there are additional interoperability functions as well,\ne.g. `oidnExecuteSYCLFilterAsync`.\n\nIf the application is using a graphics API which does not support\nunified memory allocations, e.g. DX12 or Vulkan, it may be still\npossible to share memory between the application and Open Image Denoise\nusing buffers, avoiding expensive copying through host memory. External\nbuffers can be imported from graphics APIs with the new\n`oidnNewSharedBufferFromFD` and `oidnNewSharedBufferFromWin32Handle`\nfunctions. To use this feature, buffers must be exported in the graphics\nAPI and must be imported in Open Image Denoise using the same kind of\nhandle. Care must be taken to select an external memory handle type\nwhich is supported by both APIs. The external memory types supported by\nan Open Image Denoise device can be queried using the\n`externalMemoryTypes` device parameter. Note that some devices do not\nsupport importing external memory at all (e.g. CPUs, and on GPUs it\nprimarily depends on the installed drivers), so the application should\nalways implement a fallback too, which copies the data through the host\nif there is no other supported way. Metal buffers can be used directly\nwith the `oidnNewSharedBufferFromMetal` function.\n\nSharing textures is currently not supported natively but it is still\npossible avoid copying texture data by using a linear texture layout\n(e.g. `VK_IMAGE_TILING_LINEAR` in Vulkan) and sharing the buffer that\nbacks this data. In this case, you should ensure that the row stride of\nthe linear texture data is correctly set.\n\nImporting external synchronization primitives (e.g. semaphores) from\ngraphics APIs is not yet supported either but it is planned for a future\nrelease. Meanwhile, synchronizing access to shared memory should be done\non the host using `oidnSyncDevice` and the used graphics API.\n\nWhen importing external memory, the application also needs to make sure\nthat the Open Image Denoise device is running on the same *physical*\ndevice as the graphics API. This can be easily achieved by using the new\nphysical device feature, described in the next section.\n\n### Physical Devices\n\nAlthough it is possible to explicitly create devices of a particular\ntype (with, e.g., `OIDN_DEVICE_TYPE_SYCL`), this is often insufficient,\nespecially if the system has multiple devices of the same type, and with\nGPU support it is very common that there are multiple different types of\nsupported devices in the system (e.g. a CPU and one or more GPUs).\n\nOpen Image Denoise 2 introduces a simple *physical device* API, which\nenables the application to query the list of supported physical devices\nin the system, including their name, type, UUID, LUID, PCI address, etc.\n(see `oidnGetNumPhysicalDevices`, `oidnGetPhysicalDeviceString`, etc.).\nNew logical device (i.e. `OIDNDevice`) creation functions for have been\nalso introduced, which enable creating a logical device on a specific\nphysical device: `oidnNewDeviceByID`, `oidnNewDeviceByUUID`, etc.\n\nCreating a logical device on a physical device having a particular UUID,\nLUID or PCI address is particularly important when importing external\nmemory from graphics APIs. However, not all device types support all\ntypes of IDs, and some graphics drivers may even report mismatching\nUUIDs or LUIDs for the same physical device, so applications should try\nto implement multiple identification methods, or at least assume that\nidentification might fail.\n\n### Asynchronous Execution\n\nIt is now possible to execute some operations asynchronously, most\nimportantly filtering (`oidnExecuteFilterAsync`,\n`oidnExecuteSYCLFilterAsync`) and copying data (the already mentioned\n`oidnReadBufferAsync` and `oidnWriteBufferAsync`).\n\nWhen using any asynchronous function it is the responsibility of the\napplication to handle correct synchronization using `oidnSyncDevice`.\n\n### Filter Quality\n\nOpen Image Denoise still delivers the same high image quality on all\ndevice types as before, including on GPUs. But often filtering\nperformance is more important than having the highest possible image\nquality, so it is now possible to switch between multiple filter quality\nmodes. Filters have a new parameter called `quality`, which defaults to\nthe existing *high* image quality (`OIDN_QUALITY_HIGH`) but *balanced*\n(`OIDN_QUALITY_BALANCED`) and *fast* (`OIDN_QUALITY_FAST`) quality modes\nhave been added as well for even higher performance. We recommend using\n*balanced* or *fast* quality for interactive and real-time use cases.\n\n### Small API Changes\n\nA few existing API functions have been renamed to improve clarity (e.g.\n`oidnSetFilter1i` to `oidnSetFilterInt`) but the old function names are\nstill available as deprecated functions. When compiling legacy code,\nwarnings will be emitted for these deprecated functions. To upgrade to\nthe new API, please simply follow the instructions in the warnings.\n\nSome filter parameters have been also renamed (`alignment` to\n`tileAlignment`, `overlap` to `tileOverlap`). When using the old names,\nwarnings will be emitted at runtime.\n\n### Building as a Static Library\n\nThe support to build Open Image Denoise as a static library\n(`OIDN_STATIC_LIB` CMake option) has been limited to CPU-only builds due\nto switching to a modular library design that was necessary for adding\nmulti-vendor GPU support. If the library is built with GPU support as\nwell, the `OIDN_STATIC_LIB` option is still available but enabling it\nresults in a hybrid static/shared library.\n\nIf the main reason for building as a static library would be is the\nability to use multiple versions of Open Image Denoise in the same\nprocess, please use the existing `OIDN_API_NAMESPACE` CMake option\ninstead. With this feature all symbols of the library will be put into a\ncustom namespace, which can prevent symbol clashes.\n\n## Physical Devices\n\nSystems often have multiple different types of devices supported by Open\nImage Denoise (CPUs and GPUs). The application can get the list of\nsupported *physical devices* and select which of these to use for\ndenoising.\n\nThe number of supported physical devices can be queried with\n\n``` cpp\nint oidnGetNumPhysicalDevices();\n```\n\nThe physical devices can be identified using IDs between 0 and\n(`oidnGetNumPhysicalDevices()` \\(-\\) 1), and are ordered *approximately*\nfrom fastest to slowest (e.g., ID of 0 corresponds to the likely fastest\nphysical device). Note that the reported number and order of physical\ndevices may change between application runs, so no assumptions should be\nmade about this list.\n\nParameters of these physical devices can be queried using\n\n``` cpp\nbool         oidnGetPhysicalDeviceBool  (int physicalDeviceID, const char* name);\nint          oidnGetPhysicalDeviceInt   (int physicalDeviceID, const char* name);\nunsigned int oidnGetPhysicalDeviceUInt  (int physicalDeviceID, const char* name);\nconst char*  oidnGetPhysicalDeviceString(int physicalDeviceID, const char* name);\nconst void*  oidnGetPhysicalDeviceData  (int physicalDeviceID, const char* name,\n                                         size_t* byteSize);\n```\n\nwhere `name` is the name of the parameter, and `byteSize` is the number\nof returned bytes for data parameters. The following parameters can be\nqueried:\n\n| Type     | Name                  | Description                                                                                                                         |\n| :------- | :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------- |\n| `Int`    | `type`                | device type as an `OIDNDeviceType` value                                                                                            |\n| `String` | `name`                | name string                                                                                                                         |\n| `Bool`   | `uuidSupported`       | device supports universally unique identifier (UUID)                                                                                |\n| `Data`   | `uuid`                | opaque UUID (`OIDN_UUID_SIZE` bytes, exists only if `uuidSupported` is `true`)                                                      |\n| `Bool`   | `luidSupported`       | device supports locally unique identifier (UUID)                                                                                    |\n| `Data`   | `luid`                | opaque LUID (`OIDN_LUID_SIZE` bytes, exists only if `luidSupported` is `true`)                                                      |\n| `UInt`   | `nodeMask`            | bitfield identifying the node within a linked device adapter corresponding to the device (exists only if `luidSupported` is `true`) |\n| `Bool`   | `pciAddressSupported` | device supports PCI address                                                                                                         |\n| `Int`    | `pciDomain`           | PCI domain (exists only if `pciAddressSupported` is `true`)                                                                         |\n| `Int`    | `pciBus`              | PCI bus (exists only if `pciAddressSupported` is `true`)                                                                            |\n| `Int`    | `pciDevice`           | PCI device (exists only if `pciAddressSupported` is `true`)                                                                         |\n| `Int`    | `pciFunction`         | PCI function (exists only if `pciAddressSupported` is `true`)                                                                       |\n\nConstant parameters supported by physical devices.\n\nIt is also possible to directly query whether a physical device of a\nparticular type is supported, without iterating over all supported\nphysical devices:\n\n``` cpp\nbool oidnIsCPUDeviceSupported();\nbool oidnIsSYCLDeviceSupported(const sycl::device* device);\nbool oidnIsCUDADeviceSupported(int deviceID);\nbool oidnIsHIPDeviceSupported(int deviceID);\nbool oidnIsMetalDeviceSupported(MTLDevice_id device);\n```\n\n## Devices\n\nOpen Image Denoise has a *logical* device concept as well, or simply\nreferred to as *device*, which allows different components of the\napplication to use the Open Image Denoise API without interfering with\neach other. Each physical device may be associated with one ore more\nlogical devices. A basic way to create a device is by calling\n\n``` cpp\nOIDNDevice oidnNewDevice(OIDNDeviceType type);\n```\n\nwhere the `type` enumeration maps to a specific device implementation,\nwhich can be one of the following:\n\n| Name                       | Description                                                          |\n| :------------------------- | :------------------------------------------------------------------- |\n| `OIDN_DEVICE_TYPE_DEFAULT` | select the likely fastest device (same as physical device with ID 0) |\n| `OIDN_DEVICE_TYPE_CPU`     | CPU device                                                           |\n| `OIDN_DEVICE_TYPE_SYCL`    | SYCL device (requires a supported Intel GPU)                         |\n| `OIDN_DEVICE_TYPE_CUDA`    | CUDA device (requires a supported NVIDIA GPU)                        |\n| `OIDN_DEVICE_TYPE_HIP`     | HIP device (requires a supported AMD GPU)                            |\n| `OIDN_DEVICE_TYPE_METAL`   | Metal device (requires a supported Apple GPU)                        |\n\nSupported device types, i.e., valid constants of type `OIDNDeviceType`.\n\nIf there are multiple supported devices of the specified type, an\nimplementation-dependent default will be selected.\n\nA device can be created by specifying a physical device ID as well using\n\n``` cpp\nOIDNDevice oidnNewDeviceByID(int physicalDeviceID);\n```\n\nApplications can manually iterate over the list of physical devices and\nselect from them based on their properties but there are also some\nbuilt-in helper functions as well, which make creating a device by a\nparticular physical device property easier:\n\n``` cpp\nOIDNDevice oidnNewDeviceByUUID(const void* uuid);\nOIDNDevice oidnNewDeviceByLUID(const void* luid);\nOIDNDevice oidnNewDeviceByPCIAddress(int pciDomain, int pciBus, int pciDevice,\n                                     int pciFunction);\n```\n\nThese functions are particularly useful when the application needs\ninteroperability with a graphics API (e.g. DX12, Vulkan). However, not\nall of these properties may be supported by the intended physical device\n(or drivers might even report inconsistent identifiers), so it is\nrecommended to select by more than one property, if possible.\n\nIf the application requires interoperability with a particular compute\nor graphics API (SYCL, CUDA, HIP, Metal), it is recommended to use one\nof the following dedicated functions instead:\n\n``` cpp\nOIDNDevice oidnNewSYCLDevice(const sycl::queue* queues, int numQueues);\nOIDNDevice oidnNewCUDADevice(const int* deviceIDs, const cudaStream_t* streams,\n                             int numPairs);\nOIDNDevice oidnNewHIPDevice(const int* deviceIDs, const hipStream_t* streams,\n                            int numPairs);\nOIDNDevice oidnNewMetalDevice(const MTLCommandQueue_id* commandQueues,\n                              int numQueues);\n```\n\nFor SYCL, it is possible to pass one or more SYCL queues which will be\nused by Open Image Denoise for all device operations. This is useful\nwhen the application wants to use the same queues for both denoising and\nits own operations (e.g. rendering). Passing multiple queues is not\nintended to be used for different physical devices but just for a single\nSYCL root-device which consists of multiple sub-devices (e.g. Intel®\nData Center GPU Max Series having multiple Xe-Stacks/tiles). The only\nsupported SYCL backend is oneAPI Level Zero.\n\nFor CUDA and HIP, pairs of CUDA/HIP device IDs and corresponding streams\ncan be specified but the current implementation supports only one pair.\nA `NULL` stream corresponds to the default stream on the corresponding\ndevice. Open Image Denoise automatically sets and restores the current\nCUDA/HIP device/context on the calling thread when necessary, thus the\ncurrent device does not have to be changed manually by the application.\n\nFor Metal, a single command queue is supported.\n\nOnce a device is created, you can call\n\n``` cpp\nbool oidnGetDeviceBool(OIDNDevice device, const char* name);\nvoid oidnSetDeviceBool(OIDNDevice device, const char* name, bool value);\nint  oidnGetDeviceInt (OIDNDevice device, const char* name);\nvoid oidnSetDeviceInt (OIDNDevice device, const char* name, int  value);\nint  oidnGetDeviceUInt(OIDNDevice device, const char* name);\nvoid oidnSetDeviceUInt(OIDNDevice device, const char* name, unsigned int value);\n```\n\nto set and get parameter values on the device. Note that some parameters\nare constants, thus trying to set them is an error. See the tables below\nfor the parameters supported by devices.\n\n| Type   | Name                     |    Default | Description                                                                                                                               |\n| :----- | :----------------------- | ---------: | :---------------------------------------------------------------------------------------------------------------------------------------- |\n| `Int`  | `type`                   | *constant* | device type as an `OIDNDeviceType` value                                                                                                  |\n| `Int`  | `version`                | *constant* | combined version number (major.minor.patch) with two decimal digits per component                                                         |\n| `Int`  | `versionMajor`           | *constant* | major version number                                                                                                                      |\n| `Int`  | `versionMinor`           | *constant* | minor version number                                                                                                                      |\n| `Int`  | `versionPatch`           | *constant* | patch version number                                                                                                                      |\n| `Bool` | `systemMemorySupported`  | *constant* | device can directly access memory allocated with the system allocator (e.g. `malloc`)                                                     |\n| `Bool` | `managedMemorySupported` | *constant* | device supports buffers created with managed storage (`OIDN_STORAGE_MANAGED`)                                                             |\n| `Int`  | `externalMemoryTypes`    | *constant* | bitfield of `OIDNExternalMemoryTypeFlag` values representing the external memory types supported by the device                            |\n| `Int`  | `verbose`                |          0 | verbosity level of the console output between 0–4; when set to 0, no output is printed, when set to a higher level more output is printed |\n\nParameters supported by all devices.\n\n| Type   | Name          | Default | Description                                                                                                                       |\n| :----- | :------------ | ------: | :-------------------------------------------------------------------------------------------------------------------------------- |\n| `Int`  | `numThreads`  |       0 | maximum number of threads which the library should use; 0 will set it automatically to get the best performance                   |\n| `Bool` | `setAffinity` |  `true` | enables thread affinitization (pinning software threads to hardware threads) if it is necessary for achieving optimal performance |\n\nAdditional parameters supported only by CPU devices.\n\nNote that the CPU device heavily relies on setting the thread affinities\nto achieve optimal performance, so it is highly recommended to leave\nthis option enabled. However, this may interfere with the application if\nthat also sets the thread affinities, potentially causing performance\ndegradation. In such cases, the recommended solution is to either\ndisable setting the affinities in the application or in Open Image\nDenoise, or to always set/reset the affinities before/after each\nparallel region in the application (e.g., if using TBB, with\n`tbb::task_arena` and `tbb::task_scheduler_observer`).\n\nOnce parameters are set on the created device, the device must be\ncommitted with\n\n``` cpp\nvoid oidnCommitDevice(OIDNDevice device);\n```\n\nThis device can then be used to construct further objects, such as\nbuffers and filters. Note that a device can be committed only once\nduring its lifetime.\n\nSome functions may execute asynchronously with respect to the host. The\nnames of these functions are suffixed with `Async`. Asynchronous\noperations are executed *in order* on the device but may not block on\nthe host. Eventually, it is necessary to wait for all asynchronous\noperations to complete, which can be done by calling\n\n``` cpp\nvoid oidnSyncDevice(OIDNDevice device);\n```\n\nIf any errors have occurred during asynchronous operations (e.g.,\ncancellation through a progress monitor callback), those will be\nreported only when synchronization is triggered explicitly with\n`oidnSyncDevice` or implicitly with some other API call (e.g.,\n`oidnExecuteFilter`, `oidnCommitFilter`).\n\nBefore the application exits, it should release all devices by invoking\n\n``` cpp\nvoid oidnReleaseDevice(OIDNDevice device);\n```\n\nNote that Open Image Denoise uses reference counting for all object\ntypes, so this function decreases the reference count of the device, and\nif the count reaches 0 the device will automatically get deleted. It is\nalso possible to increase the reference count by calling\n\n``` cpp\nvoid oidnRetainDevice(OIDNDevice device);\n```\n\nAn application should typically create only a single device object per\nphysical device (one for *all* CPUs or one per GPU) as creation can be\nvery expensive and additional device objects may incur a significant\nmemory overhead. If required differently, it should only use a small\nnumber of device objects at any given time.\n\n### Error Handling\n\nEach user thread has its own error code per device. If an error occurs\nwhen calling an API function, this error code is set to the occurred\nerror if it stores no previous error. The currently stored error can be\nqueried by the application via\n\n``` cpp\nOIDNError oidnGetDeviceError(OIDNDevice device, const char** outMessage);\n```\n\nwhere `outMessage` can be a pointer to a C string which will be set to a\nmore descriptive error message, or it can be `NULL`. This function also\nclears the error code, which assures that the returned error code is\nalways the first error occurred since the last invocation of\n`oidnGetDeviceError` on the current thread. Note that the optionally\nreturned error message string is valid only until the next invocation of\nthe function.\n\nAlternatively, the application can also register a callback function of\ntype\n\n``` cpp\ntypedef void (*OIDNErrorFunction)(void* userPtr, OIDNError code, const char* message);\n```\n\nvia\n\n``` cpp\nvoid oidnSetDeviceErrorFunction(OIDNDevice device, OIDNErrorFunction func, void* userPtr);\n```\n\nto get notified when errors occur. Only a single callback function can\nbe registered per device, and further invocations overwrite the\npreviously set callback function, which do *not* require also calling\nthe `oidnCommitDevice` function. Passing `NULL` as function pointer\ndisables the registered callback function. When the registered callback\nfunction is invoked, it gets passed the user-defined payload (`userPtr`\nargument as specified at registration time), the error code (`code`\nargument) of the occurred error, as well as a string (`message`\nargument) that further describes the error. The error code is always set\neven if an error callback function is registered. It is recommended to\nalways set a error callback function, to detect all errors.\n\nWhen the device construction fails, `oidnNewDevice` returns `NULL` as\ndevice. To detect the error code of a such failed device construction,\npass `NULL` as device to the `oidnGetDeviceError` function. For all\nother invocations of `oidnGetDeviceError`, a proper device handle must\nbe specified.\n\nThe following errors are currently used by Open Image Denoise:\n\n| Name                              | Description                                |\n| :-------------------------------- | :----------------------------------------- |\n| `OIDN_ERROR_NONE`                 | no error occurred                          |\n| `OIDN_ERROR_UNKNOWN`              | an unknown error occurred                  |\n| `OIDN_ERROR_INVALID_ARGUMENT`     | an invalid argument was specified          |\n| `OIDN_ERROR_INVALID_OPERATION`    | the operation is not allowed               |\n| `OIDN_ERROR_OUT_OF_MEMORY`        | not enough memory to execute the operation |\n| `OIDN_ERROR_UNSUPPORTED_HARDWARE` | the hardware (CPU/GPU) is not supported    |\n| `OIDN_ERROR_CANCELLED`            | the operation was cancelled by the user    |\n\nPossible error codes, i.e., valid constants of type `OIDNError`.\n\n### Environment Variables\n\nOpen Image Denoise supports environment variables for overriding certain\nsettings at runtime, which can be useful for debugging and development:\n\n| Name                  | Description                                                                                                                         |\n| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------- |\n| `OIDN_DEFAULT_DEVICE` | overrides what physical device to use with `OIDN_DEVICE_TYPE_DEFAULT`; can be `cpu`, `sycl`, `cuda`, `hip`, or a physical device ID |\n| `OIDN_DEVICE_CPU`     | value of 0 disables CPU device support                                                                                              |\n| `OIDN_DEVICE_SYCL`    | value of 0 disables SYCL device support                                                                                             |\n| `OIDN_DEVICE_CUDA`    | value of 0 disables CUDA device support                                                                                             |\n| `OIDN_DEVICE_HIP`     | value of 0 disables HIP device support                                                                                              |\n| `OIDN_DEVICE_METAL`   | value of 0 disables Metal device support                                                                                            |\n| `OIDN_NUM_THREADS`    | overrides `numThreads` device parameter                                                                                             |\n| `OIDN_SET_AFFINITY`   | overrides `setAffinity` device parameter                                                                                            |\n| `OIDN_NUM_SUBDEVICES` | overrides number of SYCL sub-devices to use (e.g. for Intel® Data Center GPU Max Series)                                            |\n| `OIDN_VERBOSE`        | overrides `verbose` device parameter                                                                                                |\n\nEnvironment variables supported by Open Image Denoise.\n\n## Buffers\n\nImage data can be passed to Open Image Denoise either via pointers to\nmemory allocated and managed by the user or by creating buffer objects.\nRegardless of which method is used, the data must be allocated in a way\nthat it is accessible by the device (either CPU or GPU). Using buffers\nis typically the preferred approach because this ensures that the\nallocation requirements are fulfilled regardless of device type. To\ncreate a new data buffer with memory allocated and owned by the device,\nuse\n\n``` cpp\nOIDNBuffer oidnNewBuffer(OIDNDevice device, size_t byteSize);\n```\n\nThe created buffer is bound to the specified device (`device` argument).\nThe specified number of bytes (`byteSize`) are allocated at buffer\nconstruction time and deallocated when the buffer is destroyed. The\nmemory is by default allocated as managed memory automatically migrated\nbetween host and device, if supported, or as pinned host memory\notherwise.\n\nIf this default buffer allocation is not suitable, a buffer can be\ncreated with a manually specified storage mode as well:\n\n``` cpp\nOIDNBuffer oidnNewBufferWithStorage(OIDNDevice device, size_t byteSize, OIDNStorage storage);\n```\n\nThe supported storage modes are the following:\n\n| Name                     | Description                                                                                                                                                               |\n| :----------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `OIDN_STORAGE_UNDEFINED` | undefined storage mode                                                                                                                                                    |\n| `OIDN_STORAGE_HOST`      | pinned host memory, accessible by both host and device                                                                                                                    |\n| `OIDN_STORAGE_DEVICE`    | device memory, *not* accessible by the host                                                                                                                               |\n| `OIDN_STORAGE_MANAGED`   | automatically migrated between host and device, accessible by both (*not* supported by all devices, `managedMemorySupported` device parameter must be checked before use) |\n\nSupported storage modes for buffers, i.e., valid constants of type\n`OIDNStorage`.\n\nNote that the host and device storage modes are supported by all devices\nbut managed storage is an optional feature. Before using managed\nstorage, the `managedMemorySupported` device parameter should be\nqueried.\n\nIt is also possible to create a “shared” data buffer with memory\nallocated and managed by the user with\n\n``` cpp\nOIDNBuffer oidnNewSharedBuffer(OIDNDevice device, void* devPtr, size_t byteSize);\n```\n\nwhere `devPtr` points to user-managed device-accessible memory and\n`byteSize` is its size in bytes. At buffer construction time no buffer\ndata is allocated, but the buffer data provided by the user is used. The\nbuffer data must remain valid for as long as the buffer may be used, and\nthe user is responsible to free the buffer data when no longer required.\nThe user must also ensure that the memory is accessible to the device by\nusing a supported allocation function (e.g., `sycl::malloc_device`,\n`cudaMalloc`, `hipMalloc`) and alignment (e.g., Metal requires the\nallocation to be page-aligned).\n\nBuffers can be also imported from graphics APIs as external memory, to\navoid expensive copying of data through host memory. Different types of\nexternal memory can be imported from either POSIX file descriptors or\nWin32 handles using\n\n``` cpp\nOIDNBuffer oidnNewSharedBufferFromFD(OIDNDevice device,\n                                     OIDNExternalMemoryTypeFlag fdType,\n                                     int fd, size_t byteSize);\n\nOIDNBuffer oidnNewSharedBufferFromWin32Handle(OIDNDevice device,\n                                              OIDNExternalMemoryTypeFlag handleType,\n                                              void* handle, const void* name, size_t byteSize);\n```\n\nBefore exporting memory from the graphics API, the application should\nfind a handle type which is supported by both the Open Image Denoise\ndevice (see `externalMemoryTypes` device parameter) and the graphics\nAPI. Note that different GPU vendors may support different handle types.\nTo ensure compatibility with all device types, applications should\nsupport at least `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32` on\nWindows and both `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_FD` and\n`OIDN_EXTERNAL_MEMORY_TYPE_FLAG_DMA_BUF` on Linux. All possible external\nmemory types are listed in the table below.\n\n| Name                                                | Description                                                                                                        |\n| :-------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------- |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_NONE`               |                                                                                                                    |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_FD`          | opaque POSIX file descriptor handle (recommended on Linux)                                                         |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_DMA_BUF`            | file descriptor handle for a Linux dma\\_buf (recommended on Linux)                                                 |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32`       | NT handle (recommended on Windows)                                                                                 |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32_KMT`   | global share (KMT) handle                                                                                          |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_D3D11_TEXTURE`      | NT handle returned by `IDXGIResource1::CreateSharedHandle` referring to a Direct3D 11 texture resource             |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_D3D11_TEXTURE_KMT`  | global share (KMT) handle returned by `IDXGIResource::GetSharedHandle` referring to a Direct3D 11 texture resource |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_D3D11_RESOURCE`     | NT handle returned by `IDXGIResource1::CreateSharedHandle` referring to a Direct3D 11 resource                     |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_D3D11_RESOURCE_KMT` | global share (KMT) handle returned by `IDXGIResource::GetSharedHandle` referring to a Direct3D 11 resource         |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_D3D12_HEAP`         | NT handle returned by `ID3D12Device::CreateSharedHandle` referring to a Direct3D 12 heap resource                  |\n| `OIDN_EXTERNAL_MEMORY_TYPE_FLAG_D3D12_RESOURCE`     | NT handle returned by `ID3D12Device::CreateSharedHandle` referring to a Direct3D 12 committed resource             |\n\nSupported external memory type flags, i.e., valid constants of type\n`OIDNExternalMemoryTypeFlag`.\n\nMetal buffers can be imported directly with\n\n``` cpp\nOIDNBuffer oidnNewSharedBufferFromMetal(OIDNDevice device, MTLBuffer_id buffer);\n```\n\nNote that if a buffer with an `MTLStorageModeManaged` storage mode is\nimported, it is the responsibility of the user to synchronize the\ncontents of the buffer between the host and the device.\n\nSimilar to device objects, buffer objects are also reference-counted and\ncan be retained and released by calling the following functions:\n\n``` cpp\nvoid oidnRetainBuffer (OIDNBuffer buffer);\nvoid oidnReleaseBuffer(OIDNBuffer buffer);\n```\n\nThe size of in bytes and storage mode of the buffer can be queried using\n\n``` cpp\nsize_t      oidnGetBufferSize   (OIDNBuffer buffer);\nOIDNStorage oidnGetBufferStorage(OIDNBuffer buffer);\n```\n\nIt is possible to get a pointer directly to the buffer data, which is\nusually the preferred way to access the data stored in the buffer:\n\n``` cpp\nvoid* oidnGetBufferData(OIDNBuffer buffer);\n```\n\nAccessing the data on the host through this pointer is possible *only*\nif the buffer was created with `OIDN_STORAGE_HOST` or\n`OIDN_STORAGE_MANAGED`. Note that a `NULL` pointer may be returned if\nthe buffer is empty.\n\nIn some cases better performance can be achieved by using device storage\nfor buffers. Such data can be accessed on the host by copying to/from\nhost memory (including pageable system memory) using the following\nfunctions:\n\n``` cpp\nvoid oidnReadBuffer(OIDNBuffer buffer,\n                    size_t byteOffset, size_t byteSize, void* dstHostPtr);\n\nvoid oidnWriteBuffer(OIDNBuffer buffer,\n                     size_t byteOffset, size_t byteSize, const void* srcHostPtr);\n```\n\nThese functions will always block until the read/write operation has\nbeen completed, which is often suboptimal. The following functions\nexecute these operations asynchronously:\n\n``` cpp\nvoid oidnReadBufferAsync(OIDNBuffer buffer,\n                         size_t byteOffset, size_t byteSize, void* dstHostPtr);\n\nvoid oidnWriteBufferAsync(OIDNBuffer buffer,\n                          size_t byteOffset, size_t byteSize, const void* srcHostPtr);\n```\n\nWhen copying asynchronously, the user must ensure correct\nsynchronization with the device by calling `oidnSyncDevice` before\naccessing the copied data or releasing the buffer. Failure to do so will\nresult in undefined behavior.\n\n### Data Format\n\nBuffers store opaque data and thus have no information about the type\nand format of the data. Other objects, e.g. filters, typically require\nspecifying the format of the data stored in buffers or shared via\npointers. This can be done using the `OIDNFormat` enumeration type:\n\n| Name                     | Description                                  |\n| :----------------------- | :------------------------------------------- |\n| `OIDN_FORMAT_UNDEFINED`  | undefined format                             |\n| `OIDN_FORMAT_FLOAT`      | 32-bit floating-point scalar                 |\n| `OIDN_FORMAT_FLOAT[234]` | 32-bit floating-point \\[234\\]-element vector |\n| `OIDN_FORMAT_HALF`       | 16-bit floating-point scalar                 |\n| `OIDN_FORMAT_HALF[234]`  | 16-bit floating-point \\[234\\]-element vector |\n\nSupported data formats, i.e., valid constants of type `OIDNFormat`.\n\n## Filters\n\nFilters are the main objects in Open Image Denoise that are responsible\nfor the actual denoising. The library ships with a collection of filters\nwhich are optimized for different types of images and use cases. To\ncreate a filter object, call\n\n``` cpp\nOIDNFilter oidnNewFilter(OIDNDevice device, const char* type);\n```\n\nwhere `type` is the name of the filter type to create. The supported\nfilter types are documented later in this section.\n\nCreating filter objects can be very expensive, therefore it is\n*strongly* recommended to reuse the same filter for denoising as many\nimages as possible, as long as the these images have the same same size,\nformat, and features (i.e., only the memory locations and pixel values\nmay be different). Otherwise (e.g. for images with different\nresolutions), reusing the same filter would not have any benefits.\n\nOnce created, filter objects can be retained and released with\n\n``` cpp\nvoid oidnRetainFilter (OIDNFilter filter);\nvoid oidnReleaseFilter(OIDNFilter filter);\n```\n\nAfter creating a filter, it needs to be set up by specifying the input\nand output images, and potentially setting other parameter values as\nwell.\n\nTo set image parameters of a filter, you can use one of the following\nfunctions:\n\n``` cpp\nvoid oidnSetFilterImage(OIDNFilter filter, const char* name,\n                        OIDNBuffer buffer, OIDNFormat format,\n                        size_t width, size_t height,\n                        size_t byteOffset,\n                        size_t pixelByteStride, size_t rowByteStride);\n\nvoid oidnSetSharedFilterImage(OIDNFilter filter, const char* name,\n                              void* devPtr, OIDNFormat format,\n                              size_t width, size_t height,\n                              size_t byteOffset,\n                              size_t pixelByteStride, size_t rowByteStride);\n```\n\nIt is possible to specify either a data buffer object (`buffer`\nargument) with the `oidnSetFilterImage` function, or directly a pointer\nto user-managed device-accessible data (`devPtr` argument) with the\n`oidnSetSharedFilterImage` function. Regardless of whether a buffer or a\npointer is specified, the data *must* be accessible to the device. The\neasiest way to guarantee this regardless of the device type (CPU or GPU)\nis using buffer objects.\n\nIn both cases, you must also specify the name of the image parameter to\nset (`name` argument, e.g. `\"color\"`, `\"output\"`), the pixel format\n(`format` argument), the width and height of the image in number of\npixels (`width` and `height` arguments), the starting offset of the\nimage data (`byteOffset` argument), the pixel stride (`pixelByteStride`\nargument) and the row stride (`rowByteStride` argument), in number of\nbytes.\n\nIf the pixels and/or rows are stored contiguously (tightly packed\nwithout any gaps), you can set `pixelByteStride` and/or `rowByteStride`\nto 0 to let the library compute the actual strides automatically, as a\nconvenience.\n\nImages support only `FLOAT` and `HALF` pixel formats with up to 3\nchannels. Custom image layouts with extra channels (e.g. alpha channel)\nor other data are supported as well by specifying a non-zero pixel\nstride. This way, expensive image layout conversion and copying can be\navoided but the extra channels will be ignored by the filter. If these\nchannels also need to be denoised, separate filters can be used.\n\nTo unset a previously set image parameter, returning it to a state as if\nit had not been set, call\n\n``` cpp\nvoid oidnRemoveFilterImage(OIDNFilter filter, const char* name);\n```\n\nSome special data used by filters are opaque/untyped (e.g. trained model\nweights blobs), which can be specified with the\n`oidnSetSharedFilterData` function:\n\n``` cpp\nvoid oidnSetSharedFilterData(OIDNFilter filter, const char* name,\n                             void* hostPtr, size_t byteSize);\n```\n\nThis data (`hostPtr`) must be accessible to the *host*, therefore system\nmemory allocation is suitable (i.e., there is no reason to use buffer\nobjects for allocation).\n\nModifying the contents of an opaque data parameter after setting it as a\nfilter parameter is allowed but the filter needs to be notified that the\ndata has been updated by calling\n\n``` cpp\nvoid oidnUpdateFilterData(OIDNFilter filter, const char* name);\n```\n\nUnsetting an opaque data parameter can be performed with\n\n``` cpp\nvoid oidnRemoveFilterData(OIDNFilter filter, const char* name);\n```\n\nFilters may have parameters other than buffers as well, which you can\nset and get using the following functions:\n\n``` cpp\nbool  oidnGetFilterBool (OIDNFilter filter, const char* name);\nvoid  oidnSetFilterBool (OIDNFilter filter, const char* name, bool  value);\nint   oidnGetFilterInt  (OIDNFilter filter, const char* name);\nvoid  oidnSetFilterInt  (OIDNFilter filter, const char* name, int   value);\nfloat oidnGetFilterFloat(OIDNFilter filter, const char* name);\nvoid  oidnSetFilterFloat(OIDNFilter filter, const char* name, float value);\n```\n\nFilters support a progress monitor callback mechanism that can be used\nto report progress of filter operations and to cancel them as well.\nCalling `oidnSetFilterProgressMonitorFunction` registers a progress\nmonitor callback function (`func` argument) with payload (`userPtr`\nargument) for the specified filter (`filter` argument):\n\n``` cpp\ntypedef bool (*OIDNProgressMonitorFunction)(void* userPtr, double n);\n\nvoid oidnSetFilterProgressMonitorFunction(OIDNFilter filter,\n                                          OIDNProgressMonitorFunction func,\n                                          void* userPtr);\n```\n\nOnly a single callback function can be registered per filter, and\nfurther invocations overwrite the previously set callback function.\nPassing `NULL` as function pointer disables the registered callback\nfunction. Once registered, Open Image Denoise will invoke the callback\nfunction multiple times during filter operations, by passing the payload\nas set at registration time (`userPtr` argument), and a `double` in the\nrange \\[0, 1\\] which estimates the progress of the operation (`n`\nargument). When returning `true` from the callback function, Open Image\nDenoise will continue the filter operation normally. When returning\n`false`, the library will attempt to cancel the filter operation as soon\nas possible, and if that is fulfilled, it will raise an\n`OIDN_ERROR_CANCELLED` error. Note that cancellation is not guaranteed.\n\nUsing a progress monitor callback function introduces some overhead,\nwhich may be significant on GPU devices, hurting performance. Therefore\nwe strongly recommend progress monitoring only for offline denoising,\nwhen denoising an image is expected to take several seconds.\n\nAfter setting all necessary parameters for the filter, the changes must\nbe committed by calling\n\n``` cpp\nvoid oidnCommitFilter(OIDNFilter filter);\n```\n\nThe parameters can be updated after committing the filter, but it must\nbe re-committed for any new changes to take effect. Committing major\nchanges to the filter (e.g. setting new image parameters, changing the\nimage resolution) can be expensive, and thus should not be done\nfrequently (e.g. per frame).\n\nFinally, an image can be filtered by executing the filter with\n\n``` cpp\nvoid oidnExecuteFilter(OIDNFilter filter);\n```\n\nwhich will read the input image data from the specified buffers and\nproduce the denoised output image.\n\nThis function will always block until the filtering operation has been\ncompleted. The following function executes the operation asynchronously:\n\n``` cpp\nvoid oidnExecuteFilterAsync(OIDNFilter filter);\n```\n\nFor filters created on a SYCL device it is also possible to specify\ndependent SYCL events (`depEvents` and `numDepEvents` arguments, may be\n`NULL`/0) and get a completion event as well (`doneEvent` argument, may\nbe `NULL`):\n\n``` cpp\nvoid oidnExecuteSYCLFilterAsync(OIDNFilter filter,\n                                const sycl::event* depEvents, int numDepEvents,\n                                sycl::event* doneEvent);\n```\n\nWhen filtering asynchronously, the user must ensure correct\nsynchronization with the device by calling `oidnSyncDevice` before\naccessing the output image data or releasing the filter. Failure to do\nso will result in undefined behavior.\n\nIn the following we describe the different filters that are currently\nimplemented in Open Image Denoise.\n\n### RT\n\nThe `RT` (**r**ay **t**racing) filter is a generic ray tracing denoising\nfilter which is suitable for denoising images rendered with Monte Carlo\nray tracing methods like unidirectional and bidirectional path tracing.\nIt supports depth of field and motion blur as well, but it is *not*\ntemporally stable. The filter is based on a convolutional neural network\n(CNN) and comes with a set of pre-trained models that work well with a\nwide range of ray tracing based renderers and noise levels.\n\n![](https://openimagedenoise.github.io/images/mazda_4spp_input.jpg)\nExample noisy beauty image rendered using unidirectional path tracing\n(4 samples per pixel). *Scene by\nEvermotion.*\n\n![](https://openimagedenoise.github.io/images/mazda_4spp_oidn.jpg)\nExample output beauty image denoised using prefiltered auxiliary\nfeature images (albedo and normal)\ntoo.\n\nFor denoising *beauty* images, it accepts either a low dynamic range\n(LDR) or high dynamic range (HDR) image (`color`) as the main input\nimage. In addition to this, it also accepts *auxiliary feature* images,\n`albedo` and `normal`, which are optional inputs that usually improve\nthe denoising quality significantly, preserving more details.\n\nIt is possible to denoise auxiliary images as well, in which case only\nthe respective auxiliary image has to be specified as input, instead of\nthe beauty image. This can be done as a *prefiltering* step to further\nimprove the quality of the denoised beauty image.\n\nThe `RT` filter has certain limitations regarding the supported input\nimages. Most notably, it cannot denoise images that were not rendered\nwith ray tracing. Another important limitation is related to\nanti-aliasing filters. Most renderers use a high-quality pixel\nreconstruction filter instead of a trivial box filter to minimize\naliasing artifacts (e.g. Gaussian, Blackman-Harris). The `RT` filter\ndoes support such pixel filters but only if implemented with importance\nsampling. Weighted pixel sampling (sometimes called *splatting*)\nintroduces correlation between neighboring pixels, which causes the\ndenoising to fail (the noise will not be filtered), thus it is not\nsupported.\n\nThe filter can be created by passing `\"RT\"` to the `oidnNewFilter`\nfunction as the filter type. The filter supports the parameters listed\nin the table below. All specified images must have the same dimensions.\nThe output image can be one of the input images (i.e. in-place denoising\nis supported). See section [Examples](#examples) for simple code\nsnippets that demonstrate the usage of the filter.\n\n| Type    | Name            |    Default | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| :------ | :-------------- | ---------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `Image` | `color`         | *optional* | input beauty image (1–3 channels, LDR values in \\[0, 1\\] or HDR values in \\[0, +∞), values being interpreted such that, after scaling with the `inputScale` parameter, a value of 1 corresponds to a luminance level of 100 cd/m²)                                                                                                                                                                                                                                                                          |\n| `Image` | `albedo`        | *optional* | input auxiliary image containing the albedo per pixel (1–3 channels, values in \\[0, 1\\])                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| `Image` | `normal`        | *optional* | input auxiliary image containing the shading normal per pixel (1–3 channels, world-space or view-space vectors with arbitrary length, values in \\[-1, 1\\])                                                                                                                                                                                                                                                                                                                                                  |\n| `Image` | `output`        | *required* | output image (1–3 channels); can be one of the input images                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| `Bool`  | `hdr`           |    `false` | the main input image is HDR                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| `Bool`  | `srgb`          |    `false` | the main input image is encoded with the sRGB (or 2.2 gamma) curve (LDR only) or is linear; the output will be encoded with the same curve                                                                                                                                                                                                                                                                                                                                                                  |\n| `Float` | `inputScale`    |        NaN | scales values in the main input image before filtering, without scaling the output too, which can be used to map color or auxiliary feature values to the expected range, e.g. for mapping HDR values to physical units (which affects the quality of the output but *not* the range of the output values); if set to NaN, the scale is computed implicitly for HDR images or set to 1 otherwise                                                                                                            |\n| `Bool`  | `cleanAux`      |    `false` | the auxiliary feature (albedo, normal) images are noise-free; recommended for highest quality but should *not* be enabled for noisy auxiliary images to avoid residual noise                                                                                                                                                                                                                                                                                                                                |\n| `Int`   | `quality`       |       high | image quality mode as an `OIDNQuality` value                                                                                                                                                                                                                                                                                                                                                                                                                                                                |\n| `Data`  | `weights`       | *optional* | trained model weights blob                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |\n| `Int`   | `maxMemoryMB`   |        \\-1 | if set to \\\u003e= 0, a request is made to limit the memory usage below the specified amount in megabytes at the potential cost of slower performance, but actual memory usage may be higher (the target may not be achievable or there may be additional allocations beyond the control of the library); otherwise, memory usage will be limited to an unspecified device-dependent amount; in both cases, filters on the same device share almost all of their allocated memory to minimize total memory usage |\n| `Int`   | `tileAlignment` | *constant* | when manually denoising in tiles, the tile size and offsets should be multiples of this amount of pixels to avoid artifacts; when denoising HDR images `inputScale` *must* be set by the user to avoid seam artifacts                                                                                                                                                                                                                                                                                       |\n| `Int`   | `tileOverlap`   | *constant* | when manually denoising in tiles, the tiles should overlap by this amount of pixels                                                                                                                                                                                                                                                                                                                                                                                                                         |\n\nParameters supported by the `RT` filter.\n\nUsing auxiliary feature images like albedo and normal helps preserving\nfine details and textures in the image thus can significantly improve\ndenoising quality. These images should typically contain feature values\nfor the first hit (i.e. the surface which is directly visible) per\npixel. This works well for most surfaces but does not provide any\nbenefits for reflections and objects visible through transparent\nsurfaces (compared to just using the color as input). However, this\nissue can be usually fixed by storing feature values for a subsequent\nhit (i.e. the reflection and/or refraction) instead of the first hit.\nFor example, it usually works well to follow perfect specular (*delta*)\npaths and store features for the first diffuse or glossy surface hit\ninstead (e.g. for perfect specular dielectrics and mirrors). This can\ngreatly improve the quality of reflections and transmission. We will\ndescribe this approach in more detail in the following subsections.\n\nThe auxiliary feature images should be as noise-free as possible. It is\nnot a strict requirement but too much noise in the feature images may\ncause residual noise in the output. Ideally, these should be completely\nnoise-free. If this is the case, this should be hinted to the filter\nusing the `cleanAux` parameter to ensure the highest possible image\nquality. But this parameter should be used with care: if enabled, any\nnoise present in the auxiliary images will end up in the denoised image\nas well, as residual noise. Thus, `cleanAux` should be enabled only if\nthe auxiliary images are guaranteed to be noise-free.\n\nUsually it is difficult to provide clean feature images, and some\nresidual noise might be present in the output even with `cleanAux` being\ndisabled. To eliminate this noise and to even improve the sharpness of\ntexture details, the auxiliary images should be first denoised in a\nprefiltering step, as mentioned earlier. Then, these denoised auxiliary\nimages could be used for denoising the beauty image. Since these are now\nnoise-free, the `cleanAux` parameter should be enabled. See section\n[Denoising with prefiltering (C++11\nAPI)](#denoising-with-prefiltering-c11-api) for a simple code example.\nPrefiltering makes denoising much more expensive but if there are\nmultiple color AOVs to denoise, the prefiltered auxiliary images can be\nreused for denoising multiple AOVs, amortizing the cost of the\nprefiltering step.\n\nThus, for final-frame denoising, where the best possible image quality\nis required, it is recommended to prefilter the auxiliary features if\nthey are noisy and enable the `cleanAux` parameter. Denoising with noisy\nauxiliary features should be reserved for previews and interactive\nrendering.\n\nAll auxiliary images should use the same pixel reconstruction filter as\nthe beauty image. Using a properly anti-aliased beauty image but aliased\nalbedo or normal images will likely introduce artifacts around edges.\n\n#### Albedos\n\nThe albedo image is the feature image that usually provides the biggest\nquality improvement. It should contain the approximate color of the\nsurfaces independent of illumination and viewing angle.\n\n![](https://openimagedenoise.github.io/images/mazda_firsthit_512spp_albedo.jpg)\nExample albedo image obtained using the first hit. Note that the\nalbedos of all transparent surfaces are\n1.\n\n![](https://openimagedenoise.github.io/images/mazda_nondeltahit_512spp_albedo.jpg)\nExample albedo image obtained using the first diffuse or glossy\n(non-delta) hit. Note that the albedos of perfect specular (delta)\ntransparent surfaces are computed as the Fresnel blend of the reflected\nand transmitted\nalbedos.\n\nFor simple matte surfaces this means using the diffuse color/texture as\nthe albedo. For other, more complex surfaces it is not always obvious\nwhat is the best way to compute the albedo, but the denoising filter is\nflexible to a certain extent and works well with differently computed\nalbedos. Thus it is not necessary to compute the strict, exact albedo\nvalues but must be always between 0 and 1.\n\nFor metallic surfaces the albedo should be either the reflectivity at\nnormal incidence (e.g. from the artist friendly metallic Fresnel model)\nor the average reflectivity; or if these are constant (not textured) or\nunknown, the albedo can be simply 1 as well.\n\nThe albedo for dielectric surfaces (e.g. glass) should be either 1 or,\nif the surface is perfect specular (i.e. has a delta BSDF), the Fresnel\nblend of the reflected and transmitted albedos. The latter usually works\nbetter but only if it does not introduce too much noise or the albedo is\nprefiltered. If noise is an issue, we recommend to split the path into a\nreflected and a transmitted path at the first hit, and perhaps fall back\nto an albedo of 1 for subsequent dielectric hits. The reflected albedo\nin itself can be used for mirror-like surfaces as well.\n\nThe albedo for layered surfaces can be computed as the weighted sum of\nthe albedos of the individual layers. Non-absorbing clear coat layers\ncan be simply ignored (or the albedo of the perfect specular reflection\ncan be used as well) but absorption should be taken into account.\n\n#### Normals\n\nThe normal image should contain the shading normals of the surfaces\neither in world-space or view-space. It is recommended to include normal\nmaps to preserve as much detail as possible.\n\n![](https://openimagedenoise.github.io/images/mazda_firsthit_512spp_normal.jpg)\nExample normal image obtained using the first hit (the values are\nactually in \\[−1, 1\\] but were mapped to \\[0, 1\\] for illustration\npurposes).\n\n![](https://openimagedenoise.github.io/images/mazda_nondeltahit_512spp_normal.jpg)\nExample normal image obtained using the first diffuse or glossy\n(non-delta) hit. Note that the normals of perfect specular (delta)\ntransparent surfaces are computed as the Fresnel blend of the reflected\nand transmitted\nnormals.\n\nJust like any other input image, the normal image should be anti-aliased\n(i.e. by accumulating the normalized normals per pixel). The final\naccumulated normals do not have to be normalized but must be in the\n\\[-1, 1\\] range (i.e. normals mapped to \\[0, 1\\] are *not* acceptable\nand must be remapped to \\[−1, 1\\]).\n\nSimilar to the albedo, the normal can be stored for either the first or\na subsequent hit (if the first hit has a perfect specular/delta BSDF).\n\n#### Quality\n\nThe filter supports setting an image quality mode, which determines\nwhether to favor quality, performance, or have a balanced solution\nbetween the two. The supported quality modes are listed in the following\ntable.\n\n| Name                    | Description                                                        |\n| :---------------------- | :----------------------------------------------------------------- |\n| `OIDN_QUALITY_DEFAULT`  | default quality                                                    |\n| `OIDN_QUALITY_FAST`     | high performance (for interactive/real-time preview rendering)     |\n| `OIDN_QUALITY_BALANCED` | balanced quality/performance (for interactive/real-time rendering) |\n| `OIDN_QUALITY_HIGH`     | high quality (for final-frame rendering); *default*                |\n\nSupported image quality modes, i.e., valid constants of type\n`OIDNQuality`.\n\nBy default, filtering is performed in *high* quality mode, which is\nrecommended for final-frame rendering. Using this setting the results\nhave the same high quality regardless of what kind of device (CPU or\nGPU) is used. However, due to significant hardware architecture\ndifferences between devices, there might be small numerical differences\nbetween the produced outputs.\n\nThe *balanced* quality mode may provide somewhat lower image quality but\nhigher performance and lower default memory usage, and is thus\nrecommended for interactive and real-time rendering. For even higher\nperformance and lower memory usage, a *fast* quality mode is also\navailable but has noticeably lower image quality, making it suitable\nmainly for fast previews. Note that in the *balanced* and *fast* quality\nmodes larger numerical differences should be expected across devices\ncompared to the *high* quality mode.\n\nThe difference in quality and performance between quality modes depends\non the combination of input features, parameters (e.g. `cleanAux`), and\nthe device architecture. In some cases the difference may be small or\neven none.\n\n#### Weights\n\nInstead of using the built-in trained models for filtering, it is also\npossible to specify user-trained models at runtime. This can be achieved\nby passing the model *weights* blob corresponding to the specified set\nof features and other filter parameters, produced by the included\ntraining tool. See Section [Training](#training) for details.\n\n### RTLightmap\n\nThe `RTLightmap` filter is a variant of the `RT` filter optimized for\ndenoising HDR and normalized directional (e.g. spherical harmonics)\nlightmaps. It does not support LDR images.\n\nThe filter can be created by passing `\"RTLightmap\"` to the\n`oidnNewFilter` function as the filter type. The filter supports the\nfollowing parameters:\n\n| Type    | Name            |    Default | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| :------ | :-------------- | ---------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `Image` | `color`         | *required* | input beauty image (1–3 channels, HDR values in \\[0, +∞), interpreted such that, after scaling with the `inputScale` parameter, a value of 1 corresponds to a luminance level of 100 cd/m²; directional values in \\[-1, 1\\])                                                                                                                                                                                                                                                                                |\n| `Image` | `output`        | *required* | output image (1–3 channels); can be one of the input images                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| `Bool`  | `directional`   |    `false` | whether the input contains normalized coefficients (in \\[-1, 1\\]) of a directional lightmap (e.g. normalized L1 or higher spherical harmonics band with the L0 band divided out); if the range of the coefficients is different from \\[-1, 1\\], the `inputScale` parameter can be used to adjust the range without changing the stored values                                                                                                                                                               |\n| `Float` | `inputScale`    |        NaN | scales input color values before filtering, without scaling the output too, which can be used to map color values to the expected range, e.g. for mapping HDR values to physical units (which affects the quality of the output but *not* the range of the output values); if set to NaN, the scale is computed implicitly for HDR images or set to 1 otherwise                                                                                                                                             |\n| `Int`   | `quality`       |       high | image quality mode as an `OIDNQuality` value                                                                                                                                                                                                                                                                                                                                                                                                                                                                |\n| `Data`  | `weights`       | *optional* | trained model weights blob                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |\n| `Int`   | `maxMemoryMB`   |        \\-1 | if set to \\\u003e= 0, a request is made to limit the memory usage below the specified amount in megabytes at the potential cost of slower performance, but actual memory usage may be higher (the target may not be achievable or there may be additional allocations beyond the control of the library); otherwise, memory usage will be limited to an unspecified device-dependent amount; in both cases, filters on the same device share almost all of their allocated memory to minimize total memory usage |\n| `Int`   | `tileAlignment` | *constant* | when manually denoising in tiles, the tile size and offsets should be multiples of this amount of pixels to avoid artifacts; when denoising HDR images `inputScale` *must* be set by the user to avoid seam artifacts                                                                                                                                                                                                                                                                                       |\n| `Int`   | `tileOverlap`   | *constant* | when manually denoising in tiles, the tiles should overlap by this amount of pixels                                                                                                                                                                                                                                                                                                                                                                                                                         |\n\nParameters supported by the `RTLightmap` filter.\n\n# Examples\n\nIntel Open Image Denoise ships with a couple of simple example\napplications.\n\n## oidnDenoise\n\n`oidnDenoise` is a minimal working example demonstrating how to use\nIntel Open Image Denoise, which can be found at `apps/oidnDenoise.cpp`.\nIt uses the C++11 convenience wrappers of the C99 API.\n\nThis example is a simple command-line application that denoises the\nprovided image, which can optionally have auxiliary feature images as\nwell (e.g. albedo and normal). By default the images must be stored in\nthe [Portable FloatMap](http://www.pauldebevec.com/Research/HDR/PFM/)\n(PFM) format, and the color values must be encoded in little-endian\nformat. To enable other image formats (e.g. OpenEXR, PNG) as well, the\nproject has to be rebuilt with OpenImageIO support enabled.\n\nRunning `oidnDenoise` without any arguments or the `-h` argument will\nbring up a list of command-line options.\n\n## oidnBenchmark\n\n`oidnBenchmark` is a basic command-line benchmarking application for\nmeasuring denoising speed, which can be found at\n`apps/oidnBenchmark.cpp`.\n\nRunning `oidnBenchmark` with the `-h` argument will bring up a list of\ncommand-line options.\n\n# Training\n\nThe Intel Open Image Denoise source distribution includes a Python-based\nneural network train","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenderkit%2Foidn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frenderkit%2Foidn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenderkit%2Foidn/lists"}