diff options
author | Patrick Mours <pmours@nvidia.com> | 2019-09-12 15:50:06 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-09-13 12:50:11 +0300 |
commit | a2b52dc5716a97e5413acbd6eefc9ce3788b6456 (patch) | |
tree | 7e6d6c17b73671e67c1f7fbdadd821b4541f820f /intern/cycles/bvh | |
parent | 53932f1f068501bfb095c407a7777a964dc5ec1c (diff) |
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
Diffstat (limited to 'intern/cycles/bvh')
-rw-r--r-- | intern/cycles/bvh/CMakeLists.txt | 2 | ||||
-rw-r--r-- | intern/cycles/bvh/bvh.cpp | 11 | ||||
-rw-r--r-- | intern/cycles/bvh/bvh_optix.cpp | 215 | ||||
-rw-r--r-- | intern/cycles/bvh/bvh_optix.h | 53 |
4 files changed, 281 insertions, 0 deletions
diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt index 36bbd937e1a..27a7f604e1c 100644 --- a/intern/cycles/bvh/CMakeLists.txt +++ b/intern/cycles/bvh/CMakeLists.txt @@ -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 diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index b6a4aba74b5..16c721da06a 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -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"; } @@ -116,6 +121,12 @@ BVH *BVH::create(const BVHParams ¶ms, #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: break; diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp new file mode 100644 index 00000000000..b3a9aab3266 --- /dev/null +++ b/intern/cycles/bvh/bvh_optix.cpp @@ -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 ¶ms_, + 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 */ diff --git a/intern/cycles/bvh/bvh_optix.h b/intern/cycles/bvh/bvh_optix.h new file mode 100644 index 00000000000..35033fe635f --- /dev/null +++ b/intern/cycles/bvh/bvh_optix.h @@ -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 ¶ms, 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__ */ |