diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5e78c2e17e1bec995cff77cbbe6790ee8c71073d..8bbe173f8aa4e5722871c99ebc602e08640954d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -762,6 +762,9 @@ oneAPI targets to build AOT binaries for"
mark_as_advanced(CYCLES_ONEAPI_SYCL_TARGETS)
endif()
+# ANARI
+option(WITH_CYCLES_DEVICE_ANARI "Enable Cycles ANARI compute support" ON)
+
# Draw Manager
option(WITH_DRAW_DEBUG "Add extra debug capabilities to Draw Manager" OFF)
mark_as_advanced(WITH_DRAW_DEBUG)
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index 49b9b5bf88832d54ca55019d7bb6bd5f9c49ec9d..fbbbf00a2ea5063e985a10e3a1c0c667a458c23e 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -244,6 +244,10 @@ if(WITH_CYCLES_DEVICE_CUDA OR WITH_CYCLES_DEVICE_OPTIX)
endif()
endif()
+if(WITH_CYCLES_DEVICE_ANARI)
+ add_definitions(-DWITH_ANARI)
+endif()
+
if(WITH_CYCLES_DEVICE_HIP)
add_definitions(-DWITH_HIP)
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 92d73a1de075774a0755beabedac36fd32aff41f..1163f01af564f558da34b863ae75b30d635b15b4 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -15,7 +15,7 @@ def _configure_argument_parser():
action='store_true')
parser.add_argument("--cycles-device",
help="Set the device to use for Cycles, overriding user preferences and the scene setting."
- "Valid options are 'CPU', 'CUDA', 'OPTIX', 'HIP', 'ONEAPI', or 'METAL'."
+ "Valid options are 'CPU', 'CUDA', 'OPTIX', 'HIP', 'ONEAPI', 'METAL' or 'ANARI'."
"Additionally, you can append '+CPU' to any GPU type for hybrid rendering.",
default=None)
return parser
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 33d0407818f7ea406f7809117373ae9b2e509432..ee136c699209d50e710ad6d7ee11ba0ead44048d 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -179,7 +179,8 @@ enum_device_type = (
('OPTIX', "OptiX", "OptiX", 3),
('HIP', "HIP", "HIP", 4),
('METAL', "Metal", "Metal", 5),
- ('ONEAPI', "oneAPI", "oneAPI", 6)
+ ('ONEAPI', "oneAPI", "oneAPI", 6),
+ ('ANARI', "ANARI", "ANARI", 7)
)
enum_texture_limit = (
@@ -1539,7 +1540,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_device_types(self, context):
import _cycles
- has_cuda, has_optix, has_hip, has_metal, has_oneapi, has_hiprt = _cycles.get_device_types()
+ has_cuda, has_optix, has_hip, has_metal, has_oneapi, has_hiprt, has_anari = _cycles.get_device_types()
list = [('NONE', "None", "Don't use compute device", 0)]
if has_cuda:
@@ -1552,6 +1553,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
list.append(('METAL', "Metal", "Use Metal for GPU acceleration", 5))
if has_oneapi:
list.append(('ONEAPI', "oneAPI", "Use oneAPI for GPU acceleration", 6))
+ if has_anari:
+ list.append(('ANARI', "ANARI", "Use ANARI for acceleration", 7))
return list
@@ -1626,7 +1629,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def update_device_entries(self, device_list):
for device in device_list:
- if not device[1] in {'CUDA', 'OPTIX', 'CPU', 'HIP', 'METAL', 'ONEAPI'}:
+ if not device[1] in {'CUDA', 'OPTIX', 'CPU', 'HIP', 'METAL', 'ONEAPI', 'ANARI'}:
continue
# Try to find existing Device entry
entry = self.find_existing_device_entry(device)
@@ -1665,7 +1668,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def refresh_devices(self):
# Ensure `self.devices` is not re-allocated when the second call to
# get_devices_for_type is made, freeing items from the first list.
- for device_type in ('CUDA', 'OPTIX', 'HIP', 'METAL', 'ONEAPI'):
+ for device_type in ('CUDA', 'OPTIX', 'HIP', 'METAL', 'ONEAPI', 'ANARI'):
# Query the device list to trigger all required updates.
# Note that even though the device list is unused,
# the function has side-effects with internal state updates.
@@ -1809,6 +1812,9 @@ class CyclesPreferences(bpy.types.AddonPreferences):
mac_version = "12.2"
col.label(text=rpt_("Requires Apple Silicon with macOS %s or newer") % mac_version,
icon='BLANK1', translate=False)
+ elif device_type == 'ANARI':
+ pass
+
return
for device in devices:
@@ -1881,6 +1887,9 @@ class CyclesPreferences(bpy.types.AddonPreferences):
row.active = has_hardware_rt
row.prop(self, "use_oneapirt")
+ elif compute_device_type == 'ANARI':
+ row = layout.row()
+
def draw(self, context):
self.draw_impl(self.layout, context)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index b93ba9bba9b50eb32b3e1f20b5407c719e59d2b3..7659f2a163c994117f8adc320ec1a08aacb2a8bd 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -132,6 +132,8 @@ def use_optix(context):
def use_oneapi(context):
return (get_device_type(context) == 'ONEAPI' and use_gpu(context))
+def use_anari(context):
+ return (get_device_type(context) == 'ANARI' and use_gpu(context))
def use_multi_device(context):
if use_gpu(context):
diff --git a/intern/cycles/blender/device.cpp b/intern/cycles/blender/device.cpp
index 9cb70805be22c622b734ade565969531c16a5105..e5a672a3aa062a7acff65f256da0edf15523c6aa 100644
--- a/intern/cycles/blender/device.cpp
+++ b/intern/cycles/blender/device.cpp
@@ -15,6 +15,7 @@ enum ComputeDevice {
COMPUTE_DEVICE_HIP = 4,
COMPUTE_DEVICE_METAL = 5,
COMPUTE_DEVICE_ONEAPI = 6,
+ COMPUTE_DEVICE_ANARI = 7,
COMPUTE_DEVICE_NUM
};
@@ -123,6 +124,9 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences,
else if (compute_device == COMPUTE_DEVICE_ONEAPI) {
mask |= DEVICE_MASK_ONEAPI;
}
+ else if (compute_device == COMPUTE_DEVICE_ANARI) {
+ mask |= DEVICE_MASK_ANARI;
+ }
const vector<DeviceInfo> devices = Device::available_devices(mask);
/* Match device preferences and available devices. */
diff --git a/intern/cycles/blender/python.cpp b/intern/cycles/blender/python.cpp
index ee4cba477e3d78c6a5ed8555334f55856dde497e..603681ed8862a1de20e8bfebee92d2ce1f4dfc62 100644
--- a/intern/cycles/blender/python.cpp
+++ b/intern/cycles/blender/python.cpp
@@ -676,6 +676,7 @@ static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
bool has_metal = false;
bool has_oneapi = false;
bool has_hiprt = false;
+ bool has_anari = false;
for (const DeviceType device_type : device_types) {
has_cuda |= (device_type == DEVICE_CUDA);
has_optix |= (device_type == DEVICE_OPTIX);
@@ -683,14 +684,16 @@ static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
has_metal |= (device_type == DEVICE_METAL);
has_oneapi |= (device_type == DEVICE_ONEAPI);
has_hiprt |= (device_type == DEVICE_HIPRT);
+ has_anari |= (device_type == DEVICE_ANARI);
}
- PyObject *list = PyTuple_New(6);
+ PyObject *list = PyTuple_New(7);
PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_hip));
PyTuple_SET_ITEM(list, 3, PyBool_FromLong(has_metal));
PyTuple_SET_ITEM(list, 4, PyBool_FromLong(has_oneapi));
PyTuple_SET_ITEM(list, 5, PyBool_FromLong(has_hiprt));
+ PyTuple_SET_ITEM(list, 6, PyBool_FromLong(has_anari));
return list;
}
@@ -725,6 +728,9 @@ static PyObject *set_device_override_func(PyObject * /*self*/, PyObject *arg)
else if (override == "ONEAPI") {
BlenderSession::device_override = DEVICE_MASK_ONEAPI;
}
+ else if (override == "ANARI") {
+ BlenderSession::device_override = DEVICE_MASK_ANARI;
+ }
else {
fprintf(stderr, "\nError: %s is not a valid Cycles device.\n", override.c_str());
Py_RETURN_FALSE;
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index aa9dbd151fde3bb94883cb7d067fda0a2cb231cb..1b4eb30dd3a00949f5d55211ec76d41ccf9cc675 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -128,3 +128,12 @@ if(WITH_CYCLES_DEVICE_ONEAPI AND WITH_CYCLES_ONEAPI_BINARIES)
set_and_warn_library_found("ocloc" OCLOC_FOUND WITH_CYCLES_ONEAPI_BINARIES)
endif()
endif()
+
+
+#####################################################
+# ANARI
+#####################################################
+
+if(WITH_CYCLES_DEVICE_ANARI)
+ find_package(anari 0.8.0)
+endif()
\ No newline at end of file
diff --git a/intern/cycles/cmake/macros.cmake b/intern/cycles/cmake/macros.cmake
index 348ae3b3709a3b83491340386a1f71991909302d..4cd53be7b11c4b82b4cfd3fcee38bd7e33a1dca6 100644
--- a/intern/cycles/cmake/macros.cmake
+++ b/intern/cycles/cmake/macros.cmake
@@ -169,6 +169,10 @@ macro(cycles_external_libraries_append libraries)
endif()
endif()
+ if(WITH_CYCLES_DEVICE_ANARI)
+ list(APPEND ${libraries} anari::anari)
+ endif()
+
if(WITH_CYCLES_DEVICE_HIP AND WITH_HIP_DYNLOAD)
list(APPEND ${libraries} extern_hipew)
endif()
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 431ae7a80d414127f7611b17f0ed643e369ec9e7..73591c0462d776b33b945ba60d20f2acd9be1f63 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -116,6 +116,13 @@ set(SRC_OPTIX
optix/util.h
)
+set(SRC_ANARI
+ anari/device.cpp
+ anari/device.h
+ anari/device_impl.cpp
+ anari/device_impl.h
+)
+
set(SRC_HEADERS
device.h
denoise.h
@@ -134,6 +141,7 @@ set(SRC
${SRC_DUMMY}
${SRC_MULTI}
${SRC_OPTIX}
+ ${SRC_ANARI}
${SRC_HEADERS}
)
@@ -228,4 +236,5 @@ source_group("multi" FILES ${SRC_MULTI})
source_group("metal" FILES ${SRC_METAL})
source_group("optix" FILES ${SRC_OPTIX})
source_group("oneapi" FILES ${SRC_ONEAPI})
+source_group("anari" FILES ${SRC_ANARI})
source_group("common" FILES ${SRC_BASE} ${SRC_HEADERS})
diff --git a/intern/cycles/device/anari/device.cpp b/intern/cycles/device/anari/device.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..929d2e3e8ac4ad5865803855bbd27e43bc5b9595
--- /dev/null
+++ b/intern/cycles/device/anari/device.cpp
@@ -0,0 +1,64 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+#include "device/anari/device.h"
+#include "device/anari/device_impl.h"
+#include "device/device.h"
+
+/* Used for `info.denoisers`. */
+/* TODO(sergey): The denoisers are probably to be moved completely out of the device into their
+ * own class. But until then keep API consistent with how it used to work before. */
+// #include "util/guiding.h"
+// #include "util/openimagedenoise.h"
+
+CCL_NAMESPACE_BEGIN
+
+bool device_anari_init()
+{
+ return true;
+}
+
+unique_ptr<Device> device_anari_create(const DeviceInfo &info,
+ Stats &stats,
+ Profiler &profiler,
+ bool headless)
+{
+ return make_unique<ANARIDevice>(info, stats, profiler, headless);
+}
+
+void device_anari_info(vector<DeviceInfo> &devices)
+{
+ DeviceInfo info;
+
+ info.type = DEVICE_ANARI;
+ info.description = "ANARI";//system_cpu_brand_string();
+ info.id = "ANARI";
+ info.num = 0;
+ info.has_osl = false;
+ info.has_nanovdb = false;
+ info.has_profiling = false;
+ // if (guiding_supported()) {
+ // info.has_guiding = true;
+ // }
+ // else {
+ info.has_guiding = false;
+ //}
+ // if (openimagedenoise_supported()) {
+ // info.denoisers |= DENOISER_OPENIMAGEDENOISE;
+ // }
+
+ devices.insert(devices.begin(), info);
+}
+
+string device_anari_capabilities()
+{
+ string capabilities = "";
+ // capabilities += system_cpu_support_avx2() ? "AVX2" : "";
+ // if (capabilities[capabilities.size() - 1] == ' ') {
+ // capabilities.resize(capabilities.size() - 1);
+ // }
+ return capabilities;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/anari/device.h b/intern/cycles/device/anari/device.h
new file mode 100644
index 0000000000000000000000000000000000000000..d83dd784ddca3963ed00014da2da4471ca680fff
--- /dev/null
+++ b/intern/cycles/device/anari/device.h
@@ -0,0 +1,29 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+#pragma once
+
+#include "util/string.h"
+#include "util/unique_ptr.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceInfo;
+class Profiler;
+class Stats;
+
+bool device_anari_init();
+
+unique_ptr<Device> device_anari_create(const DeviceInfo &info,
+ Stats &stats,
+ Profiler &profiler,
+ bool headless);
+
+void device_anari_info(vector<DeviceInfo> &devices);
+
+string device_anari_capabilities();
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/anari/device_impl.cpp b/intern/cycles/device/anari/device_impl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d5db77c6feac8ae695cf595786215230dd7a333b
--- /dev/null
+++ b/intern/cycles/device/anari/device_impl.cpp
@@ -0,0 +1,323 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+#include "device/anari/device_impl.h"
+
+#include <cstdlib>
+#include <cstring>
+
+// /* So ImathMath is included before our kernel_cpu_compat. */
+// #ifdef WITH_OSL
+// /* So no context pollution happens from indirectly included windows.h */
+// # ifdef _WIN32
+// # include "util/windows.h"
+// # endif
+// # include <OSL/oslexec.h>
+// #endif
+
+// #ifdef WITH_EMBREE
+// # if EMBREE_MAJOR_VERSION >= 4
+// # include <embree4/rtcore.h>
+// # else
+// # include <embree3/rtcore.h>
+// # endif
+// #endif
+
+//#include "device/anari/kernel.h"
+
+#include "device/device.h"
+
+#include "kernel/device/anari/kernel.h"
+#include "kernel/globals.h"
+#include "kernel/types.h"
+
+//#include "bvh/embree.h"
+
+#include "session/buffers.h"
+
+#include "util/guiding.h"
+#include "util/log.h"
+#include "util/progress.h"
+#include "util/task.h"
+
+CCL_NAMESPACE_BEGIN
+
+ANARIDevice::ANARIDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_, bool headless_)
+ : Device(info_, stats_, profiler_, headless_), texture_info(this, "texture_info", MEM_GLOBAL)
+{
+ /* Pick any kernel, all of them are supposed to have same level of microarchitecture
+ * optimization. */
+ //VLOG_INFO << "Using " << get_cpu_kernels().integrator_init_from_camera.get_uarch_name()
+ // << " CPU kernels.";
+
+ if (info.cpu_threads == 0) {
+ info.cpu_threads = TaskScheduler::max_concurrency();
+ }
+
+// #ifdef WITH_EMBREE
+// embree_device = rtcNewDevice("verbose=0");
+// #endif
+ need_texture_info = false;
+}
+
+ANARIDevice::~ANARIDevice()
+{
+// #ifdef WITH_EMBREE
+// rtcReleaseDevice(embree_device);
+// #endif
+
+ texture_info.free();
+}
+
+BVHLayoutMask ANARIDevice::get_bvh_layout_mask(uint /*kernel_features*/) const
+{
+ BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_BVH2;
+// #ifdef WITH_EMBREE
+// bvh_layout_mask |= BVH_LAYOUT_EMBREE;
+// #endif /* WITH_EMBREE */
+ return bvh_layout_mask;
+}
+
+bool ANARIDevice::load_texture_info()
+{
+ if (!need_texture_info) {
+ return false;
+ }
+
+ texture_info.copy_to_device();
+ need_texture_info = false;
+
+ return true;
+}
+
+void ANARIDevice::mem_alloc(device_memory &mem)
+{
+ if (mem.type == MEM_TEXTURE) {
+ assert(!"mem_alloc not supported for textures.");
+ }
+ else if (mem.type == MEM_GLOBAL) {
+ assert(!"mem_alloc not supported for global memory.");
+ }
+ else {
+ //if (mem.name) {
+ // VLOG_WORK << "Buffer allocate: " << mem.name << ", "
+ // << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ // << string_human_readable_size(mem.memory_size()) << ")";
+ //}
+
+ if (mem.type == MEM_DEVICE_ONLY) {
+ size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES;
+ void *data = util_aligned_malloc(mem.memory_size(), alignment);
+ mem.device_pointer = (device_ptr)data;
+ }
+ else {
+ assert(!(mem.host_pointer == nullptr && mem.memory_size() > 0));
+ mem.device_pointer = (device_ptr)mem.host_pointer;
+ }
+
+ mem.device_size = mem.memory_size();
+ stats.mem_alloc(mem.device_size);
+ }
+}
+
+void ANARIDevice::mem_copy_to(device_memory &mem)
+{
+ if (mem.type == MEM_GLOBAL) {
+ global_free(mem);
+ global_alloc(mem);
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free((device_texture &)mem);
+ tex_alloc((device_texture &)mem);
+ }
+ else {
+ if (!mem.device_pointer) {
+ mem_alloc(mem);
+ }
+
+ /* copy is no-op */
+ }
+}
+
+void ANARIDevice::mem_move_to_host(device_memory & /*mem*/)
+{
+ /* no-op */
+}
+
+void ANARIDevice::mem_copy_from(
+ device_memory & /*mem*/, size_t /*y*/, size_t /*w*/, size_t /*h*/, size_t /*elem*/)
+{
+ /* no-op */
+}
+
+void ANARIDevice::mem_zero(device_memory &mem)
+{
+ if (!mem.device_pointer) {
+ mem_alloc(mem);
+ }
+
+ if (mem.device_pointer) {
+ memset((void *)mem.device_pointer, 0, mem.memory_size());
+ }
+}
+
+void ANARIDevice::mem_free(device_memory &mem)
+{
+ if (mem.type == MEM_GLOBAL) {
+ global_free(mem);
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free((device_texture &)mem);
+ }
+ else if (mem.device_pointer) {
+ if (mem.type == MEM_DEVICE_ONLY) {
+ util_aligned_free((void *)mem.device_pointer, mem.memory_size());
+ }
+ mem.device_pointer = 0;
+ stats.mem_free(mem.device_size);
+ mem.device_size = 0;
+ }
+}
+
+device_ptr ANARIDevice::mem_alloc_sub_ptr(device_memory &mem, const size_t offset, size_t /*size*/)
+{
+ return (device_ptr)(((char *)mem.device_pointer) + mem.memory_elements_size(offset));
+}
+
+void ANARIDevice::const_copy_to(const char *name, void *host, const size_t size)
+{
+// #ifdef WITH_EMBREE
+// if (strcmp(name, "data") == 0) {
+// assert(size <= sizeof(KernelData));
+
+// // Update scene handle (since it is different for each device on multi devices)
+// KernelData *const data = (KernelData *)host;
+// data->device_bvh = embree_scene;
+// }
+// #endif
+ //kernel_const_copy(&kernel_globals, name, host, size);
+}
+
+void ANARIDevice::global_alloc(device_memory &mem)
+{
+ //VLOG_WORK << "Global memory allocate: " << mem.name << ", "
+ // << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ // << string_human_readable_size(mem.memory_size()) << ")";
+
+ //kernel_global_memory_copy(&kernel_globals, mem.name, mem.host_pointer, mem.data_size);
+
+ mem.device_pointer = (device_ptr)mem.host_pointer;
+ mem.device_size = mem.memory_size();
+ stats.mem_alloc(mem.device_size);
+}
+
+void ANARIDevice::global_free(device_memory &mem)
+{
+ if (mem.device_pointer) {
+ mem.device_pointer = 0;
+ stats.mem_free(mem.device_size);
+ mem.device_size = 0;
+ }
+}
+
+void ANARIDevice::tex_alloc(device_texture &mem)
+{
+ //VLOG_WORK << "Texture allocate: " << mem.name << ", "
+ // << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ // << string_human_readable_size(mem.memory_size()) << ")";
+
+ mem.device_pointer = (device_ptr)mem.host_pointer;
+ mem.device_size = mem.memory_size();
+ stats.mem_alloc(mem.device_size);
+
+ const uint slot = mem.slot;
+ if (slot >= texture_info.size()) {
+ /* Allocate some slots in advance, to reduce amount of re-allocations. */
+ texture_info.resize(slot + 128);
+ }
+
+ texture_info[slot] = mem.info;
+ texture_info[slot].data = (uint64_t)mem.host_pointer;
+ need_texture_info = true;
+}
+
+void ANARIDevice::tex_free(device_texture &mem)
+{
+ if (mem.device_pointer) {
+ mem.device_pointer = 0;
+ stats.mem_free(mem.device_size);
+ mem.device_size = 0;
+ need_texture_info = true;
+ }
+}
+
+void ANARIDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
+{
+// #ifdef WITH_EMBREE
+// if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE ||
+// bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE ||
+// bvh->params.bvh_layout == BVH_LAYOUT_MULTI_METAL_EMBREE ||
+// bvh->params.bvh_layout == BVH_LAYOUT_MULTI_HIPRT_EMBREE ||
+// bvh->params.bvh_layout == BVH_LAYOUT_MULTI_EMBREEGPU_EMBREE)
+// {
+// BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
+// if (refit) {
+// bvh_embree->refit(progress);
+// }
+// else {
+// bvh_embree->build(progress, &stats, embree_device);
+// }
+
+// if (bvh->params.top_level) {
+// embree_scene = bvh_embree->scene;
+// }
+// }
+// else
+// #endif
+ {
+ Device::build_bvh(bvh, progress, refit);
+ }
+}
+
+void *ANARIDevice::get_guiding_device() const
+{
+//#ifdef WITH_PATH_GUIDING
+// if (!guiding_device) {
+// if (guiding_device_type() == 8) {
+// guiding_device = make_unique<openpgl::cpp::Device>(PGL_DEVICE_TYPE_CPU_8);
+// }
+// else if (guiding_device_type() == 4) {
+// guiding_device = make_unique<openpgl::cpp::Device>(PGL_DEVICE_TYPE_CPU_4);
+// }
+// }
+// return guiding_device.get();
+//#else
+ return nullptr;
+//#endif
+}
+
+void ANARIDevice::get_cpu_kernel_thread_globals(
+ vector<ThreadKernelGlobalsCPU> &kernel_thread_globals)
+{
+ /* Ensure latest texture info is loaded into kernel globals before returning. */
+ load_texture_info();
+
+ //kernel_thread_globals.clear();
+ //OSLGlobals *osl_globals = get_cpu_osl_memory();
+ //for (int i = 0; i < info.cpu_threads; i++) {
+ // kernel_thread_globals.emplace_back(kernel_globals, osl_globals, profiler, i);
+ //}
+}
+
+OSLGlobals *ANARIDevice::get_cpu_osl_memory()
+{
+ return nullptr;
+}
+
+bool ANARIDevice::load_kernels(const uint /*kernel_features*/)
+{
+ return true;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/anari/device_impl.h b/intern/cycles/device/anari/device_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..774d3fc5e8b2f56dd42ae97ff750f3cfca982197
--- /dev/null
+++ b/intern/cycles/device/anari/device_impl.h
@@ -0,0 +1,79 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+#pragma once
+
+//#include "device/anari/kernel.h"
+#include "device/device.h"
+#include "device/memory.h"
+
+// clang-format off
+#include "kernel/device/anari/kernel.h"
+#include "kernel/globals.h"
+
+//#include "kernel/osl/globals.h"
+// clang-format on
+
+#include "util/guiding.h" // IWYU pragma: keep
+#include "util/unique_ptr.h"
+
+CCL_NAMESPACE_BEGIN
+
+class ANARIDevice : public Device {
+ public:
+ KernelGlobalsCPU kernel_globals;
+
+ device_vector<TextureInfo> texture_info;
+ bool need_texture_info;
+
+// #ifdef WITH_OSL
+// OSLGlobals osl_globals;
+// #endif
+// #ifdef WITH_EMBREE
+// RTCScene embree_scene = nullptr;
+// RTCDevice embree_device;
+// #endif
+// #ifdef WITH_PATH_GUIDING
+// mutable unique_ptr<openpgl::cpp::Device> guiding_device;
+// #endif
+
+ ANARIDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_, bool headless_);
+ ~ANARIDevice() override;
+
+ BVHLayoutMask get_bvh_layout_mask(uint /*kernel_features*/) const override;
+
+ /* Returns true if the texture info was copied to the device (meaning, some more
+ * re-initialization might be needed). */
+ bool load_texture_info();
+
+ void mem_alloc(device_memory &mem) override;
+ void mem_copy_to(device_memory &mem) override;
+ void mem_move_to_host(device_memory &mem) override;
+ void mem_copy_from(
+ device_memory &mem, const size_t y, size_t w, const size_t h, size_t elem) override;
+ void mem_zero(device_memory &mem) override;
+ void mem_free(device_memory &mem) override;
+ device_ptr mem_alloc_sub_ptr(device_memory &mem, const size_t offset, size_t /*size*/) override;
+
+ void const_copy_to(const char *name, void *host, const size_t size) override;
+
+ void global_alloc(device_memory &mem);
+ void global_free(device_memory &mem);
+
+ void tex_alloc(device_texture &mem);
+ void tex_free(device_texture &mem);
+
+ void build_bvh(BVH *bvh, Progress &progress, bool refit) override;
+
+ void *get_guiding_device() const override;
+
+ void get_cpu_kernel_thread_globals(
+ vector<ThreadKernelGlobalsCPU> &kernel_thread_globals) override;
+ OSLGlobals *get_cpu_osl_memory() override;
+
+ protected:
+ bool load_kernels(uint /*kernel_features*/) override;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index 44fa7988f2a2738cf948d5b518aefc2648a0a1a4..b043cfbb7a4369963bebfe65b9eded2aaf97254f 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -19,6 +19,7 @@
#include "device/multi/device.h"
#include "device/oneapi/device.h"
#include "device/optix/device.h"
+#include "device/anari/device.h"
#ifdef WITH_HIPRT
# include <hiprtew.h>
@@ -43,6 +44,7 @@ vector<DeviceInfo> Device::cpu_devices;
vector<DeviceInfo> Device::hip_devices;
vector<DeviceInfo> Device::metal_devices;
vector<DeviceInfo> Device::oneapi_devices;
+vector<DeviceInfo> Device::anari_devices;
uint Device::devices_initialized_mask = 0;
/* Device */
@@ -117,6 +119,12 @@ unique_ptr<Device> Device::create(const DeviceInfo &info,
break;
#endif
+#ifdef WITH_ANARI
+ case DEVICE_ANARI:
+ device = device_anari_create(info, stats, profiler, headless);
+ break;
+#endif
+
default:
break;
}
@@ -154,6 +162,9 @@ DeviceType Device::type_from_string(const char *name)
if (strcmp(name, "HIPRT") == 0) {
return DEVICE_HIPRT;
}
+ if (strcmp(name, "ANARI") == 0) {
+ return DEVICE_ANARI;
+ }
return DEVICE_NONE;
}
@@ -211,6 +222,9 @@ vector<DeviceType> Device::available_types()
if (hiprtewInit()) {
types.push_back(DEVICE_HIPRT);
}
+#endif
+#ifdef WITH_ANARI
+ types.push_back(DEVICE_ANARI);
#endif
return types;
}
@@ -281,6 +295,20 @@ vector<DeviceInfo> Device::available_devices(const uint mask)
}
#endif
+#ifdef WITH_ANARI
+ if (mask & DEVICE_MASK_ANARI) {
+ if (!(devices_initialized_mask & DEVICE_MASK_ANARI)) {
+ if (device_anari_init()) {
+ device_anari_info(anari_devices);
+ }
+ devices_initialized_mask |= DEVICE_MASK_ANARI;
+ }
+ for (DeviceInfo &info : anari_devices) {
+ devices.push_back(info);
+ }
+ }
+#endif
+
if (mask & DEVICE_MASK_CPU) {
if (!(devices_initialized_mask & DEVICE_MASK_CPU)) {
device_cpu_info(cpu_devices);
@@ -374,6 +402,18 @@ string Device::device_capabilities(const uint mask)
}
#endif
+#ifdef WITH_ANARI
+ if (mask & DEVICE_MASK_ANARI) {
+ if (device_anari_init()) {
+ const string device_capabilities = device_anari_capabilities();
+ if (!device_capabilities.empty()) {
+ capabilities += "\nANARI device capabilities:\n";
+ capabilities += device_capabilities;
+ }
+ }
+ }
+#endif
+
return capabilities;
}
@@ -470,6 +510,7 @@ void Device::free_memory()
oneapi_devices.free_memory();
cpu_devices.free_memory();
metal_devices.free_memory();
+ anari_devices.free_memory();
}
unique_ptr<DeviceQueue> Device::gpu_queue_create()
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index f1ea26cad9581c21512b851a189b4793736c87d2..71df167156e0e568c0c4e409971ad55b5ef558b9 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -44,7 +44,8 @@ enum DeviceType {
DEVICE_HIP,
DEVICE_HIPRT,
DEVICE_METAL,
- DEVICE_ONEAPI,
+ DEVICE_ONEAPI,
+ DEVICE_ANARI,
DEVICE_DUMMY,
};
@@ -55,6 +56,7 @@ enum DeviceTypeMask {
DEVICE_MASK_HIP = (1 << DEVICE_HIP),
DEVICE_MASK_METAL = (1 << DEVICE_METAL),
DEVICE_MASK_ONEAPI = (1 << DEVICE_ONEAPI),
+ DEVICE_MASK_ANARI = (1 << DEVICE_ANARI),
DEVICE_MASK_ALL = ~0
};
@@ -328,6 +330,7 @@ class Device {
static vector<DeviceInfo> hip_devices;
static vector<DeviceInfo> metal_devices;
static vector<DeviceInfo> oneapi_devices;
+ static vector<DeviceInfo> anari_devices;
static uint devices_initialized_mask;
};
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 05dc3c5979ddf3cc4644508677528a7cb0351a4e..9db3f8237f28156d39997e0e6c3e40c327896e3c 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -39,6 +39,10 @@ set(SRC_KERNEL_DEVICE_OPTIX
device/optix/kernel_shader_raytrace.cu
)
+set(SRC_KERNEL_DEVICE_ANARI
+ device/anari/kernel.cpp
+)
+
if(WITH_CYCLES_OSL)
math(EXPR OSL_LIBRARY_VERSION_CODE "${OSL_LIBRARY_VERSION_MAJOR} * 10000 + ${OSL_LIBRARY_VERSION_MINOR} * 100 + ${OSL_LIBRARY_VERSION_PATCH}")
@@ -139,6 +143,16 @@ set(SRC_KERNEL_DEVICE_ONEAPI_HEADERS
device/cpu/bvh.h
)
+set(SRC_KERNEL_DEVICE_ANARI_HEADERS
+ #device/anari/bvh.h
+ #device/anari/compat.h
+ #device/anari/image.h
+ #device/anari/globals.h
+ device/anari/kernel.h
+ #device/anari/kernel_arch.h
+ #device/anari/kernel_arch_impl.h
+)
+
set(SRC_KERNEL_CLOSURE_HEADERS
closure/alloc.h
closure/bsdf.h
@@ -1257,6 +1271,7 @@ cycles_add_library(cycles_kernel "${LIB}"
${SRC_KERNEL_DEVICE_HIPRT}
${SRC_KERNEL_DEVICE_OPTIX}
${SRC_KERNEL_DEVICE_METAL}
+ ${SRC_KERNEL_DEVICE_ANARI}
${SRC_KERNEL_HEADERS}
${SRC_KERNEL_DEVICE_CPU_HEADERS}
${SRC_KERNEL_DEVICE_GPU_HEADERS}
@@ -1266,6 +1281,7 @@ cycles_add_library(cycles_kernel "${LIB}"
${SRC_KERNEL_DEVICE_OPTIX_HEADERS}
${SRC_KERNEL_DEVICE_METAL_HEADERS}
${SRC_KERNEL_DEVICE_ONEAPI_HEADERS}
+ ${SRC_KERNEL_DEVICE_ANARI_HEADERS}
)
source_group("bake" FILES ${SRC_KERNEL_BAKE_HEADERS})
@@ -1280,6 +1296,7 @@ source_group("device\\hiprt" FILES ${SRC_KERNEL_DEVICE_HIPRT} ${SRC_KERNEL_DEVIC
source_group("device\\optix" FILES ${SRC_KERNEL_DEVICE_OPTIX} ${SRC_KERNEL_DEVICE_OPTIX_HEADERS})
source_group("device\\metal" FILES ${SRC_KERNEL_DEVICE_METAL} ${SRC_KERNEL_DEVICE_METAL_HEADERS})
source_group("device\\oneapi" FILES ${SRC_KERNEL_DEVICE_ONEAPI} ${SRC_KERNEL_DEVICE_ONEAPI_HEADERS})
+source_group("device\\anari" FILES ${SRC_KERNEL_DEVICE_ANARI} ${SRC_KERNEL_DEVICE_ANARI_HEADERS})
source_group("film" FILES ${SRC_KERNEL_FILM_HEADERS})
source_group("geom" FILES ${SRC_KERNEL_GEOM_HEADERS})
source_group("integrator" FILES ${SRC_KERNEL_INTEGRATOR_HEADERS})
@@ -1306,6 +1323,7 @@ cycles_add_gpu_kernel_dependencies(cycles_kernel_optix)
cycles_add_gpu_kernel_dependencies(cycles_kernel_hip)
cycles_add_gpu_kernel_dependencies(cycles_kernel_hiprt)
cycles_add_gpu_kernel_dependencies(cycles_kernel_oneapi)
+cycles_add_gpu_kernel_dependencies(cycles_kernel_anari)
# Install kernel source for runtime compilation
diff --git a/intern/cycles/kernel/device/anari/kernel.cpp b/intern/cycles/kernel/device/anari/kernel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d3734b8e89be3b6099e873058fd632af7ac0adb2
--- /dev/null
+++ b/intern/cycles/kernel/device/anari/kernel.cpp
@@ -0,0 +1,85 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+/* CPU kernel entry points */
+
+// /* On x86-64, our minimum is SSE4.2, so avoid the extra kernel and compile this
+// * one with SSE4.2 intrinsics.
+// */
+// #if defined(__x86_64__) || defined(_M_X64)
+// # define __KERNEL_SSE__
+// # define __KERNEL_SSE2__
+// # define __KERNEL_SSE3__
+// # define __KERNEL_SSSE3__
+// # define __KERNEL_SSE42__
+// #endif
+
+// /* When building kernel for native machine detect kernel features from the flags
+// * set by compiler.
+// */
+// #ifdef WITH_KERNEL_NATIVE
+// # ifdef __SSE4_2__
+// # ifndef __KERNEL_SSE42__
+// # define __KERNEL_SSE42__
+// # endif
+// # endif
+// # ifdef __AVX__
+// # ifndef __KERNEL_SSE__
+// # define __KERNEL_SSE__
+// # endif
+// # define __KERNEL_AVX__
+// # endif
+// # ifdef __AVX2__
+// # ifndef __KERNEL_SSE__
+// # define __KERNEL_SSE__
+// # endif
+// # define __KERNEL_AVX2__
+// # endif
+// #endif
+
+// /* quiet unused define warnings */
+// #if defined(__KERNEL_SSE2__)
+// /* do nothing */
+// #endif
+
+// #include "kernel/device/cpu/globals.h"
+
+// #include "kernel/device/cpu/kernel.h"
+// #define KERNEL_ARCH cpu
+// #include "kernel/device/cpu/kernel_arch_impl.h"
+
+// CCL_NAMESPACE_BEGIN
+
+// /* Memory Copy */
+
+// void kernel_const_copy(KernelGlobalsCPU *kg, const char *name, void *host, size_t /*unused*/)
+// {
+// if (strcmp(name, "data") == 0) {
+// kg->data = *(KernelData *)host;
+// }
+// else {
+// assert(0);
+// }
+// }
+
+// void kernel_global_memory_copy(KernelGlobalsCPU *kg,
+// const char *name,
+// void *mem,
+// const size_t size)
+// {
+// if (false) {
+// }
+
+// #define KERNEL_DATA_ARRAY(type, tname) \
+// else if (strcmp(name, #tname) == 0) { \
+// kg->tname.data = (type *)mem; \
+// kg->tname.width = size; \
+// }
+// #include "kernel/data_arrays.h"
+// else {
+// assert(0);
+// }
+// }
+
+// CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/anari/kernel.h b/intern/cycles/kernel/device/anari/kernel.h
new file mode 100644
index 0000000000000000000000000000000000000000..4d66cf20977a7014e73f3cdc5638459ad984135b
--- /dev/null
+++ b/intern/cycles/kernel/device/anari/kernel.h
@@ -0,0 +1,41 @@
+/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0 */
+
+#pragma once
+
+// /* CPU Kernel Interface */
+
+// #include "kernel/types.h"
+
+// #include "util/half.h"
+
+// CCL_NAMESPACE_BEGIN
+
+// #define KERNEL_NAME_JOIN(x, y, z) x##_##y##_##z
+// #define KERNEL_NAME_EVAL(arch, name) KERNEL_NAME_JOIN(kernel, arch, name)
+// #define KERNEL_FUNCTION_FULL_NAME(name) KERNEL_NAME_EVAL(KERNEL_ARCH, name)
+
+// struct IntegratorStateCPU;
+// struct KernelGlobalsCPU;
+// struct KernelData;
+
+// KernelGlobalsCPU *kernel_globals_create();
+// void kernel_globals_free(KernelGlobalsCPU *kg);
+
+// void *kernel_osl_memory(const KernelGlobalsCPU *kg);
+// bool kernel_osl_use(const KernelGlobalsCPU *kg);
+
+// void kernel_const_copy(KernelGlobalsCPU *kg, const char *name, void *host, const size_t size);
+// void kernel_global_memory_copy(KernelGlobalsCPU *kg,
+// const char *name,
+// void *mem,
+// const size_t size);
+
+// #define KERNEL_ARCH cpu
+// #include "kernel/device/cpu/kernel_arch.h"
+
+// #define KERNEL_ARCH cpu_avx2
+// #include "kernel/device/cpu/kernel_arch.h"
+
+// CCL_NAMESPACE_END
diff --git a/source/creator/creator_args.cc b/source/creator/creator_args.cc
index a7e5f0e7702be6dc476bd524cda94a6ae25ddfa3..55c6d8f298f7197a55c217b702c482dfa9ec847c 100644
--- a/source/creator/creator_args.cc
+++ b/source/creator/creator_args.cc
@@ -664,7 +664,7 @@ static void print_help(bArgs *ba, bool all)
PRINT("\n");
PRINT("--cycles-device <device>\n");
PRINT("\tSet the device used for rendering.\n");
- PRINT("\tValid options are: 'CPU' 'CUDA' 'OPTIX' 'HIP' 'ONEAPI' 'METAL'.\n");
+ PRINT("\tValid options are: 'CPU' 'CUDA' 'OPTIX' 'HIP' 'ONEAPI' 'METAL' 'ANARI'.\n");
PRINT("\n");
PRINT("\tAppend +CPU to a GPU device to render on both CPU and GPU.\n");
PRINT("\n");