Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/blender/addon/properties.py2
-rw-r--r--intern/cycles/blender/blender_device.cpp3
-rw-r--r--intern/cycles/bvh/CMakeLists.txt2
-rw-r--r--intern/cycles/bvh/bvh.cpp432
-rw-r--r--intern/cycles/bvh/bvh.h48
-rw-r--r--intern/cycles/bvh/bvh2.cpp409
-rw-r--r--intern/cycles/bvh/bvh2.h39
-rw-r--r--intern/cycles/bvh/bvh_embree.cpp329
-rw-r--r--intern/cycles/bvh/bvh_embree.h32
-rw-r--r--intern/cycles/bvh/bvh_multi.cpp37
-rw-r--r--intern/cycles/bvh/bvh_multi.h39
-rw-r--r--intern/cycles/bvh/bvh_optix.cpp204
-rw-r--r--intern/cycles/bvh/bvh_optix.h28
-rw-r--r--intern/cycles/device/cuda/device_cuda.h1
-rw-r--r--intern/cycles/device/cuda/device_cuda_impl.cpp22
-rw-r--r--intern/cycles/device/device.cpp15
-rw-r--r--intern/cycles/device/device.h11
-rw-r--r--intern/cycles/device/device_cpu.cpp33
-rw-r--r--intern/cycles/device/device_multi.cpp123
-rw-r--r--intern/cycles/device/device_optix.cpp463
-rw-r--r--intern/cycles/device/opencl/opencl_util.cpp22
-rw-r--r--intern/cycles/kernel/bvh/bvh_embree.h6
-rw-r--r--intern/cycles/kernel/kernel_types.h4
-rw-r--r--intern/cycles/render/geometry.cpp88
-rw-r--r--intern/cycles/render/geometry.h3
-rw-r--r--intern/cycles/render/hair.cpp35
-rw-r--r--intern/cycles/render/hair.h2
-rw-r--r--intern/cycles/render/image.cpp4
-rw-r--r--intern/cycles/render/mesh.cpp31
-rw-r--r--intern/cycles/render/mesh.h5
-rw-r--r--intern/cycles/render/scene.cpp5
-rw-r--r--intern/cycles/render/scene.h2
-rw-r--r--intern/cycles/render/shader.cpp11
-rw-r--r--intern/ghost/CMakeLists.txt14
-rw-r--r--intern/ghost/GHOST_C-api.h2
-rw-r--r--intern/ghost/GHOST_ISystemPaths.h6
-rw-r--r--intern/ghost/GHOST_Path-api.h6
-rw-r--r--intern/ghost/GHOST_Types.h10
-rw-r--r--intern/ghost/intern/GHOST_Path-api.cpp6
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm11
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsCocoa.h6
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsCocoa.mm52
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.cpp59
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.h6
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsWin32.cpp45
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsWin32.h6
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp4
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp69
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h14
50 files changed, 1413 insertions, 1395 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 1cb29fc6cb0..2f204b2c658 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -1570,7 +1570,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
elif entry.type == 'CPU':
cpu_devices.append(entry)
# Extend all GPU devices with CPU.
- if compute_device_type in {'CUDA', 'OPENCL'}:
+ if compute_device_type in {'CUDA', 'OPTIX', 'OPENCL'}:
devices.extend(cpu_devices)
return devices
diff --git a/intern/cycles/blender/blender_device.cpp b/intern/cycles/blender/blender_device.cpp
index ffcaef0b2a9..977f8297de1 100644
--- a/intern/cycles/blender/blender_device.cpp
+++ b/intern/cycles/blender/blender_device.cpp
@@ -90,8 +90,7 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
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;
+ mask |= DEVICE_MASK_OPTIX;
}
else if (compute_device == COMPUTE_DEVICE_OPENCL) {
mask |= DEVICE_MASK_OPENCL;
diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt
index 703c69b1797..8cc72359757 100644
--- a/intern/cycles/bvh/CMakeLists.txt
+++ b/intern/cycles/bvh/CMakeLists.txt
@@ -25,6 +25,7 @@ set(SRC
bvh_binning.cpp
bvh_build.cpp
bvh_embree.cpp
+ bvh_multi.cpp
bvh_node.cpp
bvh_optix.cpp
bvh_sort.cpp
@@ -38,6 +39,7 @@ set(SRC_HEADERS
bvh_binning.h
bvh_build.h
bvh_embree.h
+ bvh_multi.h
bvh_node.h
bvh_optix.h
bvh_params.h
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index a51ac4cf4a9..256382e63ba 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -17,17 +17,11 @@
#include "bvh/bvh.h"
-#include "render/hair.h"
-#include "render/mesh.h"
-#include "render/object.h"
-
#include "bvh/bvh2.h"
-#include "bvh/bvh_build.h"
#include "bvh/bvh_embree.h"
-#include "bvh/bvh_node.h"
+#include "bvh/bvh_multi.h"
#include "bvh/bvh_optix.h"
-#include "util/util_foreach.h"
#include "util/util_logging.h"
#include "util/util_progress.h"
@@ -38,14 +32,17 @@ CCL_NAMESPACE_BEGIN
const char *bvh_layout_name(BVHLayout layout)
{
switch (layout) {
- case BVH_LAYOUT_BVH2:
- return "BVH2";
case BVH_LAYOUT_NONE:
return "NONE";
+ case BVH_LAYOUT_BVH2:
+ return "BVH2";
case BVH_LAYOUT_EMBREE:
return "EMBREE";
case BVH_LAYOUT_OPTIX:
return "OPTIX";
+ case BVH_LAYOUT_MULTI_OPTIX:
+ case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
+ return "MULTI";
case BVH_LAYOUT_ALL:
return "ALL";
}
@@ -76,17 +73,6 @@ BVHLayout BVHParams::best_bvh_layout(BVHLayout requested_layout, BVHLayoutMask s
return (BVHLayout)(1 << widest_allowed_layout_mask);
}
-/* Pack Utility */
-
-BVHStackEntry::BVHStackEntry(const BVHNode *n, int i) : node(n), idx(i)
-{
-}
-
-int BVHStackEntry::encodeIdx() const
-{
- return (node->is_leaf()) ? ~idx : idx;
-}
-
/* BVH */
BVH::BVH(const BVHParams &params_,
@@ -99,24 +85,27 @@ BVH::BVH(const BVHParams &params_,
BVH *BVH::create(const BVHParams &params,
const vector<Geometry *> &geometry,
const vector<Object *> &objects,
- const Device *device)
+ Device *device)
{
switch (params.bvh_layout) {
case BVH_LAYOUT_BVH2:
return new BVH2(params, geometry, objects);
case BVH_LAYOUT_EMBREE:
#ifdef WITH_EMBREE
- return new BVHEmbree(params, geometry, objects, device);
+ return new BVHEmbree(params, geometry, objects);
#else
- (void)device;
break;
#endif
case BVH_LAYOUT_OPTIX:
#ifdef WITH_OPTIX
- return new BVHOptiX(params, geometry, objects);
+ return new BVHOptiX(params, geometry, objects, device);
#else
+ (void)device;
break;
#endif
+ case BVH_LAYOUT_MULTI_OPTIX:
+ case BVH_LAYOUT_MULTI_OPTIX_EMBREE:
+ return new BVHMulti(params, geometry, objects);
case BVH_LAYOUT_NONE:
case BVH_LAYOUT_ALL:
break;
@@ -125,399 +114,4 @@ BVH *BVH::create(const BVHParams &params,
return NULL;
}
-/* Building */
-
-void BVH::build(Progress &progress, Stats *)
-{
- progress.set_substatus("Building BVH");
-
- /* build nodes */
- BVHBuild bvh_build(objects,
- pack.prim_type,
- pack.prim_index,
- pack.prim_object,
- pack.prim_time,
- params,
- progress);
- BVHNode *bvh2_root = bvh_build.run();
-
- if (progress.get_cancel()) {
- if (bvh2_root != NULL) {
- bvh2_root->deleteSubtree();
- }
- return;
- }
-
- /* BVH builder returns tree in a binary mode (with two children per inner
- * node. Need to adopt that for a wider BVH implementations. */
- BVHNode *root = widen_children_nodes(bvh2_root);
- if (root != bvh2_root) {
- bvh2_root->deleteSubtree();
- }
-
- if (progress.get_cancel()) {
- if (root != NULL) {
- root->deleteSubtree();
- }
- return;
- }
-
- /* pack triangles */
- progress.set_substatus("Packing BVH triangles and strands");
- pack_primitives();
-
- if (progress.get_cancel()) {
- root->deleteSubtree();
- return;
- }
-
- /* pack nodes */
- progress.set_substatus("Packing BVH nodes");
- pack_nodes(root);
-
- /* free build nodes */
- root->deleteSubtree();
-}
-
-/* Refitting */
-
-void BVH::refit(Progress &progress)
-{
- progress.set_substatus("Packing BVH primitives");
- pack_primitives();
-
- if (progress.get_cancel())
- return;
-
- progress.set_substatus("Refitting BVH nodes");
- refit_nodes();
-}
-
-void BVH::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility)
-{
- /* Refit range of primitives. */
- for (int prim = start; prim < end; prim++) {
- int pidx = pack.prim_index[prim];
- int tob = pack.prim_object[prim];
- Object *ob = objects[tob];
-
- if (pidx == -1) {
- /* Object instance. */
- bbox.grow(ob->bounds);
- }
- else {
- /* Primitives. */
- if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
- /* Curves. */
- const Hair *hair = static_cast<const Hair *>(ob->get_geometry());
- int prim_offset = (params.top_level) ? hair->prim_offset : 0;
- Hair::Curve curve = hair->get_curve(pidx - prim_offset);
- int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
-
- curve.bounds_grow(k, &hair->get_curve_keys()[0], &hair->get_curve_radius()[0], bbox);
-
- /* Motion curves. */
- if (hair->get_use_motion_blur()) {
- Attribute *attr = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if (attr) {
- size_t hair_size = hair->get_curve_keys().size();
- size_t steps = hair->get_motion_steps() - 1;
- float3 *key_steps = attr->data_float3();
-
- for (size_t i = 0; i < steps; i++)
- curve.bounds_grow(k, key_steps + i * hair_size, &hair->get_curve_radius()[0], bbox);
- }
- }
- }
- else {
- /* Triangles. */
- const Mesh *mesh = static_cast<const Mesh *>(ob->get_geometry());
- int prim_offset = (params.top_level) ? mesh->prim_offset : 0;
- Mesh::Triangle triangle = mesh->get_triangle(pidx - prim_offset);
- const float3 *vpos = &mesh->verts[0];
-
- triangle.bounds_grow(vpos, bbox);
-
- /* Motion triangles. */
- if (mesh->use_motion_blur) {
- Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
- if (attr) {
- size_t mesh_size = mesh->verts.size();
- size_t steps = mesh->motion_steps - 1;
- float3 *vert_steps = attr->data_float3();
-
- for (size_t i = 0; i < steps; i++)
- triangle.bounds_grow(vert_steps + i * mesh_size, bbox);
- }
- }
- }
- }
- visibility |= ob->visibility_for_tracing();
- }
-}
-
-/* Triangles */
-
-void BVH::pack_triangle(int idx, float4 tri_verts[3])
-{
- int tob = pack.prim_object[idx];
- assert(tob >= 0 && tob < objects.size());
- const Mesh *mesh = static_cast<const Mesh *>(objects[tob]->get_geometry());
-
- int tidx = pack.prim_index[idx];
- Mesh::Triangle t = mesh->get_triangle(tidx);
- const float3 *vpos = &mesh->verts[0];
- float3 v0 = vpos[t.v[0]];
- float3 v1 = vpos[t.v[1]];
- float3 v2 = vpos[t.v[2]];
-
- tri_verts[0] = float3_to_float4(v0);
- tri_verts[1] = float3_to_float4(v1);
- tri_verts[2] = float3_to_float4(v2);
-}
-
-void BVH::pack_primitives()
-{
- const size_t tidx_size = pack.prim_index.size();
- size_t num_prim_triangles = 0;
- /* Count number of triangles primitives in BVH. */
- for (unsigned int i = 0; i < tidx_size; i++) {
- if ((pack.prim_index[i] != -1)) {
- if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
- ++num_prim_triangles;
- }
- }
- }
- /* Reserve size for arrays. */
- pack.prim_tri_index.clear();
- pack.prim_tri_index.resize(tidx_size);
- pack.prim_tri_verts.clear();
- pack.prim_tri_verts.resize(num_prim_triangles * 3);
- pack.prim_visibility.clear();
- pack.prim_visibility.resize(tidx_size);
- /* Fill in all the arrays. */
- size_t prim_triangle_index = 0;
- for (unsigned int i = 0; i < tidx_size; i++) {
- if (pack.prim_index[i] != -1) {
- int tob = pack.prim_object[i];
- Object *ob = objects[tob];
- if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
- pack_triangle(i, (float4 *)&pack.prim_tri_verts[3 * prim_triangle_index]);
- pack.prim_tri_index[i] = 3 * prim_triangle_index;
- ++prim_triangle_index;
- }
- else {
- pack.prim_tri_index[i] = -1;
- }
- pack.prim_visibility[i] = ob->visibility_for_tracing();
- }
- else {
- pack.prim_tri_index[i] = -1;
- pack.prim_visibility[i] = 0;
- }
- }
-}
-
-/* Pack Instances */
-
-void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
-{
- /* Adjust primitive index to point to the triangle in the global array, for
- * geometry with transform applied and already in the top level BVH.
- */
- for (size_t i = 0; i < pack.prim_index.size(); i++) {
- if (pack.prim_index[i] != -1) {
- pack.prim_index[i] += objects[pack.prim_object[i]]->get_geometry()->prim_offset;
- }
- }
-
- /* track offsets of instanced BVH data in global array */
- size_t prim_offset = pack.prim_index.size();
- size_t nodes_offset = nodes_size;
- size_t nodes_leaf_offset = leaf_nodes_size;
-
- /* clear array that gives the node indexes for instanced objects */
- pack.object_node.clear();
-
- /* reserve */
- size_t prim_index_size = pack.prim_index.size();
- size_t prim_tri_verts_size = pack.prim_tri_verts.size();
-
- size_t pack_prim_index_offset = prim_index_size;
- size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
- size_t pack_nodes_offset = nodes_size;
- size_t pack_leaf_nodes_offset = leaf_nodes_size;
- size_t object_offset = 0;
-
- foreach (Geometry *geom, geometry) {
- BVH *bvh = geom->bvh;
-
- if (geom->need_build_bvh(params.bvh_layout)) {
- prim_index_size += bvh->pack.prim_index.size();
- prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
- nodes_size += bvh->pack.nodes.size();
- leaf_nodes_size += bvh->pack.leaf_nodes.size();
- }
- }
-
- pack.prim_index.resize(prim_index_size);
- pack.prim_type.resize(prim_index_size);
- pack.prim_object.resize(prim_index_size);
- pack.prim_visibility.resize(prim_index_size);
- pack.prim_tri_verts.resize(prim_tri_verts_size);
- pack.prim_tri_index.resize(prim_index_size);
- pack.nodes.resize(nodes_size);
- pack.leaf_nodes.resize(leaf_nodes_size);
- pack.object_node.resize(objects.size());
-
- if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) {
- pack.prim_time.resize(prim_index_size);
- }
-
- int *pack_prim_index = (pack.prim_index.size()) ? &pack.prim_index[0] : NULL;
- int *pack_prim_type = (pack.prim_type.size()) ? &pack.prim_type[0] : NULL;
- int *pack_prim_object = (pack.prim_object.size()) ? &pack.prim_object[0] : NULL;
- uint *pack_prim_visibility = (pack.prim_visibility.size()) ? &pack.prim_visibility[0] : NULL;
- float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size()) ? &pack.prim_tri_verts[0] : NULL;
- uint *pack_prim_tri_index = (pack.prim_tri_index.size()) ? &pack.prim_tri_index[0] : NULL;
- int4 *pack_nodes = (pack.nodes.size()) ? &pack.nodes[0] : NULL;
- int4 *pack_leaf_nodes = (pack.leaf_nodes.size()) ? &pack.leaf_nodes[0] : NULL;
- float2 *pack_prim_time = (pack.prim_time.size()) ? &pack.prim_time[0] : NULL;
-
- map<Geometry *, int> geometry_map;
-
- /* merge */
- foreach (Object *ob, objects) {
- Geometry *geom = ob->get_geometry();
-
- /* We assume that if mesh doesn't need own BVH it was already included
- * into a top-level BVH and no packing here is needed.
- */
- if (!geom->need_build_bvh(params.bvh_layout)) {
- pack.object_node[object_offset++] = 0;
- continue;
- }
-
- /* if mesh already added once, don't add it again, but used set
- * node offset for this object */
- map<Geometry *, int>::iterator it = geometry_map.find(geom);
-
- if (geometry_map.find(geom) != geometry_map.end()) {
- int noffset = it->second;
- pack.object_node[object_offset++] = noffset;
- continue;
- }
-
- BVH *bvh = geom->bvh;
-
- int noffset = nodes_offset;
- int noffset_leaf = nodes_leaf_offset;
- int geom_prim_offset = geom->prim_offset;
-
- /* fill in node indexes for instances */
- if (bvh->pack.root_index == -1)
- pack.object_node[object_offset++] = -noffset_leaf - 1;
- else
- pack.object_node[object_offset++] = noffset;
-
- geometry_map[geom] = pack.object_node[object_offset - 1];
-
- /* merge primitive, object and triangle indexes */
- if (bvh->pack.prim_index.size()) {
- size_t bvh_prim_index_size = bvh->pack.prim_index.size();
- int *bvh_prim_index = &bvh->pack.prim_index[0];
- int *bvh_prim_type = &bvh->pack.prim_type[0];
- uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
- uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
- float2 *bvh_prim_time = bvh->pack.prim_time.size() ? &bvh->pack.prim_time[0] : NULL;
-
- for (size_t i = 0; i < bvh_prim_index_size; i++) {
- if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
- pack_prim_tri_index[pack_prim_index_offset] = -1;
- }
- else {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
- pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] +
- pack_prim_tri_verts_offset;
- }
-
- pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
- pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
- pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
- if (bvh_prim_time != NULL) {
- pack_prim_time[pack_prim_index_offset] = bvh_prim_time[i];
- }
- pack_prim_index_offset++;
- }
- }
-
- /* Merge triangle vertices data. */
- if (bvh->pack.prim_tri_verts.size()) {
- const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
- memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
- &bvh->pack.prim_tri_verts[0],
- prim_tri_size * sizeof(float4));
- pack_prim_tri_verts_offset += prim_tri_size;
- }
-
- /* merge nodes */
- if (bvh->pack.leaf_nodes.size()) {
- int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0];
- size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size();
- for (size_t i = 0, j = 0; i < leaf_nodes_offset_size; i += BVH_NODE_LEAF_SIZE, j++) {
- int4 data = leaf_nodes_offset[i];
- data.x += prim_offset;
- data.y += prim_offset;
- pack_leaf_nodes[pack_leaf_nodes_offset] = data;
- for (int j = 1; j < BVH_NODE_LEAF_SIZE; ++j) {
- pack_leaf_nodes[pack_leaf_nodes_offset + j] = leaf_nodes_offset[i + j];
- }
- pack_leaf_nodes_offset += BVH_NODE_LEAF_SIZE;
- }
- }
-
- if (bvh->pack.nodes.size()) {
- int4 *bvh_nodes = &bvh->pack.nodes[0];
- size_t bvh_nodes_size = bvh->pack.nodes.size();
-
- for (size_t i = 0, j = 0; i < bvh_nodes_size; j++) {
- size_t nsize, nsize_bbox;
- if (bvh_nodes[i].x & PATH_RAY_NODE_UNALIGNED) {
- nsize = BVH_UNALIGNED_NODE_SIZE;
- nsize_bbox = 0;
- }
- else {
- nsize = BVH_NODE_SIZE;
- nsize_bbox = 0;
- }
-
- memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox * sizeof(int4));
-
- /* Modify offsets into arrays */
- int4 data = bvh_nodes[i + nsize_bbox];
- data.z += (data.z < 0) ? -noffset_leaf : noffset;
- data.w += (data.w < 0) ? -noffset_leaf : noffset;
- pack_nodes[pack_nodes_offset + nsize_bbox] = data;
-
- /* Usually this copies nothing, but we better
- * be prepared for possible node size extension.
- */
- memcpy(&pack_nodes[pack_nodes_offset + nsize_bbox + 1],
- &bvh_nodes[i + nsize_bbox + 1],
- sizeof(int4) * (nsize - (nsize_bbox + 1)));
-
- pack_nodes_offset += nsize;
- i += nsize;
- }
- }
-
- nodes_offset += bvh->pack.nodes.size();
- nodes_leaf_offset += bvh->pack.leaf_nodes.size();
- prim_offset += bvh->pack.prim_index.size();
- }
-}
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index 033b1fd8e04..94935c26f10 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -25,17 +25,16 @@
CCL_NAMESPACE_BEGIN
-class Stats;
-class Device;
-class DeviceScene;
+class BoundBox;
class BVHNode;
-struct BVHStackEntry;
class BVHParams;
-class BoundBox;
-class LeafNode;
+class Device;
+class DeviceScene;
class Geometry;
+class LeafNode;
class Object;
class Progress;
+class Stats;
#define BVH_ALIGN 4096
#define TRI_NODE_SIZE 3
@@ -76,13 +75,10 @@ struct PackedBVH {
}
};
-enum BVH_TYPE { bvh2 };
-
/* BVH */
class BVH {
public:
- PackedBVH pack;
BVHParams params;
vector<Geometry *> geometry;
vector<Object *> objects;
@@ -90,47 +86,15 @@ class BVH {
static BVH *create(const BVHParams &params,
const vector<Geometry *> &geometry,
const vector<Object *> &objects,
- const Device *device);
+ Device *device);
virtual ~BVH()
{
}
- virtual void build(Progress &progress, Stats *stats = NULL);
- virtual void copy_to_device(Progress & /*progress*/, DeviceScene * /*dscene*/)
- {
- }
-
- void refit(Progress &progress);
-
protected:
BVH(const BVHParams &params,
const vector<Geometry *> &geometry,
const vector<Object *> &objects);
-
- /* Refit range of primitives. */
- void refit_primitives(int start, int end, BoundBox &bbox, uint &visibility);
-
- /* triangles and strands */
- void pack_primitives();
- void pack_triangle(int idx, float4 storage[3]);
-
- /* merge instance BVH's */
- void pack_instances(size_t nodes_size, size_t leaf_nodes_size);
-
- /* for subclasses to implement */
- virtual void pack_nodes(const BVHNode *root) = 0;
- virtual void refit_nodes() = 0;
-
- virtual BVHNode *widen_children_nodes(const BVHNode *root) = 0;
-};
-
-/* Pack Utility */
-struct BVHStackEntry {
- const BVHNode *node;
- int idx;
-
- BVHStackEntry(const BVHNode *n = 0, int i = 0);
- int encodeIdx() const;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp
index c903070429e..379ae9b25ff 100644
--- a/intern/cycles/bvh/bvh2.cpp
+++ b/intern/cycles/bvh/bvh2.cpp
@@ -17,14 +17,28 @@
#include "bvh/bvh2.h"
+#include "render/hair.h"
#include "render/mesh.h"
#include "render/object.h"
+#include "bvh/bvh_build.h"
#include "bvh/bvh_node.h"
#include "bvh/bvh_unaligned.h"
+#include "util/util_foreach.h"
+#include "util/util_progress.h"
+
CCL_NAMESPACE_BEGIN
+BVHStackEntry::BVHStackEntry(const BVHNode *n, int i) : node(n), idx(i)
+{
+}
+
+int BVHStackEntry::encodeIdx() const
+{
+ return (node->is_leaf()) ? ~idx : idx;
+}
+
BVH2::BVH2(const BVHParams &params_,
const vector<Geometry *> &geometry_,
const vector<Object *> &objects_)
@@ -32,6 +46,70 @@ BVH2::BVH2(const BVHParams &params_,
{
}
+void BVH2::build(Progress &progress, Stats *)
+{
+ progress.set_substatus("Building BVH");
+
+ /* build nodes */
+ BVHBuild bvh_build(objects,
+ pack.prim_type,
+ pack.prim_index,
+ pack.prim_object,
+ pack.prim_time,
+ params,
+ progress);
+ BVHNode *bvh2_root = bvh_build.run();
+
+ if (progress.get_cancel()) {
+ if (bvh2_root != NULL) {
+ bvh2_root->deleteSubtree();
+ }
+ return;
+ }
+
+ /* BVH builder returns tree in a binary mode (with two children per inner
+ * node. Need to adopt that for a wider BVH implementations. */
+ BVHNode *root = widen_children_nodes(bvh2_root);
+ if (root != bvh2_root) {
+ bvh2_root->deleteSubtree();
+ }
+
+ if (progress.get_cancel()) {
+ if (root != NULL) {
+ root->deleteSubtree();
+ }
+ return;
+ }
+
+ /* pack triangles */
+ progress.set_substatus("Packing BVH triangles and strands");
+ pack_primitives();
+
+ if (progress.get_cancel()) {
+ root->deleteSubtree();
+ return;
+ }
+
+ /* pack nodes */
+ progress.set_substatus("Packing BVH nodes");
+ pack_nodes(root);
+
+ /* free build nodes */
+ root->deleteSubtree();
+}
+
+void BVH2::refit(Progress &progress)
+{
+ progress.set_substatus("Packing BVH primitives");
+ pack_primitives();
+
+ if (progress.get_cancel())
+ return;
+
+ progress.set_substatus("Refitting BVH nodes");
+ refit_nodes();
+}
+
BVHNode *BVH2::widen_children_nodes(const BVHNode *root)
{
return const_cast<BVHNode *>(root);
@@ -253,7 +331,7 @@ void BVH2::refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility)
const int c0 = data[0].x;
const int c1 = data[0].y;
- BVH::refit_primitives(c0, c1, bbox, visibility);
+ refit_primitives(c0, c1, bbox, visibility);
/* TODO(sergey): De-duplicate with pack_leaf(). */
float4 leaf_data[BVH_NODE_LEAF_SIZE];
@@ -292,4 +370,333 @@ void BVH2::refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility)
}
}
+/* Refitting */
+
+void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility)
+{
+ /* Refit range of primitives. */
+ for (int prim = start; prim < end; prim++) {
+ int pidx = pack.prim_index[prim];
+ int tob = pack.prim_object[prim];
+ Object *ob = objects[tob];
+
+ if (pidx == -1) {
+ /* Object instance. */
+ bbox.grow(ob->bounds);
+ }
+ else {
+ /* Primitives. */
+ if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
+ /* Curves. */
+ const Hair *hair = static_cast<const Hair *>(ob->get_geometry());
+ int prim_offset = (params.top_level) ? hair->prim_offset : 0;
+ Hair::Curve curve = hair->get_curve(pidx - prim_offset);
+ int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
+
+ curve.bounds_grow(k, &hair->get_curve_keys()[0], &hair->get_curve_radius()[0], bbox);
+
+ /* Motion curves. */
+ if (hair->get_use_motion_blur()) {
+ Attribute *attr = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ size_t hair_size = hair->get_curve_keys().size();
+ size_t steps = hair->get_motion_steps() - 1;
+ float3 *key_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps; i++)
+ curve.bounds_grow(k, key_steps + i * hair_size, &hair->get_curve_radius()[0], bbox);
+ }
+ }
+ }
+ else {
+ /* Triangles. */
+ const Mesh *mesh = static_cast<const Mesh *>(ob->get_geometry());
+ int prim_offset = (params.top_level) ? mesh->prim_offset : 0;
+ Mesh::Triangle triangle = mesh->get_triangle(pidx - prim_offset);
+ const float3 *vpos = &mesh->verts[0];
+
+ triangle.bounds_grow(vpos, bbox);
+
+ /* Motion triangles. */
+ if (mesh->use_motion_blur) {
+ Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (attr) {
+ size_t mesh_size = mesh->verts.size();
+ size_t steps = mesh->motion_steps - 1;
+ float3 *vert_steps = attr->data_float3();
+
+ for (size_t i = 0; i < steps; i++)
+ triangle.bounds_grow(vert_steps + i * mesh_size, bbox);
+ }
+ }
+ }
+ }
+ visibility |= ob->visibility_for_tracing();
+ }
+}
+
+/* Triangles */
+
+void BVH2::pack_triangle(int idx, float4 tri_verts[3])
+{
+ int tob = pack.prim_object[idx];
+ assert(tob >= 0 && tob < objects.size());
+ const Mesh *mesh = static_cast<const Mesh *>(objects[tob]->get_geometry());
+
+ int tidx = pack.prim_index[idx];
+ Mesh::Triangle t = mesh->get_triangle(tidx);
+ const float3 *vpos = &mesh->verts[0];
+ float3 v0 = vpos[t.v[0]];
+ float3 v1 = vpos[t.v[1]];
+ float3 v2 = vpos[t.v[2]];
+
+ tri_verts[0] = float3_to_float4(v0);
+ tri_verts[1] = float3_to_float4(v1);
+ tri_verts[2] = float3_to_float4(v2);
+}
+
+void BVH2::pack_primitives()
+{
+ const size_t tidx_size = pack.prim_index.size();
+ size_t num_prim_triangles = 0;
+ /* Count number of triangles primitives in BVH. */
+ for (unsigned int i = 0; i < tidx_size; i++) {
+ if ((pack.prim_index[i] != -1)) {
+ if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ ++num_prim_triangles;
+ }
+ }
+ }
+ /* Reserve size for arrays. */
+ pack.prim_tri_index.clear();
+ pack.prim_tri_index.resize(tidx_size);
+ pack.prim_tri_verts.clear();
+ pack.prim_tri_verts.resize(num_prim_triangles * 3);
+ pack.prim_visibility.clear();
+ pack.prim_visibility.resize(tidx_size);
+ /* Fill in all the arrays. */
+ size_t prim_triangle_index = 0;
+ for (unsigned int i = 0; i < tidx_size; i++) {
+ if (pack.prim_index[i] != -1) {
+ int tob = pack.prim_object[i];
+ Object *ob = objects[tob];
+ if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ pack_triangle(i, (float4 *)&pack.prim_tri_verts[3 * prim_triangle_index]);
+ pack.prim_tri_index[i] = 3 * prim_triangle_index;
+ ++prim_triangle_index;
+ }
+ else {
+ pack.prim_tri_index[i] = -1;
+ }
+ pack.prim_visibility[i] = ob->visibility_for_tracing();
+ }
+ else {
+ pack.prim_tri_index[i] = -1;
+ pack.prim_visibility[i] = 0;
+ }
+ }
+}
+
+/* Pack Instances */
+
+void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
+{
+ /* Adjust primitive index to point to the triangle in the global array, for
+ * geometry with transform applied and already in the top level BVH.
+ */
+ for (size_t i = 0; i < pack.prim_index.size(); i++) {
+ if (pack.prim_index[i] != -1) {
+ pack.prim_index[i] += objects[pack.prim_object[i]]->get_geometry()->prim_offset;
+ }
+ }
+
+ /* track offsets of instanced BVH data in global array */
+ size_t prim_offset = pack.prim_index.size();
+ size_t nodes_offset = nodes_size;
+ size_t nodes_leaf_offset = leaf_nodes_size;
+
+ /* clear array that gives the node indexes for instanced objects */
+ pack.object_node.clear();
+
+ /* reserve */
+ size_t prim_index_size = pack.prim_index.size();
+ size_t prim_tri_verts_size = pack.prim_tri_verts.size();
+
+ size_t pack_prim_index_offset = prim_index_size;
+ size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
+ size_t pack_nodes_offset = nodes_size;
+ size_t pack_leaf_nodes_offset = leaf_nodes_size;
+ size_t object_offset = 0;
+
+ foreach (Geometry *geom, geometry) {
+ BVH2 *bvh = static_cast<BVH2 *>(geom->bvh);
+
+ if (geom->need_build_bvh(params.bvh_layout)) {
+ prim_index_size += bvh->pack.prim_index.size();
+ prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
+ nodes_size += bvh->pack.nodes.size();
+ leaf_nodes_size += bvh->pack.leaf_nodes.size();
+ }
+ }
+
+ pack.prim_index.resize(prim_index_size);
+ pack.prim_type.resize(prim_index_size);
+ pack.prim_object.resize(prim_index_size);
+ pack.prim_visibility.resize(prim_index_size);
+ pack.prim_tri_verts.resize(prim_tri_verts_size);
+ pack.prim_tri_index.resize(prim_index_size);
+ pack.nodes.resize(nodes_size);
+ pack.leaf_nodes.resize(leaf_nodes_size);
+ pack.object_node.resize(objects.size());
+
+ if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) {
+ pack.prim_time.resize(prim_index_size);
+ }
+
+ int *pack_prim_index = (pack.prim_index.size()) ? &pack.prim_index[0] : NULL;
+ int *pack_prim_type = (pack.prim_type.size()) ? &pack.prim_type[0] : NULL;
+ int *pack_prim_object = (pack.prim_object.size()) ? &pack.prim_object[0] : NULL;
+ uint *pack_prim_visibility = (pack.prim_visibility.size()) ? &pack.prim_visibility[0] : NULL;
+ float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size()) ? &pack.prim_tri_verts[0] : NULL;
+ uint *pack_prim_tri_index = (pack.prim_tri_index.size()) ? &pack.prim_tri_index[0] : NULL;
+ int4 *pack_nodes = (pack.nodes.size()) ? &pack.nodes[0] : NULL;
+ int4 *pack_leaf_nodes = (pack.leaf_nodes.size()) ? &pack.leaf_nodes[0] : NULL;
+ float2 *pack_prim_time = (pack.prim_time.size()) ? &pack.prim_time[0] : NULL;
+
+ unordered_map<Geometry *, int> geometry_map;
+
+ /* merge */
+ foreach (Object *ob, objects) {
+ Geometry *geom = ob->get_geometry();
+
+ /* We assume that if mesh doesn't need own BVH it was already included
+ * into a top-level BVH and no packing here is needed.
+ */
+ if (!geom->need_build_bvh(params.bvh_layout)) {
+ pack.object_node[object_offset++] = 0;
+ continue;
+ }
+
+ /* if mesh already added once, don't add it again, but used set
+ * node offset for this object */
+ unordered_map<Geometry *, int>::iterator it = geometry_map.find(geom);
+
+ if (geometry_map.find(geom) != geometry_map.end()) {
+ int noffset = it->second;
+ pack.object_node[object_offset++] = noffset;
+ continue;
+ }
+
+ BVH2 *bvh = static_cast<BVH2 *>(geom->bvh);
+
+ int noffset = nodes_offset;
+ int noffset_leaf = nodes_leaf_offset;
+ int geom_prim_offset = geom->prim_offset;
+
+ /* fill in node indexes for instances */
+ if (bvh->pack.root_index == -1)
+ pack.object_node[object_offset++] = -noffset_leaf - 1;
+ else
+ pack.object_node[object_offset++] = noffset;
+
+ geometry_map[geom] = pack.object_node[object_offset - 1];
+
+ /* merge primitive, object and triangle indexes */
+ if (bvh->pack.prim_index.size()) {
+ size_t bvh_prim_index_size = bvh->pack.prim_index.size();
+ int *bvh_prim_index = &bvh->pack.prim_index[0];
+ int *bvh_prim_type = &bvh->pack.prim_type[0];
+ uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
+ uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
+ float2 *bvh_prim_time = bvh->pack.prim_time.size() ? &bvh->pack.prim_time[0] : NULL;
+
+ for (size_t i = 0; i < bvh_prim_index_size; i++) {
+ if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
+ pack_prim_tri_index[pack_prim_index_offset] = -1;
+ }
+ else {
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
+ pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] +
+ pack_prim_tri_verts_offset;
+ }
+
+ pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
+ pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
+ pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
+ if (bvh_prim_time != NULL) {
+ pack_prim_time[pack_prim_index_offset] = bvh_prim_time[i];
+ }
+ pack_prim_index_offset++;
+ }
+ }
+
+ /* Merge triangle vertices data. */
+ if (bvh->pack.prim_tri_verts.size()) {
+ const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
+ memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
+ &bvh->pack.prim_tri_verts[0],
+ prim_tri_size * sizeof(float4));
+ pack_prim_tri_verts_offset += prim_tri_size;
+ }
+
+ /* merge nodes */
+ if (bvh->pack.leaf_nodes.size()) {
+ int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0];
+ size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size();
+ for (size_t i = 0, j = 0; i < leaf_nodes_offset_size; i += BVH_NODE_LEAF_SIZE, j++) {
+ int4 data = leaf_nodes_offset[i];
+ data.x += prim_offset;
+ data.y += prim_offset;
+ pack_leaf_nodes[pack_leaf_nodes_offset] = data;
+ for (int j = 1; j < BVH_NODE_LEAF_SIZE; ++j) {
+ pack_leaf_nodes[pack_leaf_nodes_offset + j] = leaf_nodes_offset[i + j];
+ }
+ pack_leaf_nodes_offset += BVH_NODE_LEAF_SIZE;
+ }
+ }
+
+ if (bvh->pack.nodes.size()) {
+ int4 *bvh_nodes = &bvh->pack.nodes[0];
+ size_t bvh_nodes_size = bvh->pack.nodes.size();
+
+ for (size_t i = 0, j = 0; i < bvh_nodes_size; j++) {
+ size_t nsize, nsize_bbox;
+ if (bvh_nodes[i].x & PATH_RAY_NODE_UNALIGNED) {
+ nsize = BVH_UNALIGNED_NODE_SIZE;
+ nsize_bbox = 0;
+ }
+ else {
+ nsize = BVH_NODE_SIZE;
+ nsize_bbox = 0;
+ }
+
+ memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox * sizeof(int4));
+
+ /* Modify offsets into arrays */
+ int4 data = bvh_nodes[i + nsize_bbox];
+ data.z += (data.z < 0) ? -noffset_leaf : noffset;
+ data.w += (data.w < 0) ? -noffset_leaf : noffset;
+ pack_nodes[pack_nodes_offset + nsize_bbox] = data;
+
+ /* Usually this copies nothing, but we better
+ * be prepared for possible node size extension.
+ */
+ memcpy(&pack_nodes[pack_nodes_offset + nsize_bbox + 1],
+ &bvh_nodes[i + nsize_bbox + 1],
+ sizeof(int4) * (nsize - (nsize_bbox + 1)));
+
+ pack_nodes_offset += nsize;
+ i += nsize;
+ }
+ }
+
+ nodes_offset += bvh->pack.nodes.size();
+ nodes_leaf_offset += bvh->pack.leaf_nodes.size();
+ prim_offset += bvh->pack.prim_index.size();
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh2.h b/intern/cycles/bvh/bvh2.h
index fa3e45b72d2..1030a0f76c7 100644
--- a/intern/cycles/bvh/bvh2.h
+++ b/intern/cycles/bvh/bvh2.h
@@ -26,23 +26,30 @@
CCL_NAMESPACE_BEGIN
-class BVHNode;
-struct BVHStackEntry;
-class BVHParams;
-class BoundBox;
-class LeafNode;
-class Object;
-class Progress;
-
#define BVH_NODE_SIZE 4
#define BVH_NODE_LEAF_SIZE 1
#define BVH_UNALIGNED_NODE_SIZE 7
+/* Pack Utility */
+struct BVHStackEntry {
+ const BVHNode *node;
+ int idx;
+
+ BVHStackEntry(const BVHNode *n = 0, int i = 0);
+ int encodeIdx() const;
+};
+
/* BVH2
*
* Typical BVH with each node having two children.
*/
class BVH2 : public BVH {
+ public:
+ void build(Progress &progress, Stats *stats);
+ void refit(Progress &progress);
+
+ PackedBVH pack;
+
protected:
/* constructor */
friend class BVH;
@@ -51,10 +58,10 @@ class BVH2 : public BVH {
const vector<Object *> &objects);
/* Building process. */
- virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
+ virtual BVHNode *widen_children_nodes(const BVHNode *root);
/* pack */
- void pack_nodes(const BVHNode *root) override;
+ void pack_nodes(const BVHNode *root);
void pack_leaf(const BVHStackEntry &e, const LeafNode *leaf);
void pack_inner(const BVHStackEntry &e, const BVHStackEntry &e0, const BVHStackEntry &e1);
@@ -84,8 +91,18 @@ class BVH2 : public BVH {
uint visibility1);
/* refit */
- void refit_nodes() override;
+ void refit_nodes();
void refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility);
+
+ /* Refit range of primitives. */
+ void refit_primitives(int start, int end, BoundBox &bbox, uint &visibility);
+
+ /* triangles and strands */
+ void pack_primitives();
+ void pack_triangle(int idx, float4 storage[3]);
+
+ /* merge instance BVH's */
+ void pack_instances(size_t nodes_size, size_t leaf_nodes_size);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp
index 910e3780b2e..b874bda7186 100644
--- a/intern/cycles/bvh/bvh_embree.cpp
+++ b/intern/cycles/bvh/bvh_embree.cpp
@@ -298,82 +298,31 @@ static bool rtc_progress_func(void *user_ptr, const double n)
return !progress->get_cancel();
}
-static size_t count_primitives(Geometry *geom)
-{
- if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *mesh = static_cast<Mesh *>(geom);
- return mesh->num_triangles();
- }
- else if (geom->geometry_type == Geometry::HAIR) {
- Hair *hair = static_cast<Hair *>(geom);
- return hair->num_segments();
- }
-
- return 0;
-}
-
BVHEmbree::BVHEmbree(const BVHParams &params_,
const vector<Geometry *> &geometry_,
- const vector<Object *> &objects_,
- const Device *device)
+ const vector<Object *> &objects_)
: BVH(params_, geometry_, objects_),
scene(NULL),
- mem_used(0),
- top_level(NULL),
- rtc_device((RTCDevice)device->bvh_device()),
- stats(NULL),
- curve_subdivisions(params.curve_subdivisions),
- build_quality(RTC_BUILD_QUALITY_REFIT),
- dynamic_scene(true)
+ rtc_device(NULL),
+ build_quality(RTC_BUILD_QUALITY_REFIT)
{
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
-
- rtcSetDeviceErrorFunction(rtc_device, rtc_error_func, NULL);
-
- pack.root_index = -1;
}
BVHEmbree::~BVHEmbree()
{
- if (!params.top_level) {
- destroy(scene);
- }
-}
-
-void BVHEmbree::destroy(RTCScene scene)
-{
if (scene) {
rtcReleaseScene(scene);
- scene = NULL;
- }
-}
-
-void BVHEmbree::delete_rtcScene()
-{
- if (scene) {
- /* When this BVH is used as an instance in a top level BVH, don't delete now
- * Let the top_level BVH know that it should delete it later. */
- if (top_level) {
- top_level->add_delayed_delete_scene(scene);
- }
- else {
- rtcReleaseScene(scene);
- if (delayed_delete_scenes.size()) {
- foreach (RTCScene s, delayed_delete_scenes) {
- rtcReleaseScene(s);
- }
- }
- delayed_delete_scenes.clear();
- }
- scene = NULL;
}
}
-void BVHEmbree::build(Progress &progress, Stats *stats_)
+void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
{
+ rtc_device = rtc_device_;
assert(rtc_device);
- stats = stats_;
+
+ rtcSetDeviceErrorFunction(rtc_device, rtc_error_func, NULL);
rtcSetDeviceMemoryMonitorFunction(rtc_device, rtc_memory_monitor_func, stats);
progress.set_substatus("Building BVH");
@@ -394,35 +343,7 @@ void BVHEmbree::build(Progress &progress, Stats *stats_)
RTC_BUILD_QUALITY_MEDIUM);
rtcSetSceneBuildQuality(scene, build_quality);
- /* Count triangles and curves first, reserve arrays once. */
- size_t prim_count = 0;
-
- foreach (Object *ob, objects) {
- if (params.top_level) {
- if (!ob->is_traceable()) {
- continue;
- }
- if (!ob->get_geometry()->is_instanced()) {
- prim_count += count_primitives(ob->get_geometry());
- }
- else {
- ++prim_count;
- }
- }
- else {
- prim_count += count_primitives(ob->get_geometry());
- }
- }
-
- pack.prim_object.reserve(prim_count);
- pack.prim_type.reserve(prim_count);
- pack.prim_index.reserve(prim_count);
- pack.prim_tri_index.reserve(prim_count);
-
int i = 0;
-
- pack.object_node.clear();
-
foreach (Object *ob, objects) {
if (params.top_level) {
if (!ob->is_traceable()) {
@@ -445,37 +366,11 @@ void BVHEmbree::build(Progress &progress, Stats *stats_)
}
if (progress.get_cancel()) {
- delete_rtcScene();
- stats = NULL;
return;
}
rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
rtcCommitScene(scene);
-
- pack_primitives();
-
- if (progress.get_cancel()) {
- delete_rtcScene();
- stats = NULL;
- return;
- }
-
- progress.set_substatus("Packing geometry");
- pack_nodes(NULL);
-
- stats = NULL;
-}
-
-void BVHEmbree::copy_to_device(Progress & /*progress*/, DeviceScene *dscene)
-{
- dscene->data.bvh.scene = scene;
-}
-
-BVHNode *BVHEmbree::widen_children_nodes(const BVHNode * /*root*/)
-{
- assert(!"Must not be called.");
- return NULL;
}
void BVHEmbree::add_object(Object *ob, int i)
@@ -498,15 +393,8 @@ void BVHEmbree::add_object(Object *ob, int i)
void BVHEmbree::add_instance(Object *ob, int i)
{
- if (!ob || !ob->get_geometry()) {
- assert(0);
- return;
- }
BVHEmbree *instance_bvh = (BVHEmbree *)(ob->get_geometry()->bvh);
-
- if (instance_bvh->top_level != this) {
- instance_bvh->top_level = this;
- }
+ assert(instance_bvh != NULL);
const size_t num_object_motion_steps = ob->use_motion() ? ob->get_motion().size() : 1;
const size_t num_motion_steps = min(num_object_motion_steps, RTC_MAX_TIME_STEP_COUNT);
@@ -538,11 +426,6 @@ void BVHEmbree::add_instance(Object *ob, int i)
geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float *)&ob->get_tfm());
}
- pack.prim_index.push_back_slow(-1);
- pack.prim_object.push_back_slow(i);
- pack.prim_type.push_back_slow(PRIMITIVE_NONE);
- pack.prim_tri_index.push_back_slow(-1);
-
rtcSetGeometryUserData(geom_id, (void *)instance_bvh->scene);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
@@ -553,20 +436,22 @@ void BVHEmbree::add_instance(Object *ob, int i)
void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
{
- size_t prim_offset = pack.prim_index.size();
+ size_t prim_offset = mesh->optix_prim_offset;
+
const Attribute *attr_mP = NULL;
- size_t num_geometry_motion_steps = 1;
+ size_t num_motion_steps = 1;
if (mesh->has_motion_blur()) {
attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr_mP) {
- num_geometry_motion_steps = mesh->get_motion_steps();
+ num_motion_steps = mesh->get_motion_steps();
}
}
- const size_t num_motion_steps = min(num_geometry_motion_steps, RTC_MAX_TIME_STEP_COUNT);
- assert(num_geometry_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
+ assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
+ num_motion_steps = min(num_motion_steps, RTC_MAX_TIME_STEP_COUNT);
const size_t num_triangles = mesh->num_triangles();
+
RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_TRIANGLE);
rtcSetGeometryBuildQuality(geom_id, build_quality);
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
@@ -588,22 +473,6 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
set_tri_vertex_buffer(geom_id, mesh, false);
- size_t prim_object_size = pack.prim_object.size();
- pack.prim_object.resize(prim_object_size + num_triangles);
- size_t prim_type_size = pack.prim_type.size();
- pack.prim_type.resize(prim_type_size + num_triangles);
- size_t prim_index_size = pack.prim_index.size();
- pack.prim_index.resize(prim_index_size + num_triangles);
- pack.prim_tri_index.resize(prim_index_size + num_triangles);
- int prim_type = (num_motion_steps > 1 ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE);
-
- for (size_t j = 0; j < num_triangles; ++j) {
- pack.prim_object[prim_object_size + j] = i;
- pack.prim_type[prim_type_size + j] = prim_type;
- pack.prim_index[prim_index_size + j] = j;
- pack.prim_tri_index[prim_index_size + j] = j;
- }
-
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
@@ -629,12 +498,12 @@ void BVHEmbree::set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, con
}
}
}
- const size_t num_verts = mesh->verts.size();
+ const size_t num_verts = mesh->get_verts().size();
for (int t = 0; t < num_motion_steps; ++t) {
const float3 *verts;
if (t == t_mid) {
- verts = &mesh->verts[0];
+ verts = mesh->get_verts().data();
}
else {
int t_ = (t > t_mid) ? (t - 1) : t;
@@ -736,24 +605,19 @@ void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, c
void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
{
- size_t prim_offset = pack.prim_index.size();
+ size_t prim_offset = hair->optix_prim_offset;
+
const Attribute *attr_mP = NULL;
- size_t num_geometry_motion_steps = 1;
+ size_t num_motion_steps = 1;
if (hair->has_motion_blur()) {
attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr_mP) {
- num_geometry_motion_steps = hair->get_motion_steps();
+ num_motion_steps = hair->get_motion_steps();
}
}
- const size_t num_motion_steps = min(num_geometry_motion_steps, RTC_MAX_TIME_STEP_COUNT);
- const PrimitiveType primitive_type =
- (num_motion_steps > 1) ?
- ((hair->curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
- PRIMITIVE_MOTION_CURVE_THICK) :
- ((hair->curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK);
-
- assert(num_geometry_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
+ assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
+ num_motion_steps = min(num_motion_steps, RTC_MAX_TIME_STEP_COUNT);
const size_t num_curves = hair->num_curves();
size_t num_segments = 0;
@@ -763,22 +627,12 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
num_segments += c.num_segments();
}
- /* Make room for Cycles specific data. */
- size_t prim_object_size = pack.prim_object.size();
- pack.prim_object.resize(prim_object_size + num_segments);
- size_t prim_type_size = pack.prim_type.size();
- pack.prim_type.resize(prim_type_size + num_segments);
- size_t prim_index_size = pack.prim_index.size();
- pack.prim_index.resize(prim_index_size + num_segments);
- size_t prim_tri_index_size = pack.prim_index.size();
- pack.prim_tri_index.resize(prim_tri_index_size + num_segments);
-
enum RTCGeometryType type = (hair->curve_shape == CURVE_RIBBON ?
RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE :
RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE);
RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
- rtcSetGeometryTessellationRate(geom_id, curve_subdivisions + 1);
+ rtcSetGeometryTessellationRate(geom_id, params.curve_subdivisions + 1);
unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof(int), num_segments);
size_t rtc_index = 0;
@@ -788,11 +642,6 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
rtc_indices[rtc_index] = c.first_key + k;
/* Room for extra CVs at Catmull-Rom splines. */
rtc_indices[rtc_index] += j * 2;
- /* Cycles specific data. */
- pack.prim_object[prim_object_size + rtc_index] = i;
- pack.prim_type[prim_type_size + rtc_index] = (PRIMITIVE_PACK_SEGMENT(primitive_type, k));
- pack.prim_index[prim_index_size + rtc_index] = j;
- pack.prim_tri_index[prim_tri_index_size + rtc_index] = rtc_index;
++rtc_index;
}
@@ -818,134 +667,10 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
rtcReleaseGeometry(geom_id);
}
-void BVHEmbree::pack_nodes(const BVHNode *)
+void BVHEmbree::refit(Progress &progress)
{
- /* Quite a bit of this code is for compatibility with Cycles' native BVH. */
- if (!params.top_level) {
- return;
- }
-
- for (size_t i = 0; i < pack.prim_index.size(); ++i) {
- if (pack.prim_index[i] != -1) {
- pack.prim_index[i] += objects[pack.prim_object[i]]->get_geometry()->prim_offset;
- }
- }
-
- size_t prim_offset = pack.prim_index.size();
-
- /* reserve */
- size_t prim_index_size = pack.prim_index.size();
- size_t prim_tri_verts_size = pack.prim_tri_verts.size();
-
- size_t pack_prim_index_offset = prim_index_size;
- size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
- size_t object_offset = 0;
-
- map<Geometry *, int> geometry_map;
-
- foreach (Object *ob, objects) {
- Geometry *geom = ob->get_geometry();
- BVH *bvh = geom->bvh;
-
- if (geom->need_build_bvh(BVH_LAYOUT_EMBREE)) {
- if (geometry_map.find(geom) == geometry_map.end()) {
- prim_index_size += bvh->pack.prim_index.size();
- prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
- geometry_map[geom] = 1;
- }
- }
- }
+ progress.set_substatus("Refitting BVH nodes");
- geometry_map.clear();
-
- pack.prim_index.resize(prim_index_size);
- pack.prim_type.resize(prim_index_size);
- pack.prim_object.resize(prim_index_size);
- pack.prim_visibility.clear();
- pack.prim_tri_verts.resize(prim_tri_verts_size);
- pack.prim_tri_index.resize(prim_index_size);
- pack.object_node.resize(objects.size());
-
- int *pack_prim_index = (pack.prim_index.size()) ? &pack.prim_index[0] : NULL;
- int *pack_prim_type = (pack.prim_type.size()) ? &pack.prim_type[0] : NULL;
- int *pack_prim_object = (pack.prim_object.size()) ? &pack.prim_object[0] : NULL;
- float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size()) ? &pack.prim_tri_verts[0] : NULL;
- uint *pack_prim_tri_index = (pack.prim_tri_index.size()) ? &pack.prim_tri_index[0] : NULL;
-
- /* merge */
- foreach (Object *ob, objects) {
- Geometry *geom = ob->get_geometry();
-
- /* We assume that if mesh doesn't need own BVH it was already included
- * into a top-level BVH and no packing here is needed.
- */
- if (!geom->need_build_bvh(BVH_LAYOUT_EMBREE)) {
- pack.object_node[object_offset++] = prim_offset;
- continue;
- }
-
- /* if geom already added once, don't add it again, but used set
- * node offset for this object */
- map<Geometry *, int>::iterator it = geometry_map.find(geom);
-
- if (geometry_map.find(geom) != geometry_map.end()) {
- int noffset = it->second;
- pack.object_node[object_offset++] = noffset;
- continue;
- }
-
- BVHEmbree *bvh = (BVHEmbree *)geom->bvh;
-
- rtc_memory_monitor_func(stats, unaccounted_mem, true);
- unaccounted_mem = 0;
-
- int geom_prim_offset = geom->prim_offset;
-
- /* fill in node indexes for instances */
- pack.object_node[object_offset++] = prim_offset;
-
- geometry_map[geom] = pack.object_node[object_offset - 1];
-
- /* merge primitive, object and triangle indexes */
- if (bvh->pack.prim_index.size()) {
- size_t bvh_prim_index_size = bvh->pack.prim_index.size();
- int *bvh_prim_index = &bvh->pack.prim_index[0];
- int *bvh_prim_type = &bvh->pack.prim_type[0];
- uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
-
- for (size_t i = 0; i < bvh_prim_index_size; ++i) {
- if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
- pack_prim_tri_index[pack_prim_index_offset] = -1;
- }
- else {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
- pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] +
- pack_prim_tri_verts_offset;
- }
-
- pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
- pack_prim_object[pack_prim_index_offset] = 0;
-
- ++pack_prim_index_offset;
- }
- }
-
- /* Merge triangle vertices data. */
- if (bvh->pack.prim_tri_verts.size()) {
- const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
- memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
- &bvh->pack.prim_tri_verts[0],
- prim_tri_size * sizeof(float4));
- pack_prim_tri_verts_offset += prim_tri_size;
- }
-
- prim_offset += bvh->pack.prim_index.size();
- }
-}
-
-void BVHEmbree::refit_nodes()
-{
/* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */
unsigned geom_id = 0;
foreach (Object *ob, objects) {
@@ -971,8 +696,10 @@ void BVHEmbree::refit_nodes()
}
geom_id += 2;
}
+
rtcCommitScene(scene);
}
+
CCL_NAMESPACE_END
#endif /* WITH_EMBREE */
diff --git a/intern/cycles/bvh/bvh_embree.h b/intern/cycles/bvh/bvh_embree.h
index 3e895e7b588..01636fbd1dc 100644
--- a/intern/cycles/bvh/bvh_embree.h
+++ b/intern/cycles/bvh/bvh_embree.h
@@ -31,56 +31,34 @@
CCL_NAMESPACE_BEGIN
-class Geometry;
class Hair;
class Mesh;
class BVHEmbree : public BVH {
public:
- virtual void build(Progress &progress, Stats *stats) override;
- virtual void copy_to_device(Progress &progress, DeviceScene *dscene) override;
- virtual ~BVHEmbree();
- RTCScene scene;
- static void destroy(RTCScene);
+ void build(Progress &progress, Stats *stats, RTCDevice rtc_device);
+ void refit(Progress &progress);
- /* Building process. */
- virtual BVHNode *widen_children_nodes(const BVHNode *root) override;
+ RTCScene scene;
protected:
friend class BVH;
BVHEmbree(const BVHParams &params,
const vector<Geometry *> &geometry,
- const vector<Object *> &objects,
- const Device *device);
-
- virtual void pack_nodes(const BVHNode *) override;
- virtual void refit_nodes() override;
+ const vector<Object *> &objects);
+ virtual ~BVHEmbree();
void add_object(Object *ob, int i);
void add_instance(Object *ob, int i);
void add_curves(const Object *ob, const Hair *hair, int i);
void add_triangles(const Object *ob, const Mesh *mesh, int i);
- ssize_t mem_used;
-
- void add_delayed_delete_scene(RTCScene scene)
- {
- delayed_delete_scenes.push_back(scene);
- }
- BVHEmbree *top_level;
-
private:
- void delete_rtcScene();
void set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, const bool update);
void set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, const bool update);
RTCDevice rtc_device;
-
- Stats *stats;
- vector<RTCScene> delayed_delete_scenes;
- int curve_subdivisions;
enum RTCBuildQuality build_quality;
- bool dynamic_scene;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_multi.cpp b/intern/cycles/bvh/bvh_multi.cpp
new file mode 100644
index 00000000000..a9e771f20f1
--- /dev/null
+++ b/intern/cycles/bvh/bvh_multi.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#include "bvh/bvh_multi.h"
+
+#include "util/util_foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+BVHMulti::BVHMulti(const BVHParams &params_,
+ const vector<Geometry *> &geometry_,
+ const vector<Object *> &objects_)
+ : BVH(params_, geometry_, objects_)
+{
+}
+
+BVHMulti::~BVHMulti()
+{
+ foreach (BVH *bvh, sub_bvhs) {
+ delete bvh;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_multi.h b/intern/cycles/bvh/bvh_multi.h
new file mode 100644
index 00000000000..840438c5d0c
--- /dev/null
+++ b/intern/cycles/bvh/bvh_multi.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020, 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_MULTI_H__
+#define __BVH_MULTI_H__
+
+#include "bvh/bvh.h"
+#include "bvh/bvh_params.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVHMulti : public BVH {
+ public:
+ vector<BVH *> sub_bvhs;
+
+ protected:
+ friend class BVH;
+ BVHMulti(const BVHParams &params,
+ const vector<Geometry *> &geometry,
+ const vector<Object *> &objects);
+ virtual ~BVHMulti();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_MULTI_H__ */
diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp
index 52fc9c0a50d..e094f339ede 100644
--- a/intern/cycles/bvh/bvh_optix.cpp
+++ b/intern/cycles/bvh/bvh_optix.cpp
@@ -19,212 +19,22 @@
# include "bvh/bvh_optix.h"
-# include "device/device.h"
-
-# include "render/geometry.h"
-# include "render/hair.h"
-# include "render/mesh.h"
-# include "render/object.h"
-
-# include "util/util_foreach.h"
-# include "util/util_logging.h"
-# include "util/util_progress.h"
-
CCL_NAMESPACE_BEGIN
BVHOptiX::BVHOptiX(const BVHParams &params_,
const vector<Geometry *> &geometry_,
- const vector<Object *> &objects_)
- : BVH(params_, geometry_, objects_)
+ const vector<Object *> &objects_,
+ Device *device)
+ : BVH(params_, geometry_, objects_),
+ traversable_handle(0),
+ as_data(device, params_.top_level ? "optix tlas" : "optix blas"),
+ motion_transform_data(device, "optix motion transform")
{
- optix_handle = 0;
- optix_data_handle = 0;
- do_refit = false;
}
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))
- 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(geometry.size() == 1 && objects.size() == 1); // These are built per-mesh
- Geometry *const geom = geometry[0];
-
- if (geom->geometry_type == Geometry::HAIR) {
- Hair *const hair = static_cast<Hair *const>(geom);
- if (hair->num_curves() > 0) {
- const size_t num_curves = hair->num_curves();
- const size_t num_segments = hair->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 = (hair->get_use_motion_blur() &&
- hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) ?
- ((hair->curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
- PRIMITIVE_MOTION_CURVE_THICK) :
- ((hair->curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON :
- PRIMITIVE_CURVE_THICK);
-
- for (size_t j = 0; j < num_curves; ++j) {
- const Hair::Curve curve = hair->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);
- }
- }
- }
- }
- else if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
- Mesh *const mesh = static_cast<Mesh *const>(geom);
- if (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->get_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]->get_visibility();
- objects[0]->set_visibility(0);
-
- // Update 'pack.prim_tri_index', 'pack.prim_tri_verts' and 'pack.prim_visibility'
- pack_primitives();
-
- // Reset visibility after packing
- objects[0]->set_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 (Geometry *geom, geometry) {
- BVH *const bvh = geom->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 'Geometry::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 (Geometry *geom, geometry) {
- PackedBVH &bvh_pack = geom->bvh->pack;
- int geom_prim_offset = geom->prim_offset;
-
- // Merge visibility flags of all objects and fix object indices for non-instanced geometry
- int object_index = 0; // Unused for instanced geometry
- int object_visibility = 0;
- foreach (Object *ob, objects) {
- if (ob->get_geometry() == geom) {
- object_visibility |= ob->visibility_for_tracing();
- if (!geom->is_instanced()) {
- object_index = ob->get_device_index();
- break;
- }
- }
- }
-
- // 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] + geom_prim_offset;
- pack_prim_tri_index[pack_offset] = -1;
- }
- else {
- pack_prim_index[pack_offset] = bvh_prim_index[i] + geom_prim_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] = object_index;
- pack_prim_visibility[pack_offset] = bvh_prim_visibility[i] | object_visibility;
- }
- }
-
- // 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;
- }
- }
-}
-
-void BVHOptiX::pack_nodes(const BVHNode *)
-{
-}
-
-void BVHOptiX::refit_nodes()
-{
- do_refit = true;
-}
-
-BVHNode *BVHOptiX::widen_children_nodes(const BVHNode *)
-{
- return NULL;
+ // Acceleration structure memory is freed via the 'as_data' destructor
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_optix.h b/intern/cycles/bvh/bvh_optix.h
index 663cba67260..aa514beae0d 100644
--- a/intern/cycles/bvh/bvh_optix.h
+++ b/intern/cycles/bvh/bvh_optix.h
@@ -26,33 +26,19 @@
CCL_NAMESPACE_BEGIN
-class Geometry;
-class Optix;
-
class BVHOptiX : public BVH {
- friend class BVH;
-
public:
- uint64_t optix_handle;
- uint64_t optix_data_handle;
- bool do_refit;
+ uint64_t traversable_handle;
+ device_only_memory<char> as_data;
+ device_only_memory<char> motion_transform_data;
+ protected:
+ friend class BVH;
BVHOptiX(const BVHParams &params,
const vector<Geometry *> &geometry,
- const vector<Object *> &objects);
+ const vector<Object *> &objects,
+ Device *device);
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
diff --git a/intern/cycles/device/cuda/device_cuda.h b/intern/cycles/device/cuda/device_cuda.h
index e5e3e24165d..c3271c3cfcf 100644
--- a/intern/cycles/device/cuda/device_cuda.h
+++ b/intern/cycles/device/cuda/device_cuda.h
@@ -71,6 +71,7 @@ class CUDADevice : public Device {
};
typedef map<device_memory *, CUDAMem> CUDAMemMap;
CUDAMemMap cuda_mem_map;
+ thread_mutex cuda_mem_map_mutex;
struct PixelMem {
GLuint cuPBO;
diff --git a/intern/cycles/device/cuda/device_cuda_impl.cpp b/intern/cycles/device/cuda/device_cuda_impl.cpp
index 01adf10f252..48151365e5d 100644
--- a/intern/cycles/device/cuda/device_cuda_impl.cpp
+++ b/intern/cycles/device/cuda/device_cuda_impl.cpp
@@ -718,8 +718,10 @@ void CUDADevice::init_host_memory()
void CUDADevice::load_texture_info()
{
if (need_texture_info) {
- texture_info.copy_to_device();
+ /* Unset flag before copying, so this does not loop indefinitely if the copy below calls
+ * into 'move_textures_to_host' (which calls 'load_texture_info' again). */
need_texture_info = false;
+ texture_info.copy_to_device();
}
}
@@ -988,6 +990,7 @@ void CUDADevice::mem_alloc(device_memory &mem)
assert(!"mem_alloc not supported for global memory.");
}
else {
+ thread_scoped_lock lock(cuda_mem_map_mutex);
generic_alloc(mem);
}
}
@@ -1006,10 +1009,10 @@ void CUDADevice::mem_copy_to(device_memory &mem)
tex_alloc((device_texture &)mem);
}
else {
+ thread_scoped_lock lock(cuda_mem_map_mutex);
if (!mem.device_pointer) {
generic_alloc(mem);
}
-
generic_copy_to(mem);
}
}
@@ -1048,6 +1051,7 @@ void CUDADevice::mem_zero(device_memory &mem)
/* If use_mapped_host of mem is false, mem.device_pointer currently refers to device memory
* regardless of mem.host_pointer and mem.shared_pointer. */
+ thread_scoped_lock lock(cuda_mem_map_mutex);
if (!cuda_mem_map[&mem].use_mapped_host || mem.host_pointer != mem.shared_pointer) {
const CUDAContextScope scope(this);
cuda_assert(cuMemsetD8((CUdeviceptr)mem.device_pointer, 0, mem.memory_size()));
@@ -1069,6 +1073,7 @@ void CUDADevice::mem_free(device_memory &mem)
tex_free((device_texture &)mem);
}
else {
+ thread_scoped_lock lock(cuda_mem_map_mutex);
generic_free(mem);
}
}
@@ -1092,6 +1097,7 @@ void CUDADevice::const_copy_to(const char *name, void *host, size_t size)
void CUDADevice::global_alloc(device_memory &mem)
{
if (mem.is_resident(this)) {
+ thread_scoped_lock lock(cuda_mem_map_mutex);
generic_alloc(mem);
generic_copy_to(mem);
}
@@ -1102,6 +1108,7 @@ void CUDADevice::global_alloc(device_memory &mem)
void CUDADevice::global_free(device_memory &mem)
{
if (mem.is_resident(this) && mem.device_pointer) {
+ thread_scoped_lock lock(cuda_mem_map_mutex);
generic_free(mem);
}
}
@@ -1170,6 +1177,8 @@ void CUDADevice::tex_alloc(device_texture &mem)
size_t src_pitch = mem.data_width * dsize * mem.data_elements;
size_t dst_pitch = src_pitch;
+ thread_scoped_lock lock(cuda_mem_map_mutex);
+
if (!mem.is_resident(this)) {
cmem = &cuda_mem_map[&mem];
cmem->texobject = 0;
@@ -1257,6 +1266,9 @@ void CUDADevice::tex_alloc(device_texture &mem)
cuda_assert(cuMemcpyHtoD(mem.device_pointer, mem.host_pointer, size));
}
+ /* Unlock mutex before resizing texture info, since that may attempt to lock it again. */
+ lock.unlock();
+
/* Resize once */
const uint slot = mem.slot;
if (slot >= texture_info.size()) {
@@ -1305,6 +1317,11 @@ void CUDADevice::tex_alloc(device_texture &mem)
texDesc.filterMode = filter_mode;
texDesc.flags = CU_TRSF_NORMALIZED_COORDINATES;
+ /* Lock again and refresh the data pointer (in case another thread modified the map in the
+ * meantime). */
+ lock.lock();
+ cmem = &cuda_mem_map[&mem];
+
cuda_assert(cuTexObjectCreate(&cmem->texobject, &resDesc, &texDesc, NULL));
texture_info[slot].data = (uint64_t)cmem->texobject;
@@ -1318,6 +1335,7 @@ void CUDADevice::tex_free(device_texture &mem)
{
if (mem.device_pointer) {
CUDAContextScope scope(this);
+ thread_scoped_lock lock(cuda_mem_map_mutex);
const CUDAMem &cmem = cuda_mem_map[&mem];
if (cmem.texobject) {
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index eb8fb8040e3..1efd628b79b 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -17,6 +17,8 @@
#include <stdlib.h>
#include <string.h>
+#include "bvh/bvh2.h"
+
#include "device/device.h"
#include "device/device_intern.h"
@@ -364,6 +366,19 @@ void Device::draw_pixels(device_memory &rgba,
}
}
+void Device::build_bvh(BVH *bvh, Progress &progress, bool refit)
+{
+ assert(bvh->params.bvh_layout == BVH_LAYOUT_BVH2);
+
+ BVH2 *const bvh2 = static_cast<BVH2 *>(bvh);
+ if (refit) {
+ bvh2->refit(progress);
+ }
+ else {
+ bvh2->build(progress, &stats);
+ }
+}
+
Device *Device::create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background)
{
#ifdef WITH_MULTI
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 2006db02ce7..e9b7cde7a16 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -373,12 +373,6 @@ class Device {
return NULL;
}
- /* Device specific pointer for BVH creation. Currently only used by Embree. */
- virtual void *bvh_device() const
- {
- return NULL;
- }
-
/* load/compile kernels, must be called before adding tasks */
virtual bool load_kernels(const DeviceRequestedFeatures & /*requested_features*/)
{
@@ -427,10 +421,7 @@ class Device {
const DeviceDrawParams &draw_params);
/* acceleration structure building */
- virtual bool build_optix_bvh(BVH *)
- {
- return false;
- }
+ virtual void build_bvh(BVH *bvh, Progress &progress, bool refit);
#ifdef WITH_NETWORK
/* networking */
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index 6912ac1e638..fea4fc53d1f 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -47,6 +47,8 @@
#include "kernel/osl/osl_globals.h"
// clang-format on
+#include "bvh/bvh_embree.h"
+
#include "render/buffers.h"
#include "render/coverage.h"
@@ -188,6 +190,7 @@ class CPUDevice : public Device {
#endif
thread_spin_lock oidn_task_lock;
#ifdef WITH_EMBREE
+ RTCScene embree_scene = NULL;
RTCDevice embree_device;
#endif
@@ -472,6 +475,15 @@ class CPUDevice : public Device {
virtual void const_copy_to(const char *name, void *host, size_t size) override
{
+#if 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->bvh.scene = embree_scene;
+ }
+#endif
kernel_const_copy(&kernel_globals, name, host, size);
}
@@ -537,13 +549,26 @@ class CPUDevice : public Device {
#endif
}
- void *bvh_device() const override
+ void build_bvh(BVH *bvh, Progress &progress, bool refit) override
{
#ifdef WITH_EMBREE
- return embree_device;
-#else
- return NULL;
+ if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE ||
+ bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_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 thread_run(DeviceTask &task)
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index 2e72a0b4393..e5b138917ff 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -17,11 +17,14 @@
#include <sstream>
#include <stdlib.h>
+#include "bvh/bvh_multi.h"
+
#include "device/device.h"
#include "device/device_intern.h"
#include "device/device_network.h"
#include "render/buffers.h"
+#include "render/geometry.h"
#include "util/util_foreach.h"
#include "util/util_list.h"
@@ -141,7 +144,7 @@ class MultiDevice : public Device {
delete sub.device;
}
- const string &error_message()
+ const string &error_message() override
{
error_msg.clear();
@@ -153,7 +156,7 @@ class MultiDevice : public Device {
return error_msg;
}
- virtual bool show_samples() const
+ virtual bool show_samples() const override
{
if (devices.size() > 1) {
return false;
@@ -161,16 +164,31 @@ class MultiDevice : public Device {
return devices.front().device->show_samples();
}
- virtual BVHLayoutMask get_bvh_layout_mask() const
+ virtual BVHLayoutMask get_bvh_layout_mask() const override
{
BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_ALL;
+ BVHLayoutMask bvh_layout_mask_all = BVH_LAYOUT_NONE;
foreach (const SubDevice &sub_device, devices) {
- bvh_layout_mask &= sub_device.device->get_bvh_layout_mask();
+ BVHLayoutMask device_bvh_layout_mask = sub_device.device->get_bvh_layout_mask();
+ bvh_layout_mask &= device_bvh_layout_mask;
+ bvh_layout_mask_all |= device_bvh_layout_mask;
+ }
+
+ /* With multiple OptiX devices, every device needs its own acceleration structure */
+ if (bvh_layout_mask == BVH_LAYOUT_OPTIX) {
+ return BVH_LAYOUT_MULTI_OPTIX;
}
+
+ /* When devices do not share a common BVH layout, fall back to creating one for each */
+ const BVHLayoutMask BVH_LAYOUT_OPTIX_EMBREE = (BVH_LAYOUT_OPTIX | BVH_LAYOUT_EMBREE);
+ if ((bvh_layout_mask_all & BVH_LAYOUT_OPTIX_EMBREE) == BVH_LAYOUT_OPTIX_EMBREE) {
+ return BVH_LAYOUT_MULTI_OPTIX_EMBREE;
+ }
+
return bvh_layout_mask;
}
- bool load_kernels(const DeviceRequestedFeatures &requested_features)
+ bool load_kernels(const DeviceRequestedFeatures &requested_features) override
{
foreach (SubDevice &sub, devices)
if (!sub.device->load_kernels(requested_features))
@@ -188,7 +206,7 @@ class MultiDevice : public Device {
return true;
}
- bool wait_for_availability(const DeviceRequestedFeatures &requested_features)
+ bool wait_for_availability(const DeviceRequestedFeatures &requested_features) override
{
foreach (SubDevice &sub, devices)
if (!sub.device->wait_for_availability(requested_features))
@@ -203,7 +221,7 @@ class MultiDevice : public Device {
return true;
}
- DeviceKernelStatus get_active_kernel_switch_state()
+ DeviceKernelStatus get_active_kernel_switch_state() override
{
DeviceKernelStatus result = DEVICE_KERNEL_USING_FEATURE_KERNEL;
@@ -227,24 +245,61 @@ class MultiDevice : public Device {
return result;
}
- bool build_optix_bvh(BVH *bvh)
+ void build_bvh(BVH *bvh, Progress &progress, bool refit) override
{
+ /* Try to build and share a single acceleration structure, if possible */
+ if (bvh->params.bvh_layout == BVH_LAYOUT_BVH2) {
+ devices.back().device->build_bvh(bvh, progress, refit);
+ return;
+ }
+
+ BVHMulti *const bvh_multi = static_cast<BVHMulti *>(bvh);
+ bvh_multi->sub_bvhs.resize(devices.size());
+
+ vector<BVHMulti *> geom_bvhs;
+ geom_bvhs.reserve(bvh->geometry.size());
+ foreach (Geometry *geom, bvh->geometry) {
+ geom_bvhs.push_back(static_cast<BVHMulti *>(geom->bvh));
+ }
+
/* Broadcast acceleration structure build to all render devices */
+ size_t i = 0;
foreach (SubDevice &sub, devices) {
- if (!sub.device->build_optix_bvh(bvh))
- return false;
+ /* Change geometry BVH pointers to the sub BVH */
+ for (size_t k = 0; k < bvh->geometry.size(); ++k) {
+ bvh->geometry[k]->bvh = geom_bvhs[k]->sub_bvhs[i];
+ }
+
+ if (!bvh_multi->sub_bvhs[i]) {
+ BVHParams params = bvh->params;
+ if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX)
+ params.bvh_layout = BVH_LAYOUT_OPTIX;
+ else if (bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE)
+ params.bvh_layout = sub.device->info.type == DEVICE_OPTIX ? BVH_LAYOUT_OPTIX :
+ BVH_LAYOUT_EMBREE;
+
+ /* Skip building a bottom level acceleration structure for non-instanced geometry on Embree
+ * (since they are put into the top level directly, see bvh_embree.cpp) */
+ if (!params.top_level && params.bvh_layout == BVH_LAYOUT_EMBREE &&
+ !bvh->geometry[0]->is_instanced()) {
+ i++;
+ continue;
+ }
+
+ bvh_multi->sub_bvhs[i] = BVH::create(params, bvh->geometry, bvh->objects, sub.device);
+ }
+
+ sub.device->build_bvh(bvh_multi->sub_bvhs[i], progress, refit);
+ i++;
}
- return true;
- }
- virtual void *bvh_device() const
- {
- /* CPU devices will always be at the back, so simply choose the last one.
- There should only ever be one CPU device anyway and we need the Embree device for it. */
- return devices.back().device->bvh_device();
+ /* Change geomtry BVH pointers back to the multi BVH */
+ for (size_t k = 0; k < bvh->geometry.size(); ++k) {
+ bvh->geometry[k]->bvh = geom_bvhs[k];
+ }
}
- virtual void *osl_memory()
+ virtual void *osl_memory() override
{
if (devices.size() > 1) {
return NULL;
@@ -252,7 +307,7 @@ class MultiDevice : public Device {
return devices.front().device->osl_memory();
}
- bool is_resident(device_ptr key, Device *sub_device)
+ bool is_resident(device_ptr key, Device *sub_device) override
{
foreach (SubDevice &sub, devices) {
if (sub.device == sub_device) {
@@ -299,7 +354,7 @@ class MultiDevice : public Device {
return find_matching_mem_device(key, sub)->ptr_map[key];
}
- void mem_alloc(device_memory &mem)
+ void mem_alloc(device_memory &mem) override
{
device_ptr key = unique_key++;
@@ -335,7 +390,7 @@ class MultiDevice : public Device {
stats.mem_alloc(mem.device_size);
}
- void mem_copy_to(device_memory &mem)
+ void mem_copy_to(device_memory &mem) override
{
device_ptr existing_key = mem.device_pointer;
device_ptr key = (existing_key) ? existing_key : unique_key++;
@@ -378,7 +433,7 @@ class MultiDevice : public Device {
stats.mem_alloc(mem.device_size - existing_size);
}
- void mem_copy_from(device_memory &mem, int y, int w, int h, int elem)
+ void mem_copy_from(device_memory &mem, int y, int w, int h, int elem) override
{
device_ptr key = mem.device_pointer;
int i = 0, sub_h = h / devices.size();
@@ -399,7 +454,7 @@ class MultiDevice : public Device {
mem.device_pointer = key;
}
- void mem_zero(device_memory &mem)
+ void mem_zero(device_memory &mem) override
{
device_ptr existing_key = mem.device_pointer;
device_ptr key = (existing_key) ? existing_key : unique_key++;
@@ -454,7 +509,7 @@ class MultiDevice : public Device {
stats.mem_alloc(mem.device_size - existing_size);
}
- void mem_free(device_memory &mem)
+ void mem_free(device_memory &mem) override
{
device_ptr key = mem.device_pointer;
size_t existing_size = mem.device_size;
@@ -510,7 +565,7 @@ class MultiDevice : public Device {
stats.mem_free(existing_size);
}
- void const_copy_to(const char *name, void *host, size_t size)
+ void const_copy_to(const char *name, void *host, size_t size) override
{
foreach (SubDevice &sub, devices)
sub.device->const_copy_to(name, host, size);
@@ -527,7 +582,7 @@ class MultiDevice : public Device {
int dw,
int dh,
bool transparent,
- const DeviceDrawParams &draw_params)
+ const DeviceDrawParams &draw_params) override
{
assert(rgba.type == MEM_PIXELS);
@@ -551,7 +606,7 @@ class MultiDevice : public Device {
rgba.device_pointer = key;
}
- void map_tile(Device *sub_device, RenderTile &tile)
+ void map_tile(Device *sub_device, RenderTile &tile) override
{
if (!tile.buffer) {
return;
@@ -572,7 +627,7 @@ class MultiDevice : public Device {
}
}
- int device_number(Device *sub_device)
+ int device_number(Device *sub_device) override
{
int i = 0;
@@ -591,7 +646,7 @@ class MultiDevice : public Device {
return -1;
}
- void map_neighbor_tiles(Device *sub_device, RenderTileNeighbors &neighbors)
+ void map_neighbor_tiles(Device *sub_device, RenderTileNeighbors &neighbors) override
{
for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
RenderTile &tile = neighbors.tiles[i];
@@ -643,7 +698,7 @@ class MultiDevice : public Device {
}
}
- void unmap_neighbor_tiles(Device *sub_device, RenderTileNeighbors &neighbors)
+ void unmap_neighbor_tiles(Device *sub_device, RenderTileNeighbors &neighbors) override
{
RenderTile &target_tile = neighbors.target;
device_vector<float> &mem = target_tile.buffers->buffer;
@@ -677,7 +732,7 @@ class MultiDevice : public Device {
}
}
- int get_split_task_count(DeviceTask &task)
+ int get_split_task_count(DeviceTask &task) override
{
int total_tasks = 0;
list<DeviceTask> tasks;
@@ -693,7 +748,7 @@ class MultiDevice : public Device {
return total_tasks;
}
- void task_add(DeviceTask &task)
+ void task_add(DeviceTask &task) override
{
list<SubDevice> task_devices = devices;
if (!denoising_devices.empty()) {
@@ -743,7 +798,7 @@ class MultiDevice : public Device {
}
}
- void task_wait()
+ void task_wait() override
{
foreach (SubDevice &sub, devices)
sub.device->task_wait();
@@ -751,7 +806,7 @@ class MultiDevice : public Device {
sub.device->task_wait();
}
- void task_cancel()
+ void task_cancel() override
{
foreach (SubDevice &sub, devices)
sub.device->task_cancel();
diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp
index c6276c1e955..a721f426dfe 100644
--- a/intern/cycles/device/device_optix.cpp
+++ b/intern/cycles/device/device_optix.cpp
@@ -31,6 +31,7 @@
# include "util/util_logging.h"
# include "util/util_md5.h"
# include "util/util_path.h"
+# include "util/util_progress.h"
# include "util/util_time.h"
# ifdef WITH_CUDA_DYNLOAD
@@ -186,7 +187,6 @@ class OptiXDevice : public CUDADevice {
bool motion_blur = false;
device_vector<SbtRecord> sbt_data;
device_only_memory<KernelParams> launch_params;
- vector<CUdeviceptr> as_mem;
OptixTraversableHandle tlas_handle = 0;
OptixDenoiser denoiser = NULL;
@@ -258,11 +258,6 @@ class OptiXDevice : public CUDADevice {
// Make CUDA context current
const CUDAContextScope scope(cuContext);
- // Free all acceleration structures
- for (CUdeviceptr mem : as_mem) {
- cuMemFree(mem);
- }
-
sbt_data.free();
texture_info.free();
launch_params.free();
@@ -1136,11 +1131,10 @@ class OptiXDevice : public CUDADevice {
}
}
- bool build_optix_bvh(const OptixBuildInput &build_input,
- uint16_t num_motion_steps,
- OptixTraversableHandle &out_handle,
- CUdeviceptr &out_data,
- OptixBuildOperation operation)
+ bool build_optix_bvh(BVHOptiX *bvh,
+ OptixBuildOperation operation,
+ const OptixBuildInput &build_input,
+ uint16_t num_motion_steps)
{
const CUDAContextScope scope(cuContext);
@@ -1166,24 +1160,21 @@ class OptiXDevice : public CUDADevice {
optixAccelComputeMemoryUsage(context, &options, &build_input, 1, &sizes));
// Allocate required output buffers
- device_only_memory<char> temp_mem(this, "temp_build_mem");
+ device_only_memory<char> temp_mem(this, "optix temp as build mem");
temp_mem.alloc_to_device(align_up(sizes.tempSizeInBytes, 8) + 8);
if (!temp_mem.device_pointer)
return false; // Make sure temporary memory allocation succeeded
- // Move textures to host memory if there is not enough room
- size_t size = 0, free = 0;
- cuMemGetInfo(&free, &size);
- size = sizes.outputSizeInBytes + device_working_headroom;
- if (size >= free && can_map_host) {
- move_textures_to_host(size - free, false);
- }
-
+ device_only_memory<char> &out_data = bvh->as_data;
if (operation == OPTIX_BUILD_OPERATION_BUILD) {
- check_result_cuda_ret(cuMemAlloc(&out_data, sizes.outputSizeInBytes));
+ assert(out_data.device == this);
+ out_data.alloc_to_device(sizes.outputSizeInBytes);
+ if (!out_data.device_pointer)
+ return false;
+ }
+ else {
+ assert(out_data.device_pointer && out_data.device_size >= sizes.outputSizeInBytes);
}
-
- as_mem.push_back(out_data);
// Finally build the acceleration structure
OptixAccelEmitDesc compacted_size_prop;
@@ -1192,6 +1183,7 @@ class OptiXDevice : public CUDADevice {
// Make sure this pointer is 8-byte aligned
compacted_size_prop.result = align_up(temp_mem.device_pointer + sizes.tempSizeInBytes, 8);
+ OptixTraversableHandle out_handle = 0;
check_result_optix_ret(optixAccelBuild(context,
NULL,
&options,
@@ -1199,11 +1191,12 @@ class OptiXDevice : public CUDADevice {
1,
temp_mem.device_pointer,
sizes.tempSizeInBytes,
- out_data,
+ out_data.device_pointer,
sizes.outputSizeInBytes,
&out_handle,
background ? &compacted_size_prop : NULL,
background ? 1 : 0));
+ bvh->traversable_handle = static_cast<uint64_t>(out_handle);
// Wait for all operations to finish
check_result_cuda_ret(cuStreamSynchronize(NULL));
@@ -1219,81 +1212,60 @@ class OptiXDevice : public CUDADevice {
// There is no point compacting if the size does not change
if (compacted_size < sizes.outputSizeInBytes) {
- CUdeviceptr compacted_data = 0;
- if (cuMemAlloc(&compacted_data, compacted_size) != CUDA_SUCCESS)
+ device_only_memory<char> compacted_data(this, "optix compacted as");
+ compacted_data.alloc_to_device(compacted_size);
+ if (!compacted_data.device_pointer)
// Do not compact if memory allocation for compacted acceleration structure fails
// Can just use the uncompacted one then, so succeed here regardless
return true;
- as_mem.push_back(compacted_data);
- check_result_optix_ret(optixAccelCompact(
- context, NULL, out_handle, compacted_data, compacted_size, &out_handle));
+ check_result_optix_ret(optixAccelCompact(context,
+ NULL,
+ out_handle,
+ compacted_data.device_pointer,
+ compacted_size,
+ &out_handle));
+ bvh->traversable_handle = static_cast<uint64_t>(out_handle);
// Wait for compaction to finish
check_result_cuda_ret(cuStreamSynchronize(NULL));
- // Free uncompacted acceleration structure
- cuMemFree(out_data);
- as_mem.erase(as_mem.end() - 2); // Remove 'out_data' from 'as_mem' array
+ std::swap(out_data.device_size, compacted_data.device_size);
+ std::swap(out_data.device_pointer, compacted_data.device_pointer);
}
}
return true;
}
- bool build_optix_bvh(BVH *bvh) override
+ void build_bvh(BVH *bvh, Progress &progress, bool refit) override
{
- assert(bvh->params.top_level);
-
- unsigned int num_instances = 0;
- unordered_map<Geometry *, OptixTraversableHandle> geometry;
- geometry.reserve(bvh->geometry.size());
+ BVHOptiX *const bvh_optix = static_cast<BVHOptiX *>(bvh);
- // Free all previous acceleration structures which can not be refit
- std::set<CUdeviceptr> refit_mem;
+ progress.set_substatus("Building OptiX acceleration structure");
- for (Geometry *geom : bvh->geometry) {
- if (static_cast<BVHOptiX *>(geom->bvh)->do_refit) {
- refit_mem.insert(static_cast<BVHOptiX *>(geom->bvh)->optix_data_handle);
- }
- }
+ if (!bvh->params.top_level) {
+ assert(bvh->objects.size() == 1 && bvh->geometry.size() == 1);
- for (CUdeviceptr mem : as_mem) {
- if (refit_mem.find(mem) == refit_mem.end()) {
- cuMemFree(mem);
- }
- }
-
- as_mem.clear();
-
- // Build bottom level acceleration structures (BLAS)
- // Note: Always keep this logic in sync with bvh_optix.cpp!
- for (Object *ob : bvh->objects) {
- // Skip geometry for which acceleration structure already exists
- Geometry *geom = ob->get_geometry();
- if (geometry.find(geom) != geometry.end())
- continue;
-
- OptixTraversableHandle handle;
- OptixBuildOperation operation;
- CUdeviceptr out_data;
- // Refit is only possible in viewport for now.
- if (static_cast<BVHOptiX *>(geom->bvh)->do_refit && !background) {
- out_data = static_cast<BVHOptiX *>(geom->bvh)->optix_data_handle;
- handle = static_cast<BVHOptiX *>(geom->bvh)->optix_handle;
+ // Refit is only possible in viewport for now (because AS is built with
+ // OPTIX_BUILD_FLAG_ALLOW_UPDATE only there, see above)
+ OptixBuildOperation operation = OPTIX_BUILD_OPERATION_BUILD;
+ if (refit && !background) {
+ assert(bvh_optix->traversable_handle != 0);
operation = OPTIX_BUILD_OPERATION_UPDATE;
}
else {
- out_data = 0;
- handle = 0;
- operation = OPTIX_BUILD_OPERATION_BUILD;
+ bvh_optix->as_data.free();
+ bvh_optix->traversable_handle = 0;
}
+ // Build bottom level acceleration structures (BLAS)
+ Geometry *const geom = bvh->geometry[0];
if (geom->geometry_type == Geometry::HAIR) {
// Build BLAS for curve primitives
- Hair *const hair = static_cast<Hair *const>(ob->get_geometry());
+ Hair *const hair = static_cast<Hair *const>(geom);
if (hair->num_curves() == 0) {
- continue;
+ return;
}
const size_t num_segments = hair->num_segments();
@@ -1304,10 +1276,10 @@ class OptiXDevice : public CUDADevice {
num_motion_steps = hair->get_motion_steps();
}
- device_vector<OptixAabb> aabb_data(this, "temp_aabb_data", MEM_READ_ONLY);
+ device_vector<OptixAabb> aabb_data(this, "optix temp aabb data", MEM_READ_ONLY);
# if OPTIX_ABI_VERSION >= 36
- device_vector<int> index_data(this, "temp_index_data", MEM_READ_ONLY);
- device_vector<float4> vertex_data(this, "temp_vertex_data", MEM_READ_ONLY);
+ device_vector<int> index_data(this, "optix temp index data", MEM_READ_ONLY);
+ device_vector<float4> vertex_data(this, "optix temp vertex data", MEM_READ_ONLY);
// Four control points for each curve segment
const size_t num_vertices = num_segments * 4;
if (DebugFlags().optix.curves_api && hair->curve_shape == CURVE_THICK) {
@@ -1325,7 +1297,7 @@ class OptiXDevice : public CUDADevice {
size_t center_step = (num_motion_steps - 1) / 2;
if (step != center_step) {
size_t attr_offset = (step > center_step) ? step - 1 : step;
- // Technically this is a float4 array, but sizeof(float3) is the same as sizeof(float4)
+ // Technically this is a float4 array, but sizeof(float3) == sizeof(float4)
keys = motion_keys->data_float3() + attr_offset * hair->get_curve_keys().size();
}
@@ -1452,22 +1424,15 @@ class OptiXDevice : public CUDADevice {
# endif
}
- // Allocate memory for new BLAS and build it
- if (build_optix_bvh(build_input, num_motion_steps, handle, out_data, operation)) {
- geometry.insert({ob->get_geometry(), handle});
- static_cast<BVHOptiX *>(geom->bvh)->optix_data_handle = out_data;
- static_cast<BVHOptiX *>(geom->bvh)->optix_handle = handle;
- static_cast<BVHOptiX *>(geom->bvh)->do_refit = false;
- }
- else {
- return false;
+ if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) {
+ progress.set_error("Failed to build OptiX acceleration structure");
}
}
else if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
// Build BLAS for triangle primitives
- Mesh *const mesh = static_cast<Mesh *const>(ob->get_geometry());
+ Mesh *const mesh = static_cast<Mesh *const>(geom);
if (mesh->num_triangles() == 0) {
- continue;
+ return;
}
const size_t num_verts = mesh->get_verts().size();
@@ -1478,12 +1443,12 @@ class OptiXDevice : public CUDADevice {
num_motion_steps = mesh->get_motion_steps();
}
- device_vector<int> index_data(this, "temp_index_data", MEM_READ_ONLY);
+ device_vector<int> index_data(this, "optix temp index data", MEM_READ_ONLY);
index_data.alloc(mesh->get_triangles().size());
memcpy(index_data.data(),
mesh->get_triangles().data(),
mesh->get_triangles().size() * sizeof(int));
- device_vector<float3> vertex_data(this, "temp_vertex_data", MEM_READ_ONLY);
+ device_vector<float3> vertex_data(this, "optix temp vertex data", MEM_READ_ONLY);
vertex_data.alloc(num_verts * num_motion_steps);
for (size_t step = 0; step < num_motion_steps; ++step) {
@@ -1528,190 +1493,208 @@ class OptiXDevice : public CUDADevice {
build_input.triangleArray.numSbtRecords = 1;
build_input.triangleArray.primitiveIndexOffset = mesh->optix_prim_offset;
- // Allocate memory for new BLAS and build it
- if (build_optix_bvh(build_input, num_motion_steps, handle, out_data, operation)) {
- geometry.insert({ob->get_geometry(), handle});
- static_cast<BVHOptiX *>(geom->bvh)->optix_data_handle = out_data;
- static_cast<BVHOptiX *>(geom->bvh)->optix_handle = handle;
- static_cast<BVHOptiX *>(geom->bvh)->do_refit = false;
- }
- else {
- return false;
+ if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) {
+ progress.set_error("Failed to build OptiX acceleration structure");
}
}
}
+ else {
+ unsigned int num_instances = 0;
+
+ bvh_optix->as_data.free();
+ bvh_optix->traversable_handle = 0;
+ bvh_optix->motion_transform_data.free();
- // Fill instance descriptions
+ // Fill instance descriptions
# if OPTIX_ABI_VERSION < 41
- device_vector<OptixAabb> aabbs(this, "tlas_aabbs", MEM_READ_ONLY);
- aabbs.alloc(bvh->objects.size());
+ device_vector<OptixAabb> aabbs(this, "optix tlas aabbs", MEM_READ_ONLY);
+ aabbs.alloc(bvh->objects.size());
# endif
- device_vector<OptixInstance> instances(this, "tlas_instances", MEM_READ_ONLY);
- instances.alloc(bvh->objects.size());
-
- for (Object *ob : bvh->objects) {
- // Skip non-traceable objects
- if (!ob->is_traceable())
- continue;
-
- // Create separate instance for triangle/curve meshes of an object
- const auto handle_it = geometry.find(ob->get_geometry());
- if (handle_it == geometry.end()) {
- continue;
+ device_vector<OptixInstance> instances(this, "optix tlas instances", MEM_READ_ONLY);
+ instances.alloc(bvh->objects.size());
+
+ // Calculate total motion transform size and allocate memory for them
+ size_t motion_transform_offset = 0;
+ if (motion_blur) {
+ size_t total_motion_transform_size = 0;
+ for (Object *const ob : bvh->objects) {
+ if (ob->is_traceable() && ob->use_motion()) {
+ total_motion_transform_size = align_up(total_motion_transform_size,
+ OPTIX_TRANSFORM_BYTE_ALIGNMENT);
+ const size_t motion_keys = max(ob->get_motion().size(), 2) - 2;
+ total_motion_transform_size = total_motion_transform_size +
+ sizeof(OptixSRTMotionTransform) +
+ motion_keys * sizeof(OptixSRTData);
+ }
+ }
+
+ assert(bvh_optix->motion_transform_data.device == this);
+ bvh_optix->motion_transform_data.alloc_to_device(total_motion_transform_size);
}
- OptixTraversableHandle handle = handle_it->second;
+
+ for (Object *ob : bvh->objects) {
+ // Skip non-traceable objects
+ if (!ob->is_traceable())
+ continue;
+
+ BVHOptiX *const blas = static_cast<BVHOptiX *>(ob->get_geometry()->bvh);
+ OptixTraversableHandle handle = blas->traversable_handle;
# if OPTIX_ABI_VERSION < 41
- OptixAabb &aabb = aabbs[num_instances];
- aabb.minX = ob->bounds.min.x;
- aabb.minY = ob->bounds.min.y;
- aabb.minZ = ob->bounds.min.z;
- aabb.maxX = ob->bounds.max.x;
- aabb.maxY = ob->bounds.max.y;
- aabb.maxZ = ob->bounds.max.z;
+ OptixAabb &aabb = aabbs[num_instances];
+ aabb.minX = ob->bounds.min.x;
+ aabb.minY = ob->bounds.min.y;
+ aabb.minZ = ob->bounds.min.z;
+ aabb.maxX = ob->bounds.max.x;
+ aabb.maxY = ob->bounds.max.y;
+ aabb.maxZ = ob->bounds.max.z;
# endif
- OptixInstance &instance = instances[num_instances++];
- memset(&instance, 0, sizeof(instance));
+ OptixInstance &instance = instances[num_instances++];
+ memset(&instance, 0, sizeof(instance));
- // Clear transform to identity matrix
- instance.transform[0] = 1.0f;
- instance.transform[5] = 1.0f;
- instance.transform[10] = 1.0f;
+ // Clear transform to identity matrix
+ instance.transform[0] = 1.0f;
+ instance.transform[5] = 1.0f;
+ instance.transform[10] = 1.0f;
- // Set user instance ID to object index
- instance.instanceId = ob->get_device_index();
+ // Set user instance ID to object index
+ instance.instanceId = ob->get_device_index();
- // Have to have at least one bit in the mask, or else instance would always be culled
- instance.visibilityMask = 1;
+ // Have to have at least one bit in the mask, or else instance would always be culled
+ instance.visibilityMask = 1;
- if (ob->get_geometry()->has_volume) {
- // Volumes have a special bit set in the visibility mask so a trace can mask only volumes
- instance.visibilityMask |= 2;
- }
+ if (ob->get_geometry()->has_volume) {
+ // Volumes have a special bit set in the visibility mask so a trace can mask only volumes
+ instance.visibilityMask |= 2;
+ }
- if (ob->get_geometry()->geometry_type == Geometry::HAIR) {
- // Same applies to curves (so they can be skipped in local trace calls)
- instance.visibilityMask |= 4;
+ if (ob->get_geometry()->geometry_type == Geometry::HAIR) {
+ // Same applies to curves (so they can be skipped in local trace calls)
+ instance.visibilityMask |= 4;
# if OPTIX_ABI_VERSION >= 36
- if (motion_blur && ob->get_geometry()->has_motion_blur() &&
- DebugFlags().optix.curves_api &&
- static_cast<const Hair *>(ob->get_geometry())->curve_shape == CURVE_THICK) {
- // Select between motion blur and non-motion blur built-in intersection module
- instance.sbtOffset = PG_HITD_MOTION - PG_HITD;
- }
+ if (motion_blur && ob->get_geometry()->has_motion_blur() &&
+ DebugFlags().optix.curves_api &&
+ static_cast<const Hair *>(ob->get_geometry())->curve_shape == CURVE_THICK) {
+ // Select between motion blur and non-motion blur built-in intersection module
+ instance.sbtOffset = PG_HITD_MOTION - PG_HITD;
+ }
# endif
- }
-
- // Insert motion traversable if object has motion
- if (motion_blur && ob->use_motion()) {
- size_t motion_keys = max(ob->get_motion().size(), 2) - 2;
- size_t motion_transform_size = sizeof(OptixSRTMotionTransform) +
- motion_keys * sizeof(OptixSRTData);
-
- const CUDAContextScope scope(cuContext);
-
- CUdeviceptr motion_transform_gpu = 0;
- check_result_cuda_ret(cuMemAlloc(&motion_transform_gpu, motion_transform_size));
- as_mem.push_back(motion_transform_gpu);
-
- // Allocate host side memory for motion transform and fill it with transform data
- OptixSRTMotionTransform &motion_transform = *reinterpret_cast<OptixSRTMotionTransform *>(
- new uint8_t[motion_transform_size]);
- motion_transform.child = handle;
- motion_transform.motionOptions.numKeys = ob->get_motion().size();
- motion_transform.motionOptions.flags = OPTIX_MOTION_FLAG_NONE;
- motion_transform.motionOptions.timeBegin = 0.0f;
- motion_transform.motionOptions.timeEnd = 1.0f;
-
- OptixSRTData *const srt_data = motion_transform.srtData;
- array<DecomposedTransform> decomp(ob->get_motion().size());
- transform_motion_decompose(
- decomp.data(), ob->get_motion().data(), ob->get_motion().size());
-
- for (size_t i = 0; i < ob->get_motion().size(); ++i) {
- // Scale
- srt_data[i].sx = decomp[i].y.w; // scale.x.x
- srt_data[i].sy = decomp[i].z.w; // scale.y.y
- srt_data[i].sz = decomp[i].w.w; // scale.z.z
-
- // Shear
- srt_data[i].a = decomp[i].z.x; // scale.x.y
- srt_data[i].b = decomp[i].z.y; // scale.x.z
- srt_data[i].c = decomp[i].w.x; // scale.y.z
- assert(decomp[i].z.z == 0.0f); // scale.y.x
- assert(decomp[i].w.y == 0.0f); // scale.z.x
- assert(decomp[i].w.z == 0.0f); // scale.z.y
-
- // Pivot point
- srt_data[i].pvx = 0.0f;
- srt_data[i].pvy = 0.0f;
- srt_data[i].pvz = 0.0f;
-
- // Rotation
- srt_data[i].qx = decomp[i].x.x;
- srt_data[i].qy = decomp[i].x.y;
- srt_data[i].qz = decomp[i].x.z;
- srt_data[i].qw = decomp[i].x.w;
-
- // Translation
- srt_data[i].tx = decomp[i].y.x;
- srt_data[i].ty = decomp[i].y.y;
- srt_data[i].tz = decomp[i].y.z;
}
- // Upload motion transform to GPU
- cuMemcpyHtoD(motion_transform_gpu, &motion_transform, motion_transform_size);
- delete[] reinterpret_cast<uint8_t *>(&motion_transform);
+ // Insert motion traversable if object has motion
+ if (motion_blur && ob->use_motion()) {
+ size_t motion_keys = max(ob->get_motion().size(), 2) - 2;
+ size_t motion_transform_size = sizeof(OptixSRTMotionTransform) +
+ motion_keys * sizeof(OptixSRTData);
+
+ const CUDAContextScope scope(cuContext);
+
+ motion_transform_offset = align_up(motion_transform_offset,
+ OPTIX_TRANSFORM_BYTE_ALIGNMENT);
+ CUdeviceptr motion_transform_gpu = bvh_optix->motion_transform_data.device_pointer +
+ motion_transform_offset;
+ motion_transform_offset += motion_transform_size;
+
+ // Allocate host side memory for motion transform and fill it with transform data
+ OptixSRTMotionTransform &motion_transform = *reinterpret_cast<OptixSRTMotionTransform *>(
+ new uint8_t[motion_transform_size]);
+ motion_transform.child = handle;
+ motion_transform.motionOptions.numKeys = ob->get_motion().size();
+ motion_transform.motionOptions.flags = OPTIX_MOTION_FLAG_NONE;
+ motion_transform.motionOptions.timeBegin = 0.0f;
+ motion_transform.motionOptions.timeEnd = 1.0f;
+
+ OptixSRTData *const srt_data = motion_transform.srtData;
+ array<DecomposedTransform> decomp(ob->get_motion().size());
+ transform_motion_decompose(
+ decomp.data(), ob->get_motion().data(), ob->get_motion().size());
+
+ for (size_t i = 0; i < ob->get_motion().size(); ++i) {
+ // Scale
+ srt_data[i].sx = decomp[i].y.w; // scale.x.x
+ srt_data[i].sy = decomp[i].z.w; // scale.y.y
+ srt_data[i].sz = decomp[i].w.w; // scale.z.z
+
+ // Shear
+ srt_data[i].a = decomp[i].z.x; // scale.x.y
+ srt_data[i].b = decomp[i].z.y; // scale.x.z
+ srt_data[i].c = decomp[i].w.x; // scale.y.z
+ assert(decomp[i].z.z == 0.0f); // scale.y.x
+ assert(decomp[i].w.y == 0.0f); // scale.z.x
+ assert(decomp[i].w.z == 0.0f); // scale.z.y
+
+ // Pivot point
+ srt_data[i].pvx = 0.0f;
+ srt_data[i].pvy = 0.0f;
+ srt_data[i].pvz = 0.0f;
+
+ // Rotation
+ srt_data[i].qx = decomp[i].x.x;
+ srt_data[i].qy = decomp[i].x.y;
+ srt_data[i].qz = decomp[i].x.z;
+ srt_data[i].qw = decomp[i].x.w;
+
+ // Translation
+ srt_data[i].tx = decomp[i].y.x;
+ srt_data[i].ty = decomp[i].y.y;
+ srt_data[i].tz = decomp[i].y.z;
+ }
- // Disable instance transform if object uses motion transform already
- instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
+ // Upload motion transform to GPU
+ cuMemcpyHtoD(motion_transform_gpu, &motion_transform, motion_transform_size);
+ delete[] reinterpret_cast<uint8_t *>(&motion_transform);
- // Get traversable handle to motion transform
- optixConvertPointerToTraversableHandle(context,
- motion_transform_gpu,
- OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM,
- &instance.traversableHandle);
- }
- else {
- instance.traversableHandle = handle;
+ // Disable instance transform if object uses motion transform already
+ instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
- if (ob->get_geometry()->is_instanced()) {
- // Set transform matrix
- memcpy(instance.transform, &ob->get_tfm(), sizeof(instance.transform));
+ // Get traversable handle to motion transform
+ optixConvertPointerToTraversableHandle(context,
+ motion_transform_gpu,
+ OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM,
+ &instance.traversableHandle);
}
else {
- // Disable instance transform if geometry already has it applied to vertex data
- instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
- // Non-instanced objects read ID from prim_object, so
- // distinguish them from instanced objects with high bit set
- instance.instanceId |= 0x800000;
+ instance.traversableHandle = handle;
+
+ if (ob->get_geometry()->is_instanced()) {
+ // Set transform matrix
+ memcpy(instance.transform, &ob->get_tfm(), sizeof(instance.transform));
+ }
+ else {
+ // Disable instance transform if geometry already has it applied to vertex data
+ instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM;
+ // Non-instanced objects read ID from prim_object, so
+ // distinguish them from instanced objects with high bit set
+ instance.instanceId |= 0x800000;
+ }
}
}
- }
- // Upload instance descriptions
+ // Upload instance descriptions
# if OPTIX_ABI_VERSION < 41
- aabbs.resize(num_instances);
- aabbs.copy_to_device();
+ aabbs.resize(num_instances);
+ aabbs.copy_to_device();
# endif
- instances.resize(num_instances);
- instances.copy_to_device();
+ instances.resize(num_instances);
+ instances.copy_to_device();
- // Build top-level acceleration structure (TLAS)
- OptixBuildInput build_input = {};
- build_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES;
+ // Build top-level acceleration structure (TLAS)
+ OptixBuildInput build_input = {};
+ build_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES;
# if OPTIX_ABI_VERSION < 41 // Instance AABBs no longer need to be set since OptiX 7.2
- build_input.instanceArray.aabbs = aabbs.device_pointer;
- build_input.instanceArray.numAabbs = num_instances;
+ build_input.instanceArray.aabbs = aabbs.device_pointer;
+ build_input.instanceArray.numAabbs = num_instances;
# endif
- build_input.instanceArray.instances = instances.device_pointer;
- build_input.instanceArray.numInstances = num_instances;
+ build_input.instanceArray.instances = instances.device_pointer;
+ build_input.instanceArray.numInstances = num_instances;
- CUdeviceptr out_data = 0;
- tlas_handle = 0;
- return build_optix_bvh(build_input, 0, tlas_handle, out_data, OPTIX_BUILD_OPERATION_BUILD);
+ if (!build_optix_bvh(bvh_optix, OPTIX_BUILD_OPERATION_BUILD, build_input, 0)) {
+ progress.set_error("Failed to build OptiX acceleration structure");
+ }
+ tlas_handle = bvh_optix->traversable_handle;
+ }
}
void const_copy_to(const char *name, void *host, size_t size) override
@@ -1724,7 +1707,7 @@ class OptiXDevice : public CUDADevice {
if (strcmp(name, "__data") == 0) {
assert(size <= sizeof(KernelData));
- // Fix traversable handle on multi devices
+ // Update traversable handle (since it is different for each device on multi devices)
KernelData *const data = (KernelData *)host;
*(OptixTraversableHandle *)&data->bvh.scene = tlas_handle;
diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp
index a72fbbad635..be9efcd43ee 100644
--- a/intern/cycles/device/opencl/opencl_util.cpp
+++ b/intern/cycles/device/opencl/opencl_util.cpp
@@ -780,13 +780,25 @@ bool OpenCLInfo::device_supported(const string &platform_name, const cl_device_i
return true;
}
- /* It is possible to have Iris GPU on AMD/Apple OpenCL framework
- * (aka, it will not be on Intel framework). This isn't supported
- * and needs an explicit blacklist.
- */
- if (strstr(device_name.c_str(), "Iris")) {
+ /* Allow Intel GPUs on Intel OpenCL platform. */
+ if (platform_name.find("Intel") != string::npos) {
+ if (device_type != CL_DEVICE_TYPE_GPU) {
+ /* OpenCL on Intel CPU is not an officially supported configuration.
+ * Use hybrid CPU+GPU rendering to utilize both GPU and CPU. */
+ return false;
+ }
+
+# ifdef __APPLE__
+ /* Apple uses own framework, which can also put Iris onto AMD frame-work.
+ * This isn't supported configuration. */
return false;
+# else
+ if (device_name.find("Iris") != string::npos || device_name.find("Xe") != string::npos) {
+ return true;
+ }
+# endif
}
+
if (platform_name == "AMD Accelerated Parallel Processing" &&
device_type == CL_DEVICE_TYPE_GPU) {
if (driver_major < 2236) {
diff --git a/intern/cycles/kernel/bvh/bvh_embree.h b/intern/cycles/kernel/bvh/bvh_embree.h
index ca637288bee..4605c3ea51d 100644
--- a/intern/cycles/kernel/bvh/bvh_embree.h
+++ b/intern/cycles/kernel/bvh/bvh_embree.h
@@ -112,8 +112,7 @@ ccl_device_inline void kernel_embree_convert_hit(KernelGlobals *kg,
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
rtcGetGeometry(kernel_data.bvh.scene, hit->instID[0]));
isect->prim = hit->primID +
- (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)) +
- kernel_tex_fetch(__object_node, hit->instID[0] / 2);
+ (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
isect->object = hit->instID[0] / 2;
}
else {
@@ -137,8 +136,7 @@ ccl_device_inline void kernel_embree_convert_sss_hit(KernelGlobals *kg,
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
rtcGetGeometry(kernel_data.bvh.scene, local_object_id * 2));
isect->prim = hit->primID +
- (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)) +
- kernel_tex_fetch(__object_node, local_object_id);
+ (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
isect->object = local_object_id;
isect->type = kernel_tex_fetch(__prim_type, isect->prim);
}
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 6beabebb92f..9d00311f746 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -1397,10 +1397,12 @@ typedef enum KernelBVHLayout {
BVH_LAYOUT_BVH2 = (1 << 0),
BVH_LAYOUT_EMBREE = (1 << 1),
BVH_LAYOUT_OPTIX = (1 << 2),
+ BVH_LAYOUT_MULTI_OPTIX = (1 << 3),
+ BVH_LAYOUT_MULTI_OPTIX_EMBREE = (1 << 4),
/* Default BVH layout to use for CPU. */
BVH_LAYOUT_AUTO = BVH_LAYOUT_EMBREE,
- BVH_LAYOUT_ALL = (unsigned int)(~0u),
+ BVH_LAYOUT_ALL = BVH_LAYOUT_BVH2 | BVH_LAYOUT_EMBREE | BVH_LAYOUT_OPTIX,
} KernelBVHLayout;
typedef struct KernelBVH {
diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
index 12f4eaf0b79..64b98a91853 100644
--- a/intern/cycles/render/geometry.cpp
+++ b/intern/cycles/render/geometry.cpp
@@ -15,8 +15,7 @@
*/
#include "bvh/bvh.h"
-#include "bvh/bvh_build.h"
-#include "bvh/bvh_embree.h"
+#include "bvh/bvh2.h"
#include "device/device.h"
@@ -41,6 +40,7 @@
#include "util/util_foreach.h"
#include "util/util_logging.h"
#include "util/util_progress.h"
+#include "util/util_task.h"
CCL_NAMESPACE_BEGIN
@@ -162,7 +162,8 @@ int Geometry::motion_step(float time) const
bool Geometry::need_build_bvh(BVHLayout layout) const
{
- return !transform_applied || has_surface_bssrdf || layout == BVH_LAYOUT_OPTIX;
+ return is_instanced() || layout == BVH_LAYOUT_OPTIX || layout == BVH_LAYOUT_MULTI_OPTIX ||
+ layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE;
}
bool Geometry::is_instanced() const
@@ -218,7 +219,7 @@ void Geometry::compute_bvh(
bvh->geometry = geometry;
bvh->objects = objects;
- bvh->refit(*progress);
+ device->build_bvh(bvh, *progress, true);
}
else {
progress->set_status(msg, "Building BVH");
@@ -235,7 +236,7 @@ void Geometry::compute_bvh(
delete bvh;
bvh = BVH::create(bparams, geometry, objects, device);
- MEM_GUARDED_CALL(progress, bvh->build, *progress);
+ MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false);
}
}
@@ -1162,25 +1163,66 @@ void GeometryManager::device_update_bvh(Device *device,
VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
- BVH *bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
- bvh->build(progress, &device->stats);
+ delete scene->bvh;
+ BVH *bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
+ device->build_bvh(bvh, progress, false);
if (progress.get_cancel()) {
-#ifdef WITH_EMBREE
- if (dscene->data.bvh.scene) {
- BVHEmbree::destroy(dscene->data.bvh.scene);
- dscene->data.bvh.scene = NULL;
- }
-#endif
- delete bvh;
return;
}
+ PackedBVH pack;
+ if (bparams.bvh_layout == BVH_LAYOUT_BVH2) {
+ pack = std::move(static_cast<BVH2 *>(bvh)->pack);
+ }
+ else {
+ progress.set_status("Updating Scene BVH", "Packing BVH primitives");
+
+ size_t num_prims = 0;
+ size_t num_tri_verts = 0;
+ foreach (Geometry *geom, scene->geometry) {
+ if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
+ Mesh *mesh = static_cast<Mesh *>(geom);
+ num_prims += mesh->num_triangles();
+ num_tri_verts += 3 * mesh->num_triangles();
+ }
+ else if (geom->is_hair()) {
+ Hair *hair = static_cast<Hair *>(geom);
+ num_prims += hair->num_segments();
+ }
+ }
+
+ pack.root_index = -1;
+ pack.prim_tri_index.reserve(num_prims);
+ pack.prim_tri_verts.reserve(num_tri_verts);
+ pack.prim_type.reserve(num_prims);
+ pack.prim_index.reserve(num_prims);
+ pack.prim_object.reserve(num_prims);
+ pack.prim_visibility.reserve(num_prims);
+
+ // Merge visibility flags of all objects and find object index for non-instanced geometry
+ unordered_map<const Geometry *, pair<int, uint>> geometry_to_object_info;
+ geometry_to_object_info.reserve(scene->geometry.size());
+ foreach (Object *ob, scene->objects) {
+ const Geometry *const geom = ob->get_geometry();
+ pair<int, uint> &info = geometry_to_object_info[geom];
+ info.second |= ob->visibility_for_tracing();
+ if (!geom->is_instanced()) {
+ info.first = ob->get_device_index();
+ }
+ }
+
+ // Iterate over scene mesh list instead of objects, since 'optix_prim_offset' was calculated
+ // based on that list, which may be ordered differently from the object list.
+ foreach (Geometry *geom, scene->geometry) {
+ const pair<int, uint> &info = geometry_to_object_info[geom];
+ geom->pack_primitives(pack, info.first, info.second);
+ }
+ }
+
/* copy to device */
progress.set_status("Updating Scene BVH", "Copying BVH to device");
- PackedBVH &pack = bvh->pack;
-
if (pack.nodes.size()) {
dscene->bvh_nodes.steal_data(pack.nodes);
dscene->bvh_nodes.copy_to_device();
@@ -1226,10 +1268,8 @@ void GeometryManager::device_update_bvh(Device *device,
dscene->data.bvh.bvh_layout = bparams.bvh_layout;
dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions();
-
- bvh->copy_to_device(progress, dscene);
-
- delete bvh;
+ /* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */
+ dscene->data.bvh.scene = NULL;
}
void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress)
@@ -1653,14 +1693,6 @@ void GeometryManager::device_update(Device *device,
void GeometryManager::device_free(Device *device, DeviceScene *dscene)
{
-#ifdef WITH_EMBREE
- if (dscene->data.bvh.scene) {
- if (dscene->data.bvh.bvh_layout == BVH_LAYOUT_EMBREE)
- BVHEmbree::destroy(dscene->data.bvh.scene);
- dscene->data.bvh.scene = NULL;
- }
-#endif
-
dscene->bvh_nodes.free();
dscene->bvh_leaf_nodes.free();
dscene->object_node.free();
diff --git a/intern/cycles/render/geometry.h b/intern/cycles/render/geometry.h
index 1c101540464..d3daf0cc809 100644
--- a/intern/cycles/render/geometry.h
+++ b/intern/cycles/render/geometry.h
@@ -41,6 +41,7 @@ class Scene;
class SceneParams;
class Shader;
class Volume;
+struct PackedBVH;
/* Geometry
*
@@ -124,6 +125,8 @@ class Geometry : public Node {
int n,
int total);
+ virtual void pack_primitives(PackedBVH &pack, int object, uint visibility) = 0;
+
/* Check whether the geometry should have own BVH built separately. Briefly,
* own BVH is needed for geometry, if:
*
diff --git a/intern/cycles/render/hair.cpp b/intern/cycles/render/hair.cpp
index d67bd209142..896e798b6f9 100644
--- a/intern/cycles/render/hair.cpp
+++ b/intern/cycles/render/hair.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-#include "render/hair.h"
+#include "bvh/bvh.h"
+
#include "render/curves.h"
+#include "render/hair.h"
#include "render/scene.h"
CCL_NAMESPACE_BEGIN
@@ -492,4 +494,35 @@ void Hair::pack_curves(Scene *scene,
}
}
+void Hair::pack_primitives(PackedBVH &pack, int object, uint visibility)
+{
+ if (curve_first_key.empty())
+ return;
+
+ const size_t num_prims = num_segments();
+ pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims);
+ pack.prim_type.reserve(pack.prim_type.size() + num_prims);
+ pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims);
+ pack.prim_index.reserve(pack.prim_index.size() + num_prims);
+ pack.prim_object.reserve(pack.prim_object.size() + num_prims);
+ // 'pack.prim_time' is unused by Embree and OptiX
+
+ uint type = has_motion_blur() ?
+ ((curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
+ PRIMITIVE_MOTION_CURVE_THICK) :
+ ((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK);
+
+ for (size_t j = 0; j < num_curves(); ++j) {
+ Curve curve = get_curve(j);
+ for (size_t k = 0; k < curve.num_segments(); ++k) {
+ pack.prim_tri_index.push_back_reserved(-1);
+ pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(type, k));
+ pack.prim_visibility.push_back_reserved(visibility);
+ // Each curve segment points back to its curve index
+ pack.prim_index.push_back_reserved(j + prim_offset);
+ pack.prim_object.push_back_reserved(object);
+ }
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/hair.h b/intern/cycles/render/hair.h
index 32c5b00e879..c7be08d679c 100644
--- a/intern/cycles/render/hair.h
+++ b/intern/cycles/render/hair.h
@@ -145,6 +145,8 @@ class Hair : public Geometry {
/* BVH */
void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
+
+ void pack_primitives(PackedBVH &pack, int object, uint visibility) override;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 3e6ff289c85..30858c4f68b 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -493,8 +493,8 @@ static bool image_associate_alpha(ImageManager::Image *img)
template<TypeDesc::BASETYPE FileFormat, typename StorageType>
bool ImageManager::file_load_image(Image *img, int texture_limit)
{
- /* we only handle certain number of components */
- if (!(img->metadata.channels >= 1 && img->metadata.channels <= 4)) {
+ /* Ignore empty images. */
+ if (!(img->metadata.channels > 0)) {
return false;
}
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 43e664a686f..a0afdd3b841 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -805,4 +805,35 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui
}
}
+void Mesh::pack_primitives(PackedBVH &pack, int object, uint visibility)
+{
+ if (triangles.empty())
+ return;
+
+ const size_t num_prims = num_triangles();
+ pack.prim_tri_index.reserve(pack.prim_tri_index.size() + num_prims);
+ pack.prim_tri_verts.reserve(pack.prim_tri_verts.size() + num_prims * 3);
+ pack.prim_type.reserve(pack.prim_type.size() + num_prims);
+ pack.prim_visibility.reserve(pack.prim_visibility.size() + num_prims);
+ pack.prim_index.reserve(pack.prim_index.size() + num_prims);
+ pack.prim_object.reserve(pack.prim_object.size() + num_prims);
+ // 'pack.prim_time' is unused by Embree and OptiX
+
+ uint type = has_motion_blur() ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE;
+
+ for (size_t k = 0; k < num_prims; ++k) {
+ pack.prim_tri_index.push_back_reserved(pack.prim_tri_verts.size());
+
+ const Mesh::Triangle t = get_triangle(k);
+ pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[0]]));
+ pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[1]]));
+ pack.prim_tri_verts.push_back_reserved(float3_to_float4(verts[t.v[2]]));
+
+ pack.prim_type.push_back_reserved(type);
+ pack.prim_visibility.push_back_reserved(visibility);
+ pack.prim_index.push_back_reserved(k + prim_offset);
+ pack.prim_object.push_back_reserved(object);
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index e2746e560da..b0a16fdfd8f 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -184,9 +184,8 @@ class Mesh : public Geometry {
unordered_multimap<int, int>
vert_stitching_map; /* stitching index -> multiple real vert indices */
- friend class BVH;
+ friend class BVH2;
friend class BVHBuild;
- friend class BVHEmbree;
friend class BVHSpatialSplit;
friend class DiagSplit;
friend class EdgeDice;
@@ -233,6 +232,8 @@ class Mesh : public Geometry {
size_t tri_offset);
void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset);
+ void pack_primitives(PackedBVH &pack, int object, uint visibility) override;
+
void tessellate(DiagSplit *split);
SubdFace get_subd_face(size_t index) const;
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index 98c256a43b5..b7720b7aa99 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -16,6 +16,7 @@
#include <stdlib.h>
+#include "bvh/bvh.h"
#include "device/device.h"
#include "render/background.h"
#include "render/bake.h"
@@ -100,6 +101,7 @@ Scene::Scene(const SceneParams &params_, Device *device)
{
memset((void *)&dscene.data, 0, sizeof(dscene.data));
+ bvh = NULL;
camera = create_node<Camera>();
dicing_camera = create_node<Camera>();
lookup_tables = new LookupTables();
@@ -135,6 +137,9 @@ Scene::~Scene()
void Scene::free_memory(bool final)
{
+ delete bvh;
+ bvh = NULL;
+
foreach (Shader *s, shaders)
delete s;
foreach (Geometry *g, geometry)
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 6686327dc49..27e9a131bbd 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -38,6 +38,7 @@ CCL_NAMESPACE_BEGIN
class AttributeRequestSet;
class Background;
+class BVH;
class Camera;
class Device;
class DeviceInfo;
@@ -220,6 +221,7 @@ class Scene : public NodeOwner {
string name;
/* data */
+ BVH *bvh;
Camera *camera;
Camera *dicing_camera;
LookupTables *lookup_tables;
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index cf49dedc426..7e06b427e4d 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -347,8 +347,15 @@ void Shader::tag_update(Scene *scene)
foreach (ShaderNode *node, graph->nodes)
node->attributes(this, &attributes);
- if (has_displacement && displacement_method == DISPLACE_BOTH) {
- attributes.add(ATTR_STD_POSITION_UNDISPLACED);
+ if (has_displacement) {
+ if (displacement_method == DISPLACE_BOTH) {
+ attributes.add(ATTR_STD_POSITION_UNDISPLACED);
+ }
+ if (displacement_method_is_modified()) {
+ need_update_geometry = true;
+ scene->geometry_manager->need_update = true;
+ scene->object_manager->need_flags_update = true;
+ }
}
/* compare if the attributes changed, mesh manager will check
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index e8611839aea..1739659ab88 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -187,6 +187,11 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
${X11_X11_INCLUDE_PATH}
)
+ list(APPEND LIB
+ ${X11_X11_LIB}
+ ${X11_Xrender_LIB}
+ )
+
list(APPEND SRC
intern/GHOST_DisplayManagerX11.cpp
intern/GHOST_SystemX11.cpp
@@ -238,6 +243,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
list(APPEND INC_SYS
${X11_xf86vmode_INCLUDE_PATH}
)
+ list(APPEND LIB
+ ${X11_Xf86vmode_LIB}
+ )
endif()
if(WITH_X11_XFIXES)
@@ -245,6 +253,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
list(APPEND INC_SYS
${X11_Xfixes_INCLUDE_PATH}
)
+ list(APPEND LIB
+ ${X11_Xfixes_LIB}
+ )
endif()
if(WITH_X11_ALPHA)
@@ -256,6 +267,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
list(APPEND INC_SYS
${X11_Xinput_INCLUDE_PATH}
)
+ list(APPEND LIB
+ ${X11_Xinput_LIB}
+ )
endif()
add_definitions(-DWITH_GHOST_X11)
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 64740b68c0c..2bc73f7eb22 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -1052,7 +1052,7 @@ int GHOST_XrSessionIsRunning(const GHOST_XrContextHandle xr_context);
/**
* Check if \a xr_context has a session that requires an upside-down frame-buffer (compared to
* OpenGL). If true, the render result should be flipped vertically for correct output.
- * \note: Only to be called after session start, may otherwise result in a false negative.
+ * \note Only to be called after session start, may otherwise result in a false negative.
*/
int GHOST_XrSessionNeedsUpsideDownDrawing(const GHOST_XrContextHandle xr_context);
diff --git a/intern/ghost/GHOST_ISystemPaths.h b/intern/ghost/GHOST_ISystemPaths.h
index b47d14984d8..e7ac752d322 100644
--- a/intern/ghost/GHOST_ISystemPaths.h
+++ b/intern/ghost/GHOST_ISystemPaths.h
@@ -78,6 +78,12 @@ class GHOST_ISystemPaths {
virtual const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const = 0;
/**
+ * Determine a special ("well known") and easy to reach user directory.
+ * \return Unsigned char string pointing to user dir (eg `~/Documents/`).
+ */
+ virtual const GHOST_TUns8 *getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const = 0;
+
+ /**
* Determine the directory of the current binary
* \return Unsigned char string pointing to the binary dir
*/
diff --git a/intern/ghost/GHOST_Path-api.h b/intern/ghost/GHOST_Path-api.h
index 4cc232be6b6..36ea70838ca 100644
--- a/intern/ghost/GHOST_Path-api.h
+++ b/intern/ghost/GHOST_Path-api.h
@@ -57,6 +57,12 @@ extern const GHOST_TUns8 *GHOST_getSystemDir(int version, const char *versionstr
extern const GHOST_TUns8 *GHOST_getUserDir(int version, const char *versionstr);
/**
+ * Determine a special ("well known") and easy to reach user directory.
+ * \return Unsigned char string pointing to user dir (eg `~/Documents/`).
+ */
+extern const GHOST_TUns8 *GHOST_getUserSpecialDir(GHOST_TUserSpecialDirTypes type);
+
+/**
* Determine the dir in which the binary file is found.
* \return Unsigned char string pointing to binary dir (eg ~/usr/local/bin/).
*/
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index a03b59d14b0..8bce064ce63 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -565,6 +565,16 @@ typedef struct {
char is_repeat;
} GHOST_TEventKeyData;
+typedef enum {
+ GHOST_kUserSpecialDirDesktop,
+ GHOST_kUserSpecialDirDocuments,
+ GHOST_kUserSpecialDirDownloads,
+ GHOST_kUserSpecialDirMusic,
+ GHOST_kUserSpecialDirPictures,
+ GHOST_kUserSpecialDirVideos,
+ /* Can be extended as needed. */
+} GHOST_TUserSpecialDirTypes;
+
typedef struct {
/** Number of pixels on a line. */
GHOST_TUns32 xPixels;
diff --git a/intern/ghost/intern/GHOST_Path-api.cpp b/intern/ghost/intern/GHOST_Path-api.cpp
index df3592fb5e5..c82e9819f3c 100644
--- a/intern/ghost/intern/GHOST_Path-api.cpp
+++ b/intern/ghost/intern/GHOST_Path-api.cpp
@@ -50,6 +50,12 @@ const GHOST_TUns8 *GHOST_getUserDir(int version, const char *versionstr)
return systemPaths ? systemPaths->getUserDir(version, versionstr) : NULL; /* shouldn't be NULL */
}
+const GHOST_TUns8 *GHOST_getUserSpecialDir(GHOST_TUserSpecialDirTypes type)
+{
+ GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
+ return systemPaths ? systemPaths->getUserSpecialDir(type) : NULL; /* shouldn't be NULL */
+}
+
const GHOST_TUns8 *GHOST_getBinaryDir()
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index d5b8311349b..d7dbfbe8813 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -82,8 +82,8 @@ static GHOST_TButtonMask convertButton(int button)
/**
* Converts Mac rawkey codes (same for Cocoa & Carbon)
* into GHOST key codes
- * \param rawCode The raw physical key code
- * \param recvChar the character ignoring modifiers (except for shift)
+ * \param rawCode: The raw physical key code
+ * \param recvChar: the character ignoring modifiers (except for shift)
* \return Ghost key code
*/
static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
@@ -783,7 +783,7 @@ GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GLSettings glSet
/**
* Dispose of a context.
- * \param context Pointer to the context to be disposed.
+ * \param context: Pointer to the context to be disposed.
* \return Indication of success.
*/
GHOST_TSuccess GHOST_SystemCocoa::disposeContext(GHOST_IContext *context)
@@ -1730,13 +1730,14 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
}
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
+ NSPoint delta = [[cocoawindow contentView] convertPointToBacking:NSMakePoint(dx, dy)];
pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
window,
GHOST_kTrackpadEventScroll,
x,
y,
- dx,
- dy,
+ delta.x,
+ delta.y,
[event isDirectionInvertedFromDevice]));
}
} break;
diff --git a/intern/ghost/intern/GHOST_SystemPathsCocoa.h b/intern/ghost/intern/GHOST_SystemPathsCocoa.h
index 188f6f02286..14633d46f03 100644
--- a/intern/ghost/intern/GHOST_SystemPathsCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemPathsCocoa.h
@@ -56,6 +56,12 @@ class GHOST_SystemPathsCocoa : public GHOST_SystemPaths {
const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const;
/**
+ * Determine a special ("well known") and easy to reach user directory.
+ * \return Unsigned char string pointing to user dir (eg `~/Documents/`).
+ */
+ const GHOST_TUns8 *getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const;
+
+ /**
* Determine the directory of the current binary
* \return Unsigned char string pointing to the binary dir
*/
diff --git a/intern/ghost/intern/GHOST_SystemPathsCocoa.mm b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm
index 830d58ba42c..7c6184837bf 100644
--- a/intern/ghost/intern/GHOST_SystemPathsCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm
@@ -21,6 +21,7 @@
#import <Foundation/Foundation.h>
+#include "GHOST_Debug.h"
#include "GHOST_SystemPathsCocoa.h"
#pragma mark initialization/finalization
@@ -89,6 +90,57 @@ const GHOST_TUns8 *GHOST_SystemPathsCocoa::getUserDir(int, const char *versionst
return (GHOST_TUns8 *)tempPath;
}
+const GHOST_TUns8 *GHOST_SystemPathsCocoa::getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const
+{
+ static char tempPath[512] = "";
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSString *basePath;
+ NSArray *paths;
+ NSSearchPathDirectory ns_directory;
+
+ switch (type) {
+ case GHOST_kUserSpecialDirDesktop:
+ ns_directory = NSDesktopDirectory;
+ break;
+ case GHOST_kUserSpecialDirDocuments:
+ ns_directory = NSDocumentDirectory;
+ break;
+ case GHOST_kUserSpecialDirDownloads:
+ ns_directory = NSDownloadsDirectory;
+ break;
+ case GHOST_kUserSpecialDirMusic:
+ ns_directory = NSMusicDirectory;
+ break;
+ case GHOST_kUserSpecialDirPictures:
+ ns_directory = NSPicturesDirectory;
+ break;
+ case GHOST_kUserSpecialDirVideos:
+ ns_directory = NSMoviesDirectory;
+ break;
+ default:
+ GHOST_ASSERT(
+ false,
+ "GHOST_SystemPathsCocoa::getUserSpecialDir(): Invalid enum value for type parameter");
+ [pool drain];
+ return NULL;
+ }
+
+ paths = NSSearchPathForDirectoriesInDomains(ns_directory, NSUserDomainMask, YES);
+
+ if ([paths count] > 0)
+ basePath = [paths objectAtIndex:0];
+ else {
+ [pool drain];
+ return NULL;
+ }
+
+ strncpy(
+ (char *)tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding], sizeof(tempPath));
+
+ [pool drain];
+ return (GHOST_TUns8 *)tempPath;
+}
+
const GHOST_TUns8 *GHOST_SystemPathsCocoa::getBinaryDir() const
{
static GHOST_TUns8 tempPath[512] = "";
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
index ad3d490eb91..86f3a0a31fb 100644
--- a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
@@ -21,6 +21,9 @@
* \ingroup GHOST
*/
+#include <cstdio>
+#include <sstream>
+
#include "GHOST_SystemPathsUnix.h"
#include "GHOST_Debug.h"
@@ -108,6 +111,62 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserDir(int version, const char *ve
}
}
+const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const
+{
+ const char *type_str;
+
+ switch (type) {
+ case GHOST_kUserSpecialDirDesktop:
+ type_str = "DESKTOP";
+ break;
+ case GHOST_kUserSpecialDirDocuments:
+ type_str = "DOCUMENTS";
+ break;
+ case GHOST_kUserSpecialDirDownloads:
+ type_str = "DOWNLOAD";
+ break;
+ case GHOST_kUserSpecialDirMusic:
+ type_str = "MUSIC";
+ break;
+ case GHOST_kUserSpecialDirPictures:
+ type_str = "PICTURES";
+ break;
+ case GHOST_kUserSpecialDirVideos:
+ type_str = "VIDEOS";
+ break;
+ default:
+ GHOST_ASSERT(
+ false,
+ "GHOST_SystemPathsUnix::getUserSpecialDir(): Invalid enum value for type parameter");
+ return NULL;
+ }
+
+ static string path = "";
+ /* Pipe stderr to /dev/null to avoid error prints. We will fail gracefully still. */
+ string command = string("xdg-user-dir ") + type_str + " 2> /dev/null";
+
+ FILE *fstream = popen(command.c_str(), "r");
+ if (fstream == NULL) {
+ return NULL;
+ }
+ std::stringstream path_stream;
+ while (!feof(fstream)) {
+ char c = fgetc(fstream);
+ /* xdg-user-dir ends the path with '\n'. */
+ if (c == '\n') {
+ break;
+ }
+ path_stream << c;
+ }
+ if (pclose(fstream) == -1) {
+ perror("GHOST_SystemPathsUnix::getUserSpecialDir failed at pclose()");
+ return NULL;
+ }
+
+ path = path_stream.str();
+ return path[0] ? (const GHOST_TUns8 *)path.c_str() : NULL;
+}
+
const GHOST_TUns8 *GHOST_SystemPathsUnix::getBinaryDir() const
{
return NULL;
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.h b/intern/ghost/intern/GHOST_SystemPathsUnix.h
index 8d2f26a28aa..bc9272ecd8f 100644
--- a/intern/ghost/intern/GHOST_SystemPathsUnix.h
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.h
@@ -54,6 +54,12 @@ class GHOST_SystemPathsUnix : public GHOST_SystemPaths {
const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const;
/**
+ * Determine a special ("well known") and easy to reach user directory.
+ * \return Unsigned char string pointing to user dir (eg `~/Documents/`).
+ */
+ const GHOST_TUns8 *getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const;
+
+ /**
* Determine the directory of the current binary
* \return Unsigned char string pointing to the binary dir
*/
diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
index 673cbcad97e..193633b5c3e 100644
--- a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
@@ -22,6 +22,7 @@
*/
#include "GHOST_SystemPathsWin32.h"
+#include "GHOST_Debug.h"
#ifndef _WIN32_IE
# define _WIN32_IE 0x0501
@@ -76,6 +77,50 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getUserDir(int, const char *versionst
return NULL;
}
+const GHOST_TUns8 *GHOST_SystemPathsWin32::getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const
+{
+ GUID folderid;
+
+ switch (type) {
+ case GHOST_kUserSpecialDirDesktop:
+ folderid = FOLDERID_Desktop;
+ break;
+ case GHOST_kUserSpecialDirDocuments:
+ folderid = FOLDERID_Documents;
+ break;
+ case GHOST_kUserSpecialDirDownloads:
+ folderid = FOLDERID_Downloads;
+ break;
+ case GHOST_kUserSpecialDirMusic:
+ folderid = FOLDERID_Music;
+ break;
+ case GHOST_kUserSpecialDirPictures:
+ folderid = FOLDERID_Pictures;
+ break;
+ case GHOST_kUserSpecialDirVideos:
+ folderid = FOLDERID_Videos;
+ break;
+ default:
+ GHOST_ASSERT(
+ false,
+ "GHOST_SystemPathsWin32::getUserSpecialDir(): Invalid enum value for type parameter");
+ return NULL;
+ }
+
+ static char knownpath[MAX_PATH * 3] = {0};
+ PWSTR knownpath_16 = NULL;
+ HRESULT hResult = SHGetKnownFolderPath(folderid, KF_FLAG_DEFAULT, NULL, &knownpath_16);
+
+ if (hResult == S_OK) {
+ conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3);
+ CoTaskMemFree(knownpath_16);
+ return (GHOST_TUns8 *)knownpath;
+ }
+
+ CoTaskMemFree(knownpath_16);
+ return NULL;
+}
+
const GHOST_TUns8 *GHOST_SystemPathsWin32::getBinaryDir() const
{
static char fullname[MAX_PATH * 3] = {0};
diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.h b/intern/ghost/intern/GHOST_SystemPathsWin32.h
index 1a1eab21bad..45e03e744a5 100644
--- a/intern/ghost/intern/GHOST_SystemPathsWin32.h
+++ b/intern/ghost/intern/GHOST_SystemPathsWin32.h
@@ -63,6 +63,12 @@ class GHOST_SystemPathsWin32 : public GHOST_SystemPaths {
const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const;
/**
+ * Determine a special ("well known") and easy to reach user directory.
+ * \return Unsigned char string pointing to user dir (eg `~/Documents/`).
+ */
+ const GHOST_TUns8 *getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const;
+
+ /**
* Determine the directory of the current binary
* \return Unsigned char string pointing to the binary dir
*/
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 8178b9bdf1e..2bf1d0c2d35 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -422,7 +422,7 @@ finished:
/**
* Dispose of a context.
- * \param context Pointer to the context to be disposed.
+ * \param context: Pointer to the context to be disposed.
* \return Indication of success.
*/
GHOST_TSuccess GHOST_SystemWin32::disposeContext(GHOST_IContext *context)
@@ -1614,7 +1614,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
break;
}
case WT_PACKET:
- window->updatePendingWintabEvents();
+ window->updateWintabEventsSyncTime();
break;
////////////////////////////////////////////////////////////////////////
// Pointer events, processed
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index fe65162d168..1e1d0814d3a 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -407,7 +407,7 @@ void GHOST_WindowWayland::setOpaque() const
#endif
/**
- * \param type The type of rendering context create.
+ * \param type: The type of rendering context create.
* \return Indication of success.
*/
GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType type)
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index af02663985d..a4cbf66b22d 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -1292,7 +1292,7 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin3
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
- updatePendingWintabEvents();
+ updateWintabEvents();
auto &pendingEvents = m_wintab.pendingEvents;
size_t pendingEventSize = pendingEvents.size();
@@ -1388,6 +1388,44 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin3
return GHOST_kSuccess;
}
+void GHOST_WindowWin32::updateWintabEvents()
+{
+ readWintabEvents();
+ // When a Wintab device is used to leave window focus, some of it's packets are periodically not
+ // queued in time to be flushed. Reading packets needs to occur before expiring packets to clear
+ // these from the queue.
+ expireWintabEvents();
+}
+
+void GHOST_WindowWin32::updateWintabEventsSyncTime()
+{
+ readWintabEvents();
+
+ if (!m_wintab.pendingEvents.empty()) {
+ auto lastEvent = m_wintab.pendingEvents.back();
+ m_wintab.sysTimeOffset = ::GetTickCount() - lastEvent.pkTime;
+ }
+
+ expireWintabEvents();
+}
+
+void GHOST_WindowWin32::readWintabEvents()
+{
+ if (!(m_wintab.packetsGet && m_wintab.context)) {
+ return;
+ }
+
+ auto &pendingEvents = m_wintab.pendingEvents;
+
+ /* Get new packets. */
+ const int numPackets = m_wintab.packetsGet(
+ m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
+
+ for (int i = 0; i < numPackets; i++) {
+ pendingEvents.push(m_wintab.pkts[i]);
+ }
+}
+
/* Wintab (per documentation but may vary with implementation) does not update when its event
* buffer is full. This is an issue because we need some synchronization point between Wintab
* events and Win32 events, so we can't drain and process the queue immediately. We need to
@@ -1396,17 +1434,12 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin3
* mode from the Wintab API alone. There is no guaranteed ordering between Wintab and Win32 mouse
* events and no documented time stamp shared between the two, so we synchronize on mouse button
* events. */
-void GHOST_WindowWin32::updatePendingWintabEvents()
+void GHOST_WindowWin32::expireWintabEvents()
{
- if (!(m_wintab.packetsGet && m_wintab.context)) {
- return;
- }
-
auto &pendingEvents = m_wintab.pendingEvents;
- /* Clear outdated events from queue. */
- DWORD currTime = ::GetTickCount();
- DWORD millisTimeout = 500;
+ DWORD currTime = ::GetTickCount() - m_wintab.sysTimeOffset;
+ DWORD millisTimeout = 300;
while (!pendingEvents.empty()) {
DWORD pkTime = pendingEvents.front().pkTime;
@@ -1417,24 +1450,6 @@ void GHOST_WindowWin32::updatePendingWintabEvents()
break;
}
}
-
- /* Get new packets. */
- const int numPackets = m_wintab.packetsGet(
- m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
-
- int i = 0;
- /* Don't queue outdated packets, such events can include packets that occurred before the current
- * window lost and regained focus. */
- for (; i < numPackets; i++) {
- DWORD pkTime = m_wintab.pkts[i].pkTime;
-
- if (currTime < pkTime + millisTimeout) {
- break;
- }
- }
- for (; i < numPackets; i++) {
- pendingEvents.push(m_wintab.pkts[i]);
- }
}
GHOST_TUns16 GHOST_WindowWin32::getDPIHint()
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index a761d7d84dc..829bbdea051 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -486,9 +486,14 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TSuccess getWintabInfo(std::vector<GHOST_WintabInfoWin32> &outWintabInfo);
/**
- * Updates stored pending Wintab events.
+ * Updates pending Wintab events and syncs Wintab time with OS time.
*/
- void updatePendingWintabEvents();
+ void updateWintabEventsSyncTime();
+
+ /**
+ * Updates pending Wintab events.
+ */
+ void updateWintabEvents();
GHOST_TSuccess beginFullScreen() const
{
@@ -629,6 +634,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TUns8 numSysButtons = 0;
/** Cursors currently in contact mapped to system buttons */
DWORD sysButtonsPressed = 0;
+ DWORD sysTimeOffset = 0;
LONG maxPressure = 0;
LONG maxAzimuth = 0, maxAltitude = 0;
/** Reusable buffer to read in Wintab Packets. */
@@ -642,6 +648,10 @@ class GHOST_WindowWin32 : public GHOST_Window {
*/
void initializeWintab();
+ void readWintabEvents();
+
+ void expireWintabEvents();
+
/**
* Convert Wintab system mapped (mouse) buttons into Ghost button mask.
* \param cursor: The Wintab cursor associated to the button.