From 166c0db3f9412925b501b7172875cb8ee2eb6958 Mon Sep 17 00:00:00 2001 From: Patrick Mours Date: Tue, 5 Jan 2021 14:39:29 +0100 Subject: [PATCH] Fix T83915: Subdivision Surface modifier causes visual artifacts in Cycles rendered viewport - CPU and OptiX Changing the geometry in the current scene caused the primitive offsets for all geometry to change, but the values would not be updated in all bottom-level BVH structures. Rendering artifacts and crashes where the result. This fixes that by ensuring all BVH structures are updated when the primitive offsets change. --- intern/cycles/bvh/bvh_embree.cpp | 2 ++ intern/cycles/render/geometry.cpp | 25 +++++++++++++++++++++---- intern/cycles/render/geometry.h | 4 +++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp index b874bda7186..c082478e5b1 100644 --- a/intern/cycles/bvh/bvh_embree.cpp +++ b/intern/cycles/bvh/bvh_embree.cpp @@ -682,6 +682,7 @@ void BVHEmbree::refit(Progress &progress) if (mesh->num_triangles() > 0) { RTCGeometry geom = rtcGetGeometry(scene, geom_id); set_tri_vertex_buffer(geom, mesh, true); + rtcSetGeometryUserData(geom, (void *)mesh->optix_prim_offset); rtcCommitGeometry(geom); } } @@ -690,6 +691,7 @@ void BVHEmbree::refit(Progress &progress) if (hair->num_curves() > 0) { RTCGeometry geom = rtcGetGeometry(scene, geom_id + 1); set_curve_vertex_buffer(geom, hair, true); + rtcSetGeometryUserData(geom, (void *)hair->optix_prim_offset); rtcCommitGeometry(geom); } } diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 64b98a91853..6fc217f2d76 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -280,6 +280,15 @@ void Geometry::tag_update(Scene *scene, bool rebuild) scene->object_manager->need_update = true; } +void Geometry::tag_bvh_update(bool rebuild) +{ + tag_modified(); + + if (rebuild) { + need_update_rebuild = true; + } +} + /* Geometry Manager */ GeometryManager::GeometryManager() @@ -915,7 +924,7 @@ void GeometryManager::device_update_attributes(Device *device, scene->object_manager->device_update_mesh_offsets(device, dscene, scene); } -void GeometryManager::mesh_calc_offset(Scene *scene) +void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout) { size_t vert_size = 0; size_t tri_size = 0; @@ -930,6 +939,14 @@ void GeometryManager::mesh_calc_offset(Scene *scene) size_t optix_prim_size = 0; foreach (Geometry *geom, scene->geometry) { + if (geom->optix_prim_offset != optix_prim_size) { + /* Need to rebuild BVH in OptiX, since refit only allows modified mesh data there */ + const bool has_optix_bvh = bvh_layout == BVH_LAYOUT_OPTIX || + bvh_layout == BVH_LAYOUT_MULTI_OPTIX || + bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE; + geom->tag_bvh_update(has_optix_bvh); + } + if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { Mesh *mesh = static_cast(geom); @@ -1526,7 +1543,9 @@ void GeometryManager::device_update(Device *device, /* Device update. */ device_free(device, dscene); - mesh_calc_offset(scene); + const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, + device->get_bvh_layout_mask()); + mesh_calc_offset(scene, bvh_layout); if (true_displacement_used) { scoped_callback_timer timer([scene](double time) { if (scene->update_stats) { @@ -1553,8 +1572,6 @@ void GeometryManager::device_update(Device *device, } /* Update displacement. */ - BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, - device->get_bvh_layout_mask()); bool displacement_done = false; size_t num_bvh = 0; diff --git a/intern/cycles/render/geometry.h b/intern/cycles/render/geometry.h index d3daf0cc809..b124e950ad2 100644 --- a/intern/cycles/render/geometry.h +++ b/intern/cycles/render/geometry.h @@ -157,6 +157,8 @@ class Geometry : public Node { /* Updates */ void tag_update(Scene *scene, bool rebuild); + + void tag_bvh_update(bool rebuild); }; /* Geometry Manager */ @@ -198,7 +200,7 @@ class GeometryManager { vector &object_attributes); /* Compute verts/triangles/curves offsets in global arrays. */ - void mesh_calc_offset(Scene *scene); + void mesh_calc_offset(Scene *scene, BVHLayout bvh_layout); void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);