Fix virtual camera-related crashes due to failed assert

See comment on https://developer.blender.org/D16366.

When browsing materials, showing material properties, or changing
camera settings for the virtual camera, Blender would crash due to a
failed assert in gpu_offscreen_fb_get() (gpu_framebuffer.cc L602),
where the framebuffer list for the virtual camera offscreen would
appear to contain corrupted data.

This was likely caused by the pointer to the virtual camera offscreen
(stored as camera->runtime.virtual_monitor_offscreen) being shared
among src and dst camera data-blocks in camera_copy_data(), which is
called from depsgraph copy-on-write (when showing material properties,
changing camera settings, etc.). This should probably not be the case,
as if one data-block is freed (freeing the runtime data), then the
other will have a dangling pointer to the offscreen.

As a tentative solution, free the runtime data for the dst camera in
camera_copy_data() to prevent sharing virtual monitor offscreens across
cameras. In this way, no two virtual camera data-blocks should share
the same offscreen pointer and a new offscreen will be created for the
dst camera if necessary in view3d_virtual_camera_update().
This commit is contained in:
Peter Kim 2022-12-12 21:25:43 +09:00
parent 3e725b55cf
commit 786aad68b2
1 changed files with 18 additions and 11 deletions

View File

@ -59,6 +59,20 @@ static void camera_init_data(ID *id)
MEMCPY_STRUCT_AFTER(cam, DNA_struct_default_get(Camera), id);
}
/** Free (or release) any data used by this camera (does not free the camera itself). */
static void camera_free_runtime_data(Camera *cam, const Camera *cam_src)
{
if (cam->runtime.virtual_monitor_offscreen) {
if (!cam_src ||
(cam_src->runtime.virtual_monitor_offscreen != cam->runtime.virtual_monitor_offscreen)) {
GPU_offscreen_free(cam->runtime.virtual_monitor_offscreen);
}
cam->runtime.virtual_monitor_offscreen = NULL;
}
/* GPU texture is owned by the GPUOffscreen instance. */
cam->runtime.offscreen_color_texture = NULL;
}
/**
* Only copy internal data of Camera ID from source
* to already allocated/initialized destination.
@ -82,24 +96,17 @@ static void camera_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src,
CameraBGImage *bgpic_dst = BKE_camera_background_image_copy(bgpic_src, flag_subdata);
BLI_addtail(&cam_dst->bg_images, bgpic_dst);
}
}
/** Free (or release) any data used by this camera (does not free the camera itself). */
static void camera_free_runtime_data(Camera *camera)
{
if (camera->runtime.virtual_monitor_offscreen) {
GPU_offscreen_free(camera->runtime.virtual_monitor_offscreen);
camera->runtime.virtual_monitor_offscreen = NULL;
}
/* GPU texture is owned by the GPUOffscreen instance. */
camera->runtime.offscreen_color_texture = NULL;
/* Free runtime data to prevent virtual monitor offscreen from being shared across data-blocks.
*/
camera_free_runtime_data(cam_dst, cam_src);
}
static void camera_free_data(ID *id)
{
Camera *cam = (Camera *)id;
BLI_freelistN(&cam->bg_images);
camera_free_runtime_data(cam);
camera_free_runtime_data(cam, NULL);
}
static void camera_foreach_id(ID *id, LibraryForeachIDData *data)