Fix #121761: Crash when compositing while rendering
Blender crashes when the interactive GPU compositor is running in a node editor while rendering. This is because the GPU compositor is sharing the same GPU context used for rendering, which is not allowed. To fix this, we use a dedicated render list for interactive compositing, to use its dedicated GPU context. This is implemented by keeping another render list for the purpose of compositing and similarly clearing its context when it is no longer needed. Pull Request: https://projects.blender.org/blender/blender/pulls/122472
This commit is contained in:
@@ -252,8 +252,8 @@ static void compo_initjob(void *cjv)
|
||||
compo_tag_output_nodes(cj->localtree, cj->recalc_flags);
|
||||
}
|
||||
|
||||
cj->re = RE_NewSceneRender(scene);
|
||||
if (scene->r.compositor_device == SCE_COMPOSITOR_DEVICE_GPU) {
|
||||
cj->re = RE_NewInteractiveCompositorRender(scene);
|
||||
RE_system_gpu_context_ensure(cj->re);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,11 @@ struct Render *RE_GetSceneRender(const struct Scene *scene);
|
||||
struct RenderEngineType;
|
||||
struct ViewRender *RE_NewViewRender(struct RenderEngineType *engine_type);
|
||||
|
||||
/* Creates a new render for interactive compositing of the given scene. If an existing render
|
||||
* exists for the given scene, it is returned instead. See interactive_compositor_renders in
|
||||
* RenderGlobal for more information. */
|
||||
struct Render *RE_NewInteractiveCompositorRender(const struct Scene *scene);
|
||||
|
||||
/* Assign default dummy callbacks. */
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_threads.h"
|
||||
@@ -129,6 +130,12 @@
|
||||
/* here we store all renders */
|
||||
static struct {
|
||||
std::forward_list<Render *> render_list;
|
||||
/* Special renders that can be used for interactive compositing, each scene has its own render,
|
||||
* keyed with the scene name returned from scene_render_name_get and matches the same name in
|
||||
* render_list. Those renders are separate from standard renders because the GPU context can't be
|
||||
* bound for compositing and rendering at the same time, so those renders are essentially used to
|
||||
* get a persistent dedicated GPU context to interactive compositor execution. */
|
||||
blender::Map<std::string, Render *> interactive_compositor_renders;
|
||||
} RenderGlobal;
|
||||
|
||||
/** \} */
|
||||
@@ -553,6 +560,19 @@ Render *RE_NewSceneRender(const Scene *scene)
|
||||
return RE_NewRender(render_name);
|
||||
}
|
||||
|
||||
Render *RE_NewInteractiveCompositorRender(const Scene *scene)
|
||||
{
|
||||
char render_name[MAX_SCENE_RENDER_NAME];
|
||||
scene_render_name_get(scene, sizeof(render_name), render_name);
|
||||
|
||||
return RenderGlobal.interactive_compositor_renders.lookup_or_add_cb(render_name, [&]() {
|
||||
Render *render = MEM_new<Render>("New Interactive Compositor Render");
|
||||
STRNCPY(render->name, render_name);
|
||||
RE_InitRenderCB(render);
|
||||
return render;
|
||||
});
|
||||
}
|
||||
|
||||
void RE_InitRenderCB(Render *re)
|
||||
{
|
||||
/* set default empty callbacks */
|
||||
@@ -592,6 +612,11 @@ void RE_FreeAllRender()
|
||||
RE_FreeRender(static_cast<Render *>(RenderGlobal.render_list.front()));
|
||||
}
|
||||
|
||||
for (Render *render : RenderGlobal.interactive_compositor_renders.values()) {
|
||||
RE_FreeRender(render);
|
||||
}
|
||||
RenderGlobal.interactive_compositor_renders.clear();
|
||||
|
||||
#ifdef WITH_FREESTYLE
|
||||
/* finalize Freestyle */
|
||||
FRS_exit();
|
||||
@@ -702,6 +727,16 @@ void RE_FreeUnusedGPUResources()
|
||||
re_gpu_texture_caches_free(re);
|
||||
RE_blender_gpu_context_free(re);
|
||||
RE_system_gpu_context_free(re);
|
||||
|
||||
/* We also free the resources from the interactive compositor render of the scene if one
|
||||
* exists. */
|
||||
Render *interactive_compositor_render =
|
||||
RenderGlobal.interactive_compositor_renders.lookup_default(re->name, nullptr);
|
||||
if (interactive_compositor_render) {
|
||||
re_gpu_texture_caches_free(interactive_compositor_render);
|
||||
RE_blender_gpu_context_free(interactive_compositor_render);
|
||||
RE_system_gpu_context_free(interactive_compositor_render);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user