diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index f00da370ccf..9dade65c045 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -493,11 +493,34 @@ struct ImBuf *BKE_image_get_first_ibuf(struct Image *image); */ struct GPUTexture *BKE_image_create_gpu_texture_from_ibuf(struct Image *image, struct ImBuf *ibuf); +/** + * Ensure that the cached GPU texture inside the image matches the pass, layer, and view of the + * given image user, if not, invalidate the cache such that the next call to the GPU texture + * retrieval functions such as BKE_image_get_gpu_texture updates the cache with an image that + * matches the give image user. + * + * This is provided as a separate function and not implemented as part of the GPU texture retrieval + * functions because the current cache system only allows a single pass, layer, and stereo view to + * be cached, so possible frequent invalidations of the cache can have performance implications, + * and making invalidation explicit by calling this function will help make that clear and pave the + * way for a more complete cache system in the future. + */ +void BKE_image_ensure_gpu_texture(struct Image *image, struct ImageUser *iuser); + /** * Get the #GPUTexture for a given `Image`. * * `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already * available. It is also required when requesting the #GPUTexture for a render result. + * + * The requested GPU texture will be cached for subsequent calls, but only a single layer, pass, + * and view can be cached at a time, so the cache should be invalidated in operators and RNA + * callbacks that change the layer, pass, or view of the image to maintain a correct cache state. + * However, in some cases, multiple layers, passes, or views might be needed at the same time, like + * is the case for the realtime compositor. This is currently not supported, so the caller should + * ensure that the requested layer is indeed the cached one and invalidated the cached otherwise by + * calling BKE_image_ensure_gpu_texture. This is a workaround until image can support a more + * complete caching system. */ struct GPUTexture *BKE_image_get_gpu_texture(struct Image *image, struct ImageUser *iuser, diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc index bb3dc32ecbf..e6aee9dbbb4 100644 --- a/source/blender/blenkernel/intern/image_gpu.cc +++ b/source/blender/blenkernel/intern/image_gpu.cc @@ -336,6 +336,20 @@ static void image_gpu_texture_try_partial_update(Image *image, ImageUser *iuser) } } +void BKE_image_ensure_gpu_texture(Image *image, ImageUser *image_user) +{ + if (!image) { + return; + } + + /* Note that the image can cache both sterio 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)) { + BKE_image_partial_update_mark_full_update(image); + } +} + static GPUTexture *image_get_gpu_texture(Image *ima, ImageUser *iuser, ImBuf *ibuf, @@ -365,6 +379,9 @@ static GPUTexture *image_get_gpu_texture(Image *ima, ima->gpu_pass = requested_pass; ima->gpu_layer = requested_layer; ima->gpu_view = requested_view; + /* The cache should be invalidated here, but it is intentionally isn't due to possible + * performance implications, see the BKE_image_ensure_gpu_texture function for more + * information. */ } #undef GPU_FLAGS_TO_CHECK diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index 27b864f9856..c9e1391cfe6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -516,6 +516,7 @@ class ImageOperation : public NodeOperation { } ImageUser image_user = compute_image_user_for_output(identifier); + BKE_image_ensure_gpu_texture(get_image(), &image_user); GPUTexture *image_texture = BKE_image_get_gpu_texture(get_image(), &image_user, nullptr); const int2 size = int2(GPU_texture_width(image_texture), GPU_texture_height(image_texture));