Cycles: Separate Embree device for each CPU Device.

Before, Cycles was using a shared Embree device across all instances.
This could result in crashes when viewport rendering and material
preview were using Cycles simultaneously.

Fixes issue T80042

Maniphest Tasks: T80042

Differential Revision: https://developer.blender.org/D8772
This commit is contained in:
Stefan Werner 2020-09-01 14:47:34 +02:00 committed by Jeroen Bakker
parent 41e4079365
commit 918ef5f835
Notes: blender-bot 2023-04-19 22:54:54 +02:00
Referenced by issue #80042, Crash switching to material preview due to incorrect free with Cycles
7 changed files with 50 additions and 68 deletions

View File

@ -98,14 +98,15 @@ BVH::BVH(const BVHParams &params_,
BVH *BVH::create(const BVHParams &params,
const vector<Geometry *> &geometry,
const vector<Object *> &objects)
const vector<Object *> &objects,
const 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);
return new BVHEmbree(params, geometry, objects, device);
#else
break;
#endif

View File

@ -89,7 +89,8 @@ class BVH {
static BVH *create(const BVHParams &params,
const vector<Geometry *> &geometry,
const vector<Object *> &objects);
const vector<Object *> &objects,
const Device *device);
virtual ~BVH()
{
}

View File

@ -36,6 +36,8 @@
# include "bvh/bvh_embree.h"
# include "device/device.h"
/* Kernel includes are necessary so that the filter function for Embree can access the packed BVH.
*/
# include "kernel/bvh/bvh_embree.h"
@ -298,12 +300,6 @@ static bool rtc_progress_func(void *user_ptr, const double n)
return !progress->get_cancel();
}
/* This is to have a shared device between all BVH instances.
It would be useful to actually to use a separte RTCDevice per Cycles instance. */
RTCDevice BVHEmbree::rtc_shared_device = NULL;
int BVHEmbree::rtc_shared_users = 0;
thread_mutex BVHEmbree::rtc_shared_mutex;
static size_t count_primitives(Geometry *geom)
{
if (geom->type == Geometry::MESH) {
@ -320,11 +316,13 @@ static size_t count_primitives(Geometry *geom)
BVHEmbree::BVHEmbree(const BVHParams &params_,
const vector<Geometry *> &geometry_,
const vector<Object *> &objects_)
const vector<Object *> &objects_,
const Device *device)
: 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),
@ -332,47 +330,8 @@ BVHEmbree::BVHEmbree(const BVHParams &params_,
{
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
thread_scoped_lock lock(rtc_shared_mutex);
if (rtc_shared_users == 0) {
rtc_shared_device = rtcNewDevice("verbose=0");
/* Check here if Embree was built with the correct flags. */
ssize_t ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED);
if (ret != 1) {
assert(0);
VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED flag."
"Ray visibility will not work.";
}
ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED);
if (ret != 1) {
assert(0);
VLOG(1)
<< "Embree is compiled without the RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED flag."
"Renders may not look as expected.";
}
ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED);
if (ret != 1) {
assert(0);
VLOG(1)
<< "Embree is compiled without the RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED flag. "
"Line primitives will not be rendered.";
}
ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED);
if (ret != 1) {
assert(0);
VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED "
"flag. "
"Triangle primitives will not be rendered.";
}
ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED);
if (ret != 0) {
assert(0);
VLOG(1) << "Embree is compiled with the RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED flag. "
"Renders may not look as expected.";
}
}
++rtc_shared_users;
rtcSetDeviceErrorFunction(rtc_shared_device, rtc_error_func, NULL);
rtcSetDeviceErrorFunction(rtc_device, rtc_error_func, NULL);
pack.root_index = -1;
}
@ -390,12 +349,6 @@ void BVHEmbree::destroy(RTCScene scene)
rtcReleaseScene(scene);
scene = NULL;
}
thread_scoped_lock lock(rtc_shared_mutex);
--rtc_shared_users;
if (rtc_shared_users == 0) {
rtcReleaseDevice(rtc_shared_device);
rtc_shared_device = NULL;
}
}
void BVHEmbree::delete_rtcScene()
@ -421,9 +374,9 @@ void BVHEmbree::delete_rtcScene()
void BVHEmbree::build(Progress &progress, Stats *stats_)
{
assert(rtc_shared_device);
assert(rtc_device);
stats = stats_;
rtcSetDeviceMemoryMonitorFunction(rtc_shared_device, rtc_memory_monitor_func, stats);
rtcSetDeviceMemoryMonitorFunction(rtc_device, rtc_memory_monitor_func, stats);
progress.set_substatus("Building BVH");
@ -434,7 +387,7 @@ void BVHEmbree::build(Progress &progress, Stats *stats_)
const bool dynamic = params.bvh_type == SceneParams::BVH_DYNAMIC;
scene = rtcNewScene(rtc_shared_device);
scene = rtcNewScene(rtc_device);
const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
RTC_SCENE_FLAG_COMPACT | RTC_SCENE_FLAG_ROBUST;
rtcSetSceneFlags(scene, scene_flags);
@ -561,7 +514,7 @@ void BVHEmbree::add_instance(Object *ob, int i)
const size_t num_motion_steps = min(num_object_motion_steps, RTC_MAX_TIME_STEP_COUNT);
assert(num_object_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_INSTANCE);
RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_INSTANCE);
rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
@ -615,7 +568,7 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
assert(num_geometry_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
const size_t num_triangles = mesh->num_triangles();
RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_TRIANGLE);
RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_TRIANGLE);
rtcSetGeometryBuildQuality(geom_id, build_quality);
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
@ -804,7 +757,7 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE :
RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE);
RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, type);
RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
rtcSetGeometryTessellationRate(geom_id, curve_subdivisions + 1);
unsigned *rtc_indices = (unsigned *)rtcSetNewGeometryBuffer(
geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof(int), num_segments);

View File

@ -50,7 +50,8 @@ class BVHEmbree : public BVH {
friend class BVH;
BVHEmbree(const BVHParams &params,
const vector<Geometry *> &geometry,
const vector<Object *> &objects);
const vector<Object *> &objects,
const Device *device);
virtual void pack_nodes(const BVHNode *) override;
virtual void refit_nodes() override;
@ -73,9 +74,7 @@ class BVHEmbree : public BVH {
void update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh);
void update_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair);
static RTCDevice rtc_shared_device;
static int rtc_shared_users;
static thread_mutex rtc_shared_mutex;
RTCDevice rtc_device;
Stats *stats;
vector<RTCScene> delayed_delete_scenes;

View File

@ -373,6 +373,12 @@ 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*/)
{

View File

@ -24,6 +24,10 @@
# include <OSL/oslexec.h>
#endif
#ifdef WITH_EMBREE
# include <embree3/rtcore.h>
#endif
#include "device/device.h"
#include "device/device_denoising.h"
#include "device/device_intern.h"
@ -183,6 +187,9 @@ class CPUDevice : public Device {
oidn::FilterRef oidn_filter;
#endif
thread_spin_lock oidn_task_lock;
#ifdef WITH_EMBREE
RTCDevice embree_device;
#endif
bool use_split_kernel;
@ -301,6 +308,9 @@ class CPUDevice : public Device {
#ifdef WITH_OSL
kernel_globals.osl = &osl_globals;
#endif
#ifdef WITH_EMBREE
embree_device = rtcNewDevice("verbose=0");
#endif
use_split_kernel = DebugFlags().cpu.split_kernel;
if (use_split_kernel) {
@ -339,6 +349,9 @@ class CPUDevice : public Device {
~CPUDevice()
{
#ifdef WITH_EMBREE
rtcReleaseDevice(embree_device);
#endif
task_pool.cancel();
texture_info.free();
}
@ -523,6 +536,15 @@ class CPUDevice : public Device {
#endif
}
void *bvh_device() const override
{
#ifdef WITH_EMBREE
return embree_device;
#else
return NULL;
#endif
}
void thread_run(DeviceTask &task)
{
if (task.type == DeviceTask::RENDER)

View File

@ -214,7 +214,7 @@ void Geometry::compute_bvh(
bparams.curve_subdivisions = params->curve_subdivisions();
delete bvh;
bvh = BVH::create(bparams, geometry, objects);
bvh = BVH::create(bparams, geometry, objects, device);
MEM_GUARDED_CALL(progress, bvh->build, *progress);
}
}
@ -1029,7 +1029,7 @@ 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);
BVH *bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
bvh->build(progress, &device->stats);
if (progress.get_cancel()) {