Cycles: add Optix device backend

This uses hardware-accelerated raytracing on NVIDIA RTX graphics cards.

It is still currently experimental. Most features are supported, but a few
are still missing like baking, branched path tracing and using CPU memory.
https://wiki.blender.org/wiki/Reference/Release_Notes/2.81/Cycles#NVIDIA_RTX

For building with Optix support, the Optix SDK must be installed. See here for
build instructions:
https://wiki.blender.org/wiki/Building_Blender/CUDA

Differential Revision: https://developer.blender.org/D5363
This commit is contained in:
Patrick Mours 2019-09-12 14:50:06 +02:00 committed by Brecht Van Lommel
parent 53932f1f06
commit a2b52dc571
26 changed files with 2574 additions and 34 deletions

View File

@ -426,6 +426,7 @@ mark_as_advanced(WITH_CYCLES_DEBUG)
mark_as_advanced(WITH_CYCLES_NATIVE_ONLY)
option(WITH_CYCLES_DEVICE_CUDA "Enable Cycles CUDA compute support" ON)
option(WITH_CYCLES_DEVICE_OPTIX "Enable Cycles OptiX support" OFF)
option(WITH_CYCLES_DEVICE_OPENCL "Enable Cycles OpenCL compute support" ON)
option(WITH_CYCLES_NETWORK "Enable Cycles compute over network support (EXPERIMENTAL and unfinished)" OFF)
mark_as_advanced(WITH_CYCLES_DEVICE_CUDA)

View File

@ -34,6 +34,9 @@ def get_cmake_options(builder):
elif builder.platform == 'linux':
config_file = "build_files/buildbot/config/blender_linux.cmake"
optix_sdk_dir = os.path.join(builder.blender_dir, '..', '..', 'NVIDIA-Optix-SDK')
options.append('-DOPTIX_ROOT_DIR:PATH=' + optix_sdk_dir)
options.append("-C" + os.path.join(builder.blender_dir, config_file))
options.append("-DCMAKE_INSTALL_PREFIX=%s" % (builder.install_dir))

View File

@ -0,0 +1,57 @@
# - Find OptiX library
# Find the native OptiX includes and library
# This module defines
# OPTIX_INCLUDE_DIRS, where to find optix.h, Set when
# OPTIX_INCLUDE_DIR is found.
# OPTIX_ROOT_DIR, The base directory to search for OptiX.
# This can also be an environment variable.
# OPTIX_FOUND, If false, do not try to use OptiX.
#=============================================================================
# Copyright 2019 Blender Foundation.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# If OPTIX_ROOT_DIR was defined in the environment, use it.
IF(NOT OPTIX_ROOT_DIR AND NOT $ENV{OPTIX_ROOT_DIR} STREQUAL "")
SET(OPTIX_ROOT_DIR $ENV{OPTIX_ROOT_DIR})
ENDIF()
SET(_optix_SEARCH_DIRS
${OPTIX_ROOT_DIR}
"$ENV{PROGRAMDATA}/NVIDIA Corporation/OptiX SDK 7.0.0"
/usr/local
/sw # Fink
/opt/local # DarwinPorts
)
FIND_PATH(OPTIX_INCLUDE_DIR
NAMES
optix.h
HINTS
${_optix_SEARCH_DIRS}
PATH_SUFFIXES
include
)
# handle the QUIETLY and REQUIRED arguments and set OPTIX_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OptiX DEFAULT_MSG
OPTIX_INCLUDE_DIR)
IF(OPTIX_FOUND)
SET(OPTIX_INCLUDE_DIRS ${OPTIX_INCLUDE_DIR})
ENDIF(OPTIX_FOUND)
MARK_AS_ADVANCED(
OPTIX_INCLUDE_DIR
)
UNSET(_optix_SEARCH_DIRS)

View File

@ -17,6 +17,7 @@ set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_OSL OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_DEVICE_OPTIX OFF CACHE BOOL "" FORCE)
set(WITH_DRACO OFF CACHE BOOL "" FORCE)
set(WITH_FFTW3 OFF CACHE BOOL "" FORCE)
set(WITH_LIBMV OFF CACHE BOOL "" FORCE)

View File

@ -57,6 +57,7 @@ set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_CUBIN_COMPILER OFF CACHE BOOL "" FORCE)
set(CYCLES_CUDA_BINARIES_ARCH sm_30;sm_35;sm_37;sm_50;sm_52;sm_60;sm_61;sm_70;sm_75 CACHE STRING "" FORCE)
set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE)
# platform dependent options
if(UNIX AND NOT APPLE)

View File

@ -219,6 +219,24 @@ if(WITH_CYCLES_OSL)
)
endif()
if(WITH_CYCLES_DEVICE_OPTIX)
find_package(OptiX)
if(OPTIX_FOUND)
add_definitions(-DWITH_OPTIX)
include_directories(
SYSTEM
${OPTIX_INCLUDE_DIR}
)
# Need pre-compiled CUDA binaries in the OptiX device
set(WITH_CYCLES_CUDA_BINARIES ON)
else()
message(STATUS "Optix not found, disabling it from Cycles")
set(WITH_CYCLES_DEVICE_OPTIX OFF)
endif()
endif()
if(WITH_CYCLES_EMBREE)
add_definitions(-DWITH_EMBREE)
add_definitions(-DEMBREE_STATIC_LIB)

View File

@ -137,6 +137,7 @@ enum_world_mis = (
enum_device_type = (
('CPU', "CPU", "CPU", 0),
('CUDA', "CUDA", "CUDA", 1),
('OPTIX', "OptiX", "OptiX", 3),
('OPENCL', "OpenCL", "OpenCL", 2)
)
@ -740,6 +741,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
debug_use_cuda_adaptive_compile: BoolProperty(name="Adaptive Compile", default=False)
debug_use_cuda_split_kernel: BoolProperty(name="Split Kernel", default=False)
debug_optix_cuda_streams: IntProperty(name="CUDA Streams", default=1, min=1)
debug_opencl_kernel_type: EnumProperty(
name="OpenCL Kernel Type",
default='DEFAULT',
@ -1400,10 +1403,12 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_device_types(self, context):
import _cycles
has_cuda, has_opencl = _cycles.get_device_types()
has_cuda, has_optix, has_opencl = _cycles.get_device_types()
list = [('NONE', "None", "Don't use compute device", 0)]
if has_cuda:
list.append(('CUDA', "CUDA", "Use CUDA for GPU acceleration", 1))
if has_optix:
list.append(('OPTIX', "OptiX", "Use OptiX for GPU acceleration", 3))
if has_opencl:
list.append(('OPENCL', "OpenCL", "Use OpenCL for GPU acceleration", 2))
return list
@ -1424,7 +1429,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def update_device_entries(self, device_list):
for device in device_list:
if not device[1] in {'CUDA', 'OPENCL', 'CPU'}:
if not device[1] in {'CUDA', 'OPTIX', 'OPENCL', 'CPU'}:
continue
# Try to find existing Device entry
entry = self.find_existing_device_entry(device)
@ -1439,8 +1444,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
# Update name in case it changed
entry.name = device[0]
# Gets all devices types by default.
def get_devices(self, compute_device_type=''):
# Gets all devices types for a compute device type.
def get_devices_for_type(self, compute_device_type):
import _cycles
# Layout of the device tuples: (Name, Type, Persistent ID)
device_list = _cycles.available_devices(compute_device_type)
@ -1449,20 +1454,23 @@ class CyclesPreferences(bpy.types.AddonPreferences):
# hold pointers to a resized array.
self.update_device_entries(device_list)
# Sort entries into lists
cuda_devices = []
opencl_devices = []
devices = []
cpu_devices = []
for device in device_list:
entry = self.find_existing_device_entry(device)
if entry.type == 'CUDA':
cuda_devices.append(entry)
elif entry.type == 'OPENCL':
opencl_devices.append(entry)
if entry.type == compute_device_type:
devices.append(entry)
elif entry.type == 'CPU':
cpu_devices.append(entry)
# Extend all GPU devices with CPU.
cuda_devices.extend(cpu_devices)
opencl_devices.extend(cpu_devices)
if compute_device_type in ('CUDA', 'OPENCL'):
devices.extend(cpu_devices)
return devices
# For backwards compatibility, only has CUDA and OpenCL.
def get_devices(self, compute_device_type=''):
cuda_devices = self.get_devices_for_type('CUDA')
opencl_devices = self.get_devices_for_type('OPENCL')
return cuda_devices, opencl_devices
def get_num_gpu_devices(self):
@ -1498,16 +1506,24 @@ class CyclesPreferences(bpy.types.AddonPreferences):
for device in devices:
box.prop(device, "use", text=device.name)
if device_type == 'OPTIX':
col = box.column(align=True)
col.label(text="OptiX support is experimental", icon='INFO')
col.label(text="Not all Cycles features are supported yet", icon='BLANK1')
def draw_impl(self, layout, context):
row = layout.row()
row.prop(self, "compute_device_type", expand=True)
cuda_devices, opencl_devices = self.get_devices(self.compute_device_type)
devices = self.get_devices_for_type(self.compute_device_type)
row = layout.row()
if self.compute_device_type == 'CUDA':
self._draw_devices(row, 'CUDA', cuda_devices)
self._draw_devices(row, 'CUDA', devices)
elif self.compute_device_type == 'OPTIX':
self._draw_devices(row, 'OPTIX', devices)
elif self.compute_device_type == 'OPENCL':
self._draw_devices(row, 'OPENCL', opencl_devices)
self._draw_devices(row, 'OPENCL', devices)
def draw(self, context):
self.draw_impl(self.layout, context)

View File

@ -88,10 +88,16 @@ def use_cuda(context):
return (get_device_type(context) == 'CUDA' and cscene.device == 'GPU')
def use_optix(context):
cscene = context.scene.cycles
return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU')
def use_branched_path(context):
cscene = context.scene.cycles
return (cscene.progressive == 'BRANCHED_PATH')
return (cscene.progressive == 'BRANCHED_PATH' and not use_optix(context))
def use_sample_all_lights(context):
@ -168,7 +174,8 @@ class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
layout.prop(cscene, "progressive")
if not use_optix(context):
layout.prop(cscene, "progressive")
if cscene.progressive == 'PATH' or use_branched_path(context) is False:
col = layout.column(align=True)
@ -1763,6 +1770,10 @@ class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel):
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'CYCLES'}
@classmethod
def poll(cls, context):
return not use_optix(context)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
@ -1947,7 +1958,13 @@ class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):
col.separator()
col = layout.column()
col.label(text='OpenCL Flags:')
col.label(text="OptiX Flags:")
col.prop(cscene, "debug_optix_cuda_streams")
col.separator()
col = layout.column()
col.label(text="OpenCL Flags:")
col.prop(cscene, "debug_opencl_device_type", text="Device")
col.prop(cscene, "debug_use_opencl_debug", text="Debug")
col.prop(cscene, "debug_opencl_mem_limit")

View File

@ -61,7 +61,8 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
COMPUTE_DEVICE_CPU = 0,
COMPUTE_DEVICE_CUDA = 1,
COMPUTE_DEVICE_OPENCL = 2,
COMPUTE_DEVICE_NUM = 3,
COMPUTE_DEVICE_OPTIX = 3,
COMPUTE_DEVICE_NUM = 4,
};
ComputeDevice compute_device = (ComputeDevice)get_enum(
@ -73,6 +74,10 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
if (compute_device == COMPUTE_DEVICE_CUDA) {
mask |= DEVICE_MASK_CUDA;
}
else if (compute_device == COMPUTE_DEVICE_OPTIX) {
/* Cannot use CPU and OptiX device at the same time right now, so replace mask. */
mask = DEVICE_MASK_OPTIX;
}
else if (compute_device == COMPUTE_DEVICE_OPENCL) {
mask |= DEVICE_MASK_OPENCL;
}

View File

@ -81,6 +81,8 @@ bool debug_flags_sync_from_scene(BL::Scene b_scene)
/* Synchronize CUDA flags. */
flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
flags.cuda.split_kernel = get_boolean(cscene, "debug_use_cuda_split_kernel");
/* Synchronize OptiX flags. */
flags.optix.cuda_streams = get_int(cscene, "debug_optix_cuda_streams");
/* Synchronize OpenCL device type. */
switch (get_enum(cscene, "debug_opencl_device_type")) {
case 0:
@ -960,14 +962,16 @@ static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*
static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
{
vector<DeviceType> device_types = Device::available_types();
bool has_cuda = false, has_opencl = false;
bool has_cuda = false, has_optix = false, has_opencl = false;
foreach (DeviceType device_type, device_types) {
has_cuda |= (device_type == DEVICE_CUDA);
has_optix |= (device_type == DEVICE_OPTIX);
has_opencl |= (device_type == DEVICE_OPENCL);
}
PyObject *list = PyTuple_New(2);
PyObject *list = PyTuple_New(3);
PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_opencl));
PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_opencl));
return list;
}

View File

@ -758,7 +758,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
preview_samples = preview_samples * preview_samples;
}
if (get_enum(cscene, "progressive") == 0) {
if (get_enum(cscene, "progressive") == 0 && (params.device.type != DEVICE_OPTIX)) {
if (background) {
params.samples = aa_samples;
}

View File

@ -15,6 +15,7 @@ set(SRC
bvh_build.cpp
bvh_embree.cpp
bvh_node.cpp
bvh_optix.cpp
bvh_sort.cpp
bvh_split.cpp
bvh_unaligned.cpp
@ -29,6 +30,7 @@ set(SRC_HEADERS
bvh_build.h
bvh_embree.h
bvh_node.h
bvh_optix.h
bvh_params.h
bvh_sort.h
bvh_split.h

View File

@ -26,6 +26,9 @@
#include "bvh/bvh_build.h"
#include "bvh/bvh_node.h"
#ifdef WITH_OPTIX
# include "bvh/bvh_optix.h"
#endif
#ifdef WITH_EMBREE
# include "bvh/bvh_embree.h"
#endif
@ -51,6 +54,8 @@ const char *bvh_layout_name(BVHLayout layout)
return "NONE";
case BVH_LAYOUT_EMBREE:
return "EMBREE";
case BVH_LAYOUT_OPTIX:
return "OPTIX";
case BVH_LAYOUT_ALL:
return "ALL";
}
@ -115,6 +120,12 @@ BVH *BVH::create(const BVHParams &params,
return new BVHEmbree(params, meshes, objects);
#else
break;
#endif
case BVH_LAYOUT_OPTIX:
#ifdef WITH_OPTIX
return new BVHOptiX(params, meshes, objects);
#else
break;
#endif
case BVH_LAYOUT_NONE:
case BVH_LAYOUT_ALL:

View File

@ -0,0 +1,215 @@
/*
* Copyright 2019, NVIDIA Corporation.
* Copyright 2019, Blender Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef WITH_OPTIX
# include "bvh/bvh_optix.h"
# include "render/mesh.h"
# include "render/object.h"
# include "util/util_logging.h"
# include "util/util_progress.h"
CCL_NAMESPACE_BEGIN
BVHOptiX::BVHOptiX(const BVHParams &params_,
const vector<Mesh *> &meshes_,
const vector<Object *> &objects_)
: BVH(params_, meshes_, objects_)
{
}
BVHOptiX::~BVHOptiX()
{
}
void BVHOptiX::build(Progress &, Stats *)
{
if (params.top_level)
pack_tlas();
else
pack_blas();
}
void BVHOptiX::copy_to_device(Progress &progress, DeviceScene *dscene)
{
progress.set_status("Updating Scene BVH", "Building OptiX acceleration structure");
Device *const device = dscene->bvh_nodes.device;
if (!device->build_optix_bvh(this, dscene->bvh_nodes))
progress.set_error("Failed to build OptiX acceleration structure");
}
void BVHOptiX::pack_blas()
{
// Bottom-level BVH can contain multiple primitive types, so merge them:
assert(meshes.size() == 1 && objects.size() == 1); // These are build per-mesh
Mesh *const mesh = meshes[0];
if (params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) {
const size_t num_curves = mesh->num_curves();
const size_t num_segments = mesh->num_segments();
pack.prim_type.reserve(pack.prim_type.size() + num_segments);
pack.prim_index.reserve(pack.prim_index.size() + num_segments);
pack.prim_object.reserve(pack.prim_object.size() + num_segments);
// 'pack.prim_time' is only used in geom_curve_intersect.h
// It is not needed because of OPTIX_MOTION_FLAG_[START|END]_VANISH
uint type = PRIMITIVE_CURVE;
if (mesh->use_motion_blur && mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION))
type = PRIMITIVE_MOTION_CURVE;
for (size_t j = 0; j < num_curves; ++j) {
const Mesh::Curve curve = mesh->get_curve(j);
for (size_t k = 0; k < curve.num_segments(); ++k) {
pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(type, k));
// Each curve segment points back to its curve index
pack.prim_index.push_back_reserved(j);
pack.prim_object.push_back_reserved(0);
}
}
}
if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && mesh->num_triangles() > 0) {
const size_t num_triangles = mesh->num_triangles();
pack.prim_type.reserve(pack.prim_type.size() + num_triangles);
pack.prim_index.reserve(pack.prim_index.size() + num_triangles);
pack.prim_object.reserve(pack.prim_object.size() + num_triangles);
uint type = PRIMITIVE_TRIANGLE;
if (mesh->use_motion_blur && mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION))
type = PRIMITIVE_MOTION_TRIANGLE;
for (size_t k = 0; k < num_triangles; ++k) {
pack.prim_type.push_back_reserved(type);
pack.prim_index.push_back_reserved(k);
pack.prim_object.push_back_reserved(0);
}
}
// Initialize visibility to zero and later update it during top-level build
uint prev_visibility = objects[0]->visibility;
objects[0]->visibility = 0;
// Update 'pack.prim_tri_index', 'pack.prim_tri_verts' and 'pack.prim_visibility'
pack_primitives();
// Reset visibility after packing
objects[0]->visibility = prev_visibility;
}
void BVHOptiX::pack_tlas()
{
// Calculate total packed size
size_t prim_index_size = 0;
size_t prim_tri_verts_size = 0;
foreach (Mesh *mesh, meshes) {
BVH *const bvh = mesh->bvh;
prim_index_size += bvh->pack.prim_index.size();
prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
}
if (prim_index_size == 0)
return; // Abort right away if this is an empty BVH
size_t pack_offset = 0;
size_t pack_verts_offset = 0;
pack.prim_type.resize(prim_index_size);
int *pack_prim_type = pack.prim_type.data();
pack.prim_index.resize(prim_index_size);
int *pack_prim_index = pack.prim_index.data();
pack.prim_object.resize(prim_index_size);
int *pack_prim_object = pack.prim_object.data();
pack.prim_visibility.resize(prim_index_size);
uint *pack_prim_visibility = pack.prim_visibility.data();
pack.prim_tri_index.resize(prim_index_size);
uint *pack_prim_tri_index = pack.prim_tri_index.data();
pack.prim_tri_verts.resize(prim_tri_verts_size);
float4 *pack_prim_tri_verts = pack.prim_tri_verts.data();
// Top-level BVH should only contain instances, see 'Mesh::need_build_bvh'
// Iterate over scene mesh list instead of objects, since the 'prim_offset' is calculated based
// on that list, which may be ordered differently from the object list.
foreach (Mesh *mesh, meshes) {
PackedBVH &bvh_pack = mesh->bvh->pack;
int mesh_tri_offset = mesh->tri_offset;
int mesh_curve_offset = mesh->curve_offset;
// Merge primitive, object and triangle indexes
if (!bvh_pack.prim_index.empty()) {
int *bvh_prim_type = &bvh_pack.prim_type[0];
int *bvh_prim_index = &bvh_pack.prim_index[0];
uint *bvh_prim_tri_index = &bvh_pack.prim_tri_index[0];
uint *bvh_prim_visibility = &bvh_pack.prim_visibility[0];
for (size_t i = 0; i < bvh_pack.prim_index.size(); i++, pack_offset++) {
if (bvh_pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
pack_prim_index[pack_offset] = bvh_prim_index[i] + mesh_curve_offset;
pack_prim_tri_index[pack_offset] = -1;
}
else {
pack_prim_index[pack_offset] = bvh_prim_index[i] + mesh_tri_offset;
pack_prim_tri_index[pack_offset] = bvh_prim_tri_index[i] + pack_verts_offset;
}
pack_prim_type[pack_offset] = bvh_prim_type[i];
pack_prim_object[pack_offset] = 0; // Unused for instanced meshes
pack_prim_visibility[pack_offset] = bvh_prim_visibility[i];
}
}
// Merge triangle vertex data
if (!bvh_pack.prim_tri_verts.empty()) {
const size_t prim_tri_size = bvh_pack.prim_tri_verts.size();
memcpy(pack_prim_tri_verts + pack_verts_offset,
bvh_pack.prim_tri_verts.data(),
prim_tri_size * sizeof(float4));
pack_verts_offset += prim_tri_size;
}
}
// Merge visibility flags of all objects and fix object indices for non-instanced meshes
foreach (Object *ob, objects) {
Mesh *const mesh = ob->mesh;
for (size_t i = 0; i < mesh->num_primitives(); ++i) {
if (!ob->mesh->is_instanced()) {
assert(pack.prim_object[mesh->prim_offset + i] == 0);
pack.prim_object[mesh->prim_offset + i] = ob->get_device_index();
}
pack.prim_visibility[mesh->prim_offset + i] |= ob->visibility_for_tracing();
}
}
}
void BVHOptiX::pack_nodes(const BVHNode *)
{
}
void BVHOptiX::refit_nodes()
{
// TODO(pmours): Implement?
VLOG(1) << "Refit is not yet implemented for OptiX BVH.";
}
BVHNode *BVHOptiX::widen_children_nodes(const BVHNode *)
{
return NULL;
}
CCL_NAMESPACE_END
#endif /* WITH_OPTIX */

View File

@ -0,0 +1,53 @@
/*
* Copyright 2019, NVIDIA Corporation.
* Copyright 2019, Blender Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __BVH_OPTIX_H__
#define __BVH_OPTIX_H__
#ifdef WITH_OPTIX
# include "bvh/bvh.h"
# include "bvh/bvh_params.h"
# include "device/device_memory.h"
CCL_NAMESPACE_BEGIN
class BVHOptiX : public BVH {
friend class BVH;
public:
BVHOptiX(const BVHParams &params, const vector<Mesh *> &meshes, const vector<Object *> &objects);
virtual ~BVHOptiX();
virtual void build(Progress &progress, Stats *) override;
virtual void copy_to_device(Progress &progress, DeviceScene *dscene) override;
private:
void pack_blas();
void pack_tlas();
virtual void pack_nodes(const BVHNode *) override;
virtual void refit_nodes() override;
virtual BVHNode *widen_children_nodes(const BVHNode *) override;
};
CCL_NAMESPACE_END
#endif /* WITH_OPTIX */
#endif /* __BVH_OPTIX_H__ */

View File

@ -29,6 +29,7 @@ set(SRC
device_memory.cpp
device_multi.cpp
device_opencl.cpp
device_optix.cpp
device_split_kernel.cpp
device_task.cpp
)
@ -85,6 +86,9 @@ endif()
if(WITH_CYCLES_DEVICE_CUDA)
add_definitions(-DWITH_CUDA)
endif()
if(WITH_CYCLES_DEVICE_OPTIX)
add_definitions(-DWITH_OPTIX)
endif()
if(WITH_CYCLES_DEVICE_MULTI)
add_definitions(-DWITH_MULTI)
endif()

View File

@ -38,6 +38,7 @@ bool Device::need_devices_update = true;
thread_mutex Device::device_mutex;
vector<DeviceInfo> Device::opencl_devices;
vector<DeviceInfo> Device::cuda_devices;
vector<DeviceInfo> Device::optix_devices;
vector<DeviceInfo> Device::cpu_devices;
vector<DeviceInfo> Device::network_devices;
uint Device::devices_initialized_mask = 0;
@ -379,6 +380,14 @@ Device *Device::create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool
device = NULL;
break;
#endif
#ifdef WITH_OPTIX
case DEVICE_OPTIX:
if (device_optix_init())
device = device_optix_create(info, stats, profiler, background);
else
device = NULL;
break;
#endif
#ifdef WITH_MULTI
case DEVICE_MULTI:
device = device_multi_create(info, stats, profiler, background);
@ -410,6 +419,8 @@ DeviceType Device::type_from_string(const char *name)
return DEVICE_CPU;
else if (strcmp(name, "CUDA") == 0)
return DEVICE_CUDA;
else if (strcmp(name, "OPTIX") == 0)
return DEVICE_OPTIX;
else if (strcmp(name, "OPENCL") == 0)
return DEVICE_OPENCL;
else if (strcmp(name, "NETWORK") == 0)
@ -426,6 +437,8 @@ string Device::string_from_type(DeviceType type)
return "CPU";
else if (type == DEVICE_CUDA)
return "CUDA";
else if (type == DEVICE_OPTIX)
return "OPTIX";
else if (type == DEVICE_OPENCL)
return "OPENCL";
else if (type == DEVICE_NETWORK)
@ -443,6 +456,9 @@ vector<DeviceType> Device::available_types()
#ifdef WITH_CUDA
types.push_back(DEVICE_CUDA);
#endif
#ifdef WITH_OPTIX
types.push_back(DEVICE_OPTIX);
#endif
#ifdef WITH_OPENCL
types.push_back(DEVICE_OPENCL);
#endif
@ -488,6 +504,20 @@ vector<DeviceInfo> Device::available_devices(uint mask)
}
#endif
#ifdef WITH_OPTIX
if (mask & DEVICE_MASK_OPTIX) {
if (!(devices_initialized_mask & DEVICE_MASK_OPTIX)) {
if (device_optix_init()) {
device_optix_info(optix_devices);
}
devices_initialized_mask |= DEVICE_MASK_OPTIX;
}
foreach (DeviceInfo &info, optix_devices) {
devices.push_back(info);
}
}
#endif
if (mask & DEVICE_MASK_CPU) {
if (!(devices_initialized_mask & DEVICE_MASK_CPU)) {
device_cpu_info(cpu_devices);

View File

@ -34,6 +34,7 @@
CCL_NAMESPACE_BEGIN
class BVH;
class Progress;
class RenderTile;
@ -45,13 +46,15 @@ enum DeviceType {
DEVICE_OPENCL,
DEVICE_CUDA,
DEVICE_NETWORK,
DEVICE_MULTI
DEVICE_MULTI,
DEVICE_OPTIX,
};
enum DeviceTypeMask {
DEVICE_MASK_CPU = (1 << DEVICE_CPU),
DEVICE_MASK_OPENCL = (1 << DEVICE_OPENCL),
DEVICE_MASK_CUDA = (1 << DEVICE_CUDA),
DEVICE_MASK_OPTIX = (1 << DEVICE_OPTIX),
DEVICE_MASK_NETWORK = (1 << DEVICE_NETWORK),
DEVICE_MASK_ALL = ~0
};
@ -380,7 +383,11 @@ class Device {
}
/* tasks */
virtual int get_split_task_count(DeviceTask &task) = 0;
virtual int get_split_task_count(DeviceTask &)
{
return 1;
}
virtual void task_add(DeviceTask &task) = 0;
virtual void task_wait() = 0;
virtual void task_cancel() = 0;
@ -399,6 +406,12 @@ class Device {
bool transparent,
const DeviceDrawParams &draw_params);
/* acceleration structure building */
virtual bool build_optix_bvh(BVH *, device_memory &)
{
return false;
}
#ifdef WITH_NETWORK
/* networking */
void server_run();
@ -456,6 +469,7 @@ class Device {
static bool need_types_update, need_devices_update;
static thread_mutex device_mutex;
static vector<DeviceInfo> cuda_devices;
static vector<DeviceInfo> optix_devices;
static vector<DeviceInfo> opencl_devices;
static vector<DeviceInfo> cpu_devices;
static vector<DeviceInfo> network_devices;

View File

@ -2263,11 +2263,6 @@ class CUDADevice : public Device {
}
};
int get_split_task_count(DeviceTask & /*task*/)
{
return 1;
}
void task_add(DeviceTask &task)
{
CUDAContextScope scope(this);

View File

@ -27,6 +27,9 @@ Device *device_opencl_create(DeviceInfo &info, Stats &stats, Profiler &profiler,
bool device_opencl_compile_kernel(const vector<string> &parameters);
bool device_cuda_init();
Device *device_cuda_create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background);
bool device_optix_init();
Device *device_optix_create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background);
Device *device_network_create(DeviceInfo &info,
Stats &stats,
Profiler &profiler,
@ -36,6 +39,7 @@ Device *device_multi_create(DeviceInfo &info, Stats &stats, Profiler &profiler,
void device_cpu_info(vector<DeviceInfo> &devices);
void device_opencl_info(vector<DeviceInfo> &devices);
void device_cuda_info(vector<DeviceInfo> &devices);
void device_optix_info(vector<DeviceInfo> &devices);
void device_network_info(vector<DeviceInfo> &devices);
string device_cpu_capabilities();

View File

@ -153,6 +153,24 @@ class MultiDevice : public Device {
return result;
}
bool build_optix_bvh(BVH *bvh, device_memory &mem)
{
device_ptr key = unique_key++;
// Broadcast acceleration structure build to all devices
foreach (SubDevice &sub, devices) {
mem.device = sub.device;
if (!sub.device->build_optix_bvh(bvh, mem))
return false;
sub.ptr_map[key] = mem.device_pointer;
}
mem.device = this;
mem.device_pointer = key;
stats.mem_alloc(mem.device_size);
return true;
}
void mem_alloc(device_memory &mem)
{
device_ptr key = unique_key++;

File diff suppressed because it is too large Load Diff

View File

@ -64,6 +64,10 @@ set(SRC_OPENCL_KERNELS
kernels/opencl/filter.cl
)
set(SRC_OPTIX_KERNELS
kernels/optix/kernel_optix.cu
)
set(SRC_BVH_HEADERS
bvh/bvh.h
bvh/bvh_nodes.h
@ -95,6 +99,7 @@ set(SRC_HEADERS
kernel_color.h
kernel_compat_cpu.h
kernel_compat_cuda.h
kernel_compat_optix.h
kernel_compat_opencl.h
kernel_differential.h
kernel_emission.h
@ -140,6 +145,9 @@ set(SRC_KERNELS_CUDA_HEADERS
kernels/cuda/kernel_cuda_image.h
)
set(SRC_KERNELS_OPTIX_HEADERS
)
set(SRC_KERNELS_OPENCL_HEADERS
kernels/opencl/kernel_split_function.h
kernels/opencl/kernel_opencl_image.h
@ -168,7 +176,7 @@ set(SRC_CLOSURE_HEADERS
closure/volume.h
closure/bsdf_principled_diffuse.h
closure/bsdf_principled_sheen.h
closure/bsdf_hair_principled.h
closure/bsdf_hair_principled.h
)
set(SRC_SVM_HEADERS
@ -476,6 +484,53 @@ if(WITH_CYCLES_CUDA_BINARIES)
cycles_set_solution_folder(cycles_kernel_cuda)
endif()
# OptiX PTX modules
if(WITH_CYCLES_DEVICE_OPTIX)
foreach(input ${SRC_OPTIX_KERNELS})
get_filename_component(input_we ${input} NAME_WE)
set(output "${CMAKE_CURRENT_BINARY_DIR}/${input_we}.ptx")
set(cuda_flags
-I "${OPTIX_INCLUDE_DIR}"
-I "${CMAKE_CURRENT_SOURCE_DIR}/.."
-I "${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda"
-arch=sm_30
--use_fast_math
-o ${output})
if(WITH_CYCLES_DEBUG)
set(cuda_flags ${cuda_flags}
-D __KERNEL_DEBUG__)
endif()
add_custom_command(
OUTPUT
${output}
DEPENDS
${input}
${SRC_HEADERS}
${SRC_KERNELS_CUDA_HEADERS}
${SRC_KERNELS_OPTIX_HEADERS}
${SRC_BVH_HEADERS}
${SRC_SVM_HEADERS}
${SRC_GEOM_HEADERS}
${SRC_CLOSURE_HEADERS}
${SRC_UTIL_HEADERS}
COMMAND
${CUDA_NVCC_EXECUTABLE} --ptx ${cuda_flags} ${input}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}")
list(APPEND optix_ptx ${output})
delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${output}" ${CYCLES_INSTALL_PATH}/lib)
endforeach()
add_custom_target(cycles_kernel_optix ALL DEPENDS ${optix_ptx})
cycles_set_solution_folder(cycles_kernel_optix)
endif()
# OSL module
if(WITH_CYCLES_OSL)
@ -535,10 +590,12 @@ endif()
cycles_add_library(cycles_kernel "${LIB}"
${SRC_CPU_KERNELS}
${SRC_CUDA_KERNELS}
${SRC_OPTIX_KERNELS}
${SRC_OPENCL_KERNELS}
${SRC_HEADERS}
${SRC_KERNELS_CPU_HEADERS}
${SRC_KERNELS_CUDA_HEADERS}
${SRC_KERNELS_OPTIX_HEADERS}
${SRC_KERNELS_OPENCL_HEADERS}
${SRC_BVH_HEADERS}
${SRC_CLOSURE_HEADERS}
@ -548,9 +605,24 @@ cycles_add_library(cycles_kernel "${LIB}"
${SRC_SPLIT_HEADERS}
)
source_group("bvh" FILES ${SRC_BVH_HEADERS})
source_group("closure" FILES ${SRC_CLOSURE_HEADERS})
source_group("filter" FILES ${SRC_FILTER_HEADERS})
source_group("geom" FILES ${SRC_GEOM_HEADERS})
source_group("kernel" FILES ${SRC_HEADERS})
source_group("kernel\\split" FILES ${SRC_SPLIT_HEADERS})
source_group("kernels\\cpu" FILES ${SRC_CPU_KERNELS} ${SRC_KERNELS_CPU_HEADERS})
source_group("kernels\\cuda" FILES ${SRC_CUDA_KERNELS} ${SRC_KERNELS_CUDA_HEADERS})
source_group("kernels\\opencl" FILES ${SRC_OPENCL_KERNELS} ${SRC_KERNELS_OPENCL_HEADERS})
source_group("kernels\\optix" FILES ${SRC_OPTIX_KERNELS} ${SRC_KERNELS_OPTIX_HEADERS})
source_group("svm" FILES ${SRC_SVM_HEADERS})
if(WITH_CYCLES_CUDA)
add_dependencies(cycles_kernel cycles_kernel_cuda)
endif()
if(WITH_CYCLES_DEVICE_OPTIX)
add_dependencies(cycles_kernel cycles_kernel_optix)
endif()
# OpenCL kernel
@ -564,9 +636,11 @@ endif()
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_OPENCL_KERNELS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CUDA_KERNELS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/cuda)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_OPTIX_KERNELS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/optix)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNELS_OPENCL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/opencl)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNELS_CUDA_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/cuda)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNELS_OPTIX_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/kernels/optix)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/bvh)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/closure)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_FILTER_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/filter)

View File

@ -1139,9 +1139,9 @@ int Mesh::motion_step(float time) const
return -1;
}
bool Mesh::need_build_bvh(BVHLayout) const
bool Mesh::need_build_bvh(BVHLayout layout) const
{
return !transform_applied || has_surface_bssrdf;
return !transform_applied || has_surface_bssrdf || layout == BVH_LAYOUT_OPTIX;
}
bool Mesh::is_instanced() const

View File

@ -86,6 +86,16 @@ void DebugFlags::CUDA::reset()
split_kernel = false;
}
DebugFlags::OptiX::OptiX()
{
reset();
}
void DebugFlags::OptiX::reset()
{
cuda_streams = 1;
}
DebugFlags::OpenCL::OpenCL() : device_type(DebugFlags::OpenCL::DEVICE_ALL), debug(false)
{
reset();
@ -130,6 +140,7 @@ void DebugFlags::reset()
viewport_static_bvh = false;
cpu.reset();
cuda.reset();
optix.reset();
opencl.reset();
}
@ -145,7 +156,10 @@ std::ostream &operator<<(std::ostream &os, DebugFlagsConstRef debug_flags)
<< " Split : " << string_from_bool(debug_flags.cpu.split_kernel) << "\n";
os << "CUDA flags:\n"
<< " Adaptive Compile: " << string_from_bool(debug_flags.cuda.adaptive_compile) << "\n";
<< " Adaptive Compile : " << string_from_bool(debug_flags.cuda.adaptive_compile) << "\n";
os << "OptiX flags:\n"
<< " CUDA streams : " << debug_flags.optix.cuda_streams << "\n";
const char *opencl_device_type;
switch (debug_flags.opencl.device_type) {

View File

@ -99,6 +99,17 @@ class DebugFlags {
bool split_kernel;
};
/* Descriptor of OptiX feature-set to be used. */
struct OptiX {
OptiX();
/* Reset flags to their defaults. */
void reset();
/* Number of CUDA streams to launch kernels concurrently from. */
int cuda_streams;
};
/* Descriptor of OpenCL feature-set to be used. */
struct OpenCL {
OpenCL();
@ -165,6 +176,9 @@ class DebugFlags {
/* Requested CUDA flags. */
CUDA cuda;
/* Requested OptiX flags. */
OptiX optix;
/* Requested OpenCL flags. */
OpenCL opencl;