From cfca7ac952022834bc99696b998df3a4960c0b4e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 7 Feb 2025 21:23:48 +0100 Subject: [PATCH] Fix #133943: Unnecessary image full update mark on file open This would be done when the frame, layer, pass or view changes compared to the previous value. But for cases like old files without these members or loading the image datablock into a different scene, this considered the image to be always be changed on file load. Now always reset this state on file load, and don't consider the initial state as an image update. This could also happen in the middle of GPU rendering, causing the GPU texture to be freed while still in use. Pull Request: https://projects.blender.org/blender/blender/pulls/134198 --- source/blender/blenkernel/intern/image.cc | 22 ++++++++++++++----- source/blender/blenkernel/intern/image_gpu.cc | 7 +++--- source/blender/makesdna/DNA_image_defaults.h | 7 +++--- source/blender/makesdna/DNA_image_types.h | 6 +++++ 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index c2a085e4c67..b0c4cc1eab1 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -49,6 +49,7 @@ #include "DNA_brush_types.h" #include "DNA_camera_types.h" #include "DNA_defaults.h" +#include "DNA_image_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" @@ -156,6 +157,16 @@ static void image_runtime_free_data(Image *image) BKE_image_partial_update_register_free(image); } +static void image_gpu_runtime_reset(Image *ima) +{ + ima->lastused = 0; + ima->gpuflag = 0; + ima->gpuframenr = IMAGE_GPU_FRAME_NONE; + ima->gpu_pass = IMAGE_GPU_PASS_NONE; + ima->gpu_layer = IMAGE_GPU_LAYER_NONE; + ima->gpu_view = IMAGE_GPU_VIEW_NONE; +} + static void image_init_data(ID *id) { Image *image = (Image *)id; @@ -348,9 +359,8 @@ static void image_blend_write(BlendWriter *writer, ID *id, const void *id_addres /* Clear all data that isn't read to reduce false detection of changed image during memfile undo. */ - ima->lastused = 0; ima->cache = nullptr; - ima->gpuflag = 0; + image_gpu_runtime_reset(ima); BLI_listbase_clear(&ima->anims); ima->runtime.partial_update_register = nullptr; ima->runtime.partial_update_user = nullptr; @@ -433,9 +443,7 @@ static void image_blend_read_data(BlendDataReader *reader, ID *id) BKE_previewimg_blend_read(reader, ima->preview); BLO_read_struct(reader, Stereo3dFormat, &ima->stereo3d_format); - ima->lastused = 0; - ima->gpuflag = 0; - + image_gpu_runtime_reset(ima); image_runtime_reset(ima); } @@ -5224,7 +5232,9 @@ void BKE_image_user_frame_calc(Image *ima, ImageUser *iuser, int cfra) /* NOTE: a single texture and refresh doesn't really work when * multiple image users may use different frames, this is to * be improved with perhaps a GPU texture cache. */ - BKE_image_partial_update_mark_full_update(ima); + if (ima->gpuframenr != IMAGE_GPU_FRAME_NONE) { + BKE_image_partial_update_mark_full_update(ima); + } ima->gpuframenr = iuser->framenr; } diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc index 9ea33c1dc76..ebfcf96320b 100644 --- a/source/blender/blenkernel/intern/image_gpu.cc +++ b/source/blender/blenkernel/intern/image_gpu.cc @@ -335,7 +335,7 @@ static void image_gpu_texture_try_partial_update(Image *image, ImageUser *iuser) } } -void BKE_image_ensure_gpu_texture(Image *image, ImageUser *image_user) +void BKE_image_ensure_gpu_texture(Image *image, ImageUser *iuser) { if (!image) { return; @@ -343,8 +343,9 @@ void BKE_image_ensure_gpu_texture(Image *image, ImageUser *image_user) /* Note that the image can cache both stereo views, so we only invalidate the cache if the view * index is more than 2. */ - if (image->gpu_pass != image_user->pass || image->gpu_layer != image_user->layer || - (image->gpu_view != image_user->multi_index && image_user->multi_index >= 2)) + if (!ELEM(image->gpu_pass, IMAGE_GPU_PASS_NONE, iuser->pass) || + !ELEM(image->gpu_layer, IMAGE_GPU_LAYER_NONE, iuser->layer) || + (!ELEM(image->gpu_view, IMAGE_GPU_VIEW_NONE, iuser->multi_index) && iuser->multi_index >= 2)) { BKE_image_partial_update_mark_full_update(image); } diff --git a/source/blender/makesdna/DNA_image_defaults.h b/source/blender/makesdna/DNA_image_defaults.h index 9e7b4bf696a..99eea9984eb 100644 --- a/source/blender/makesdna/DNA_image_defaults.h +++ b/source/blender/makesdna/DNA_image_defaults.h @@ -22,9 +22,10 @@ .gen_y = 1024, \ .gen_type = IMA_GENTYPE_GRID, \ \ - .gpuframenr = INT_MAX, \ - .gpu_pass = SHRT_MAX, \ - .gpu_layer = SHRT_MAX, \ + .gpuframenr = IMAGE_GPU_FRAME_NONE, \ + .gpu_pass = IMAGE_GPU_PASS_NONE, \ + .gpu_layer = IMAGE_GPU_LAYER_NONE, \ + .gpu_view = IMAGE_GPU_VIEW_NONE, \ .seam_margin = 8, \ } diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index dc40faec838..023639b0a96 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -293,3 +293,9 @@ enum { IMA_ALPHA_CHANNEL_PACKED = 2, IMA_ALPHA_IGNORE = 3, }; + +/* Image gpu runtime defaults */ +#define IMAGE_GPU_FRAME_NONE INT_MAX +#define IMAGE_GPU_PASS_NONE SHRT_MAX +#define IMAGE_GPU_LAYER_NONE SHRT_MAX +#define IMAGE_GPU_VIEW_NONE SHRT_MAX