diff --git a/intern/cycles/blender/session.cpp b/intern/cycles/blender/session.cpp index c81a0f4edb2..405f22ad67a 100644 --- a/intern/cycles/blender/session.cpp +++ b/intern/cycles/blender/session.cpp @@ -506,8 +506,13 @@ void BlenderSession::render_frame_finish() session->set_output_driver(nullptr); session->full_buffer_written_cb = function_null; - /* The display driver holds OpenGL resources which belong to an OpenGL context held by the render - * engine on Blender side. Force destruction of those resources. */ + /* The display driver is the source of drawing context for both drawing and possible graphics + * interop objects in the path trace. Once the frame is finished the OpenGL context might be + * freed form Blender side. Need to ensure that all GPU resources are freed prior to that + * point. + * Ideally would only do this when OpenGL context is actually destroyed, but there is no way to + * know when this happens (at least in the code at the time when this comment was written). + * The penalty of re-creating resources on every frame is unlikely to be noticed. */ display_driver_ = nullptr; session->set_display_driver(nullptr); diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp index fd697836f52..d8ee1883a06 100644 --- a/intern/cycles/integrator/path_trace.cpp +++ b/intern/cycles/integrator/path_trace.cpp @@ -67,14 +67,7 @@ PathTrace::PathTrace(Device *device, PathTrace::~PathTrace() { - /* Destroy any GPU resource which was used for graphics interop. - * Need to have access to the PathTraceDisplay as it is the only source of drawing context which - * is used for interop. */ - if (display_) { - for (auto &&path_trace_work : path_trace_works_) { - path_trace_work->destroy_gpu_resources(display_.get()); - } - } + destroy_gpu_resources(); } void PathTrace::load_kernels() @@ -572,6 +565,11 @@ void PathTrace::set_output_driver(unique_ptr driver) void PathTrace::set_display_driver(unique_ptr driver) { + /* The display driver is the source of the drawing context which might be used by + * path trace works. Make sure there is no graphics interop using resources from + * the old display, as it might no longer be available after this call. */ + destroy_gpu_resources(); + if (driver) { display_ = make_unique(move(driver)); } @@ -1088,6 +1086,18 @@ bool PathTrace::has_denoised_result() const return render_state_.has_denoised_result; } +void PathTrace::destroy_gpu_resources() +{ + /* Destroy any GPU resource which was used for graphics interop. + * Need to have access to the PathTraceDisplay as it is the only source of drawing context which + * is used for interop. */ + if (display_) { + for (auto &&path_trace_work : path_trace_works_) { + path_trace_work->destroy_gpu_resources(display_.get()); + } + } +} + /* -------------------------------------------------------------------- * Report generation. */ diff --git a/intern/cycles/integrator/path_trace.h b/intern/cycles/integrator/path_trace.h index bb41c8c3210..7849d69b646 100644 --- a/intern/cycles/integrator/path_trace.h +++ b/intern/cycles/integrator/path_trace.h @@ -239,6 +239,9 @@ class PathTrace { void progress_set_status(const string &status, const string &substatus = ""); + /* Destroy GPU resources (such as graphics interop) used by work. */ + void destroy_gpu_resources(); + /* Pointer to a device which is configured to be used for path tracing. If multiple devices * are configured this is a `MultiDevice`. */ Device *device_ = nullptr;