diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-07-29 19:13:19 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-07-30 00:06:37 +0300 |
commit | 5f6fb5bb41ed0057f0e2f0ccded717fbf04e55e2 (patch) | |
tree | 94ce813b25b5bf766136e694f893517e93432bf7 | |
parent | 7e8d4937307e0be3ab4587c58c49f16211466987 (diff) |
Cleanup: Split gpu_texture_image.c into BKE and IMB modules
This is in order to disolve GPU_draw.h into more meaningful code blocks.
All the Image related function are in `image_gpu.c`.
All the MovieClip related function are in `movieclip.c`.
The IMB module now has a connection with GPU. This is not strickly
necessary and the code could be move to `image_gpu.c` if needed.
The Image garbage collection is also ported to `image_gpu.c`.
37 files changed, 615 insertions, 555 deletions
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 1e5573ab014..c5221baf7d7 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -55,6 +55,7 @@ void BKE_image_free_packedfiles(struct Image *image); void BKE_image_free_views(struct Image *image); void BKE_image_free_buffers(struct Image *image); void BKE_image_free_buffers_ex(struct Image *image, bool do_lock); +void BKE_image_free_gputextures(struct Image *ima); /* call from library */ void BKE_image_free(struct Image *image); @@ -274,6 +275,10 @@ void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame); /* does all images with type MOVIE or SEQUENCE */ void BKE_image_all_free_anim_ibufs(struct Main *bmain, int except_frame); +void BKE_image_free_all_gputextures(struct Main *bmain); +void BKE_image_free_anim_gputextures(struct Main *bmain); +void BKE_image_free_old_gputextures(struct Main *bmain); + bool BKE_image_memorypack(struct Image *ima); void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath); void BKE_image_packfiles_from_mem(struct ReportList *reports, @@ -362,6 +367,30 @@ bool BKE_image_has_loaded_ibuf(struct Image *image); struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name); struct ImBuf *BKE_image_get_first_ibuf(struct Image *image); +/* Not to be use directly. */ +struct GPUTexture *BKE_image_create_gpu_texture_from_ibuf(struct Image *image, struct ImBuf *ibuf); + +/* 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. */ +struct GPUTexture *BKE_image_get_gpu_texture(struct Image *image, + struct ImageUser *iuser, + struct ImBuf *ibuf); +struct GPUTexture *BKE_image_get_gpu_tiles(struct Image *image, + struct ImageUser *iuser, + struct ImBuf *ibuf); +struct GPUTexture *BKE_image_get_gpu_tilemap(struct Image *image, + struct ImageUser *iuser, + struct ImBuf *ibuf); + +void BKE_image_update_gputexture( + struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h); +void BKE_image_paint_set_mipmap(struct Main *bmain, bool mipmap); + +/* Delayed free of OpenGL buffers by main thread */ +void BKE_image_free_unused_gpu_textures(void); + struct RenderSlot *BKE_image_add_renderslot(struct Image *ima, const char *name); bool BKE_image_remove_renderslot(struct Image *ima, struct ImageUser *iuser, int slot); struct RenderSlot *BKE_image_get_renderslot(struct Image *ima, int slot); diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index dbd6eb15bf2..bba01dd84d2 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -113,6 +113,11 @@ bool BKE_movieclip_put_frame_if_possible(struct MovieClip *clip, struct MovieClipUser *user, struct ImBuf *ibuf); +struct GPUTexture *BKE_movieclip_get_gpu_texture(struct MovieClip *clip, + struct MovieClipUser *cuser); + +void BKE_movieclip_free_gputexture(struct MovieClip *clip); + /* Dependency graph evaluation. */ void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index d702da55ea8..95f06d02055 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -134,6 +134,7 @@ set(SRC intern/idtype.c intern/image.c intern/image_gen.c + intern/image_gpu.c intern/image_save.c intern/ipo.c intern/kelvinlet.c diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 042a5233978..fa0be9ea441 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -90,7 +90,6 @@ #include "RE_pipeline.h" -#include "GPU_draw.h" #include "GPU_texture.h" #include "BLI_sys_types.h" // for intptr_t support @@ -393,7 +392,7 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock) ima->rr = NULL; } - GPU_free_image(ima); + BKE_image_free_gputextures(ima); LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { tile->ok = IMA_OK; diff --git a/source/blender/gpu/intern/gpu_texture_image.c b/source/blender/blenkernel/intern/image_gpu.c index aa0637c2c3f..b02b6e1453c 100644 --- a/source/blender/gpu/intern/gpu_texture_image.c +++ b/source/blender/blenkernel/intern/image_gpu.c @@ -13,36 +13,24 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2005 Blender Foundation. + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. */ /** \file - * \ingroup gpu - * - * Utility functions for dealing with OpenGL texture & material context, - * mipmap generation and light objects. - * - * These are some obscure rendering functions shared between the game engine (not anymore) - * and the blender, in this module to avoid duplication - * and abstract them away from the rest a bit. + * \ingroup bke */ -#include <string.h> +#include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" #include "BLI_boxpack_2d.h" #include "BLI_linklist.h" -#include "BLI_math.h" +#include "BLI_listbase.h" #include "BLI_threads.h" -#include "BLI_utildefines.h" #include "DNA_image_types.h" -#include "DNA_movieclip_types.h" #include "DNA_userdef_types.h" -#include "MEM_guardedalloc.h" - #include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -50,218 +38,31 @@ #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" -#include "BKE_movieclip.h" -#include "GPU_draw.h" #include "GPU_extensions.h" +#include "GPU_state.h" #include "GPU_texture.h" #include "PIL_time.h" -static void gpu_free_image(Image *ima, const bool immediate); +/* Prototypes. */ static void gpu_free_unused_buffers(void); - -/** \} */ +static void image_free_gpu(Image *ima, const bool immediate); /* -------------------------------------------------------------------- */ -/** \name Utility functions +/** \name UDIM gpu texture * \{ */ -/** Checking powers of two for images since OpenGL ES requires it */ -#ifdef WITH_DDS -static bool is_power_of_2_resolution(int w, int h) -{ - return is_power_of_2_i(w) && is_power_of_2_i(h); -} -#endif - static bool is_over_resolution_limit(int w, int h) { - int size = GPU_max_texture_size(); - int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size; - - return (w > reslimit || h > reslimit); + return (w > GPU_texture_size_with_limit(w) || h > GPU_texture_size_with_limit(h)); } static int smaller_power_of_2_limit(int num) { - int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, GPU_max_texture_size()) : - GPU_max_texture_size(); - /* take texture clamping into account */ - if (num > reslimit) { - return reslimit; - } - - return power_of_2_min_i(num); -} - -static GPUTexture **gpu_get_image_gputexture(Image *ima, - eGPUTextureTarget textarget, - const int multiview_eye) -{ - const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT); - BLI_assert(in_range); - - if (in_range) { - return &(ima->gputexture[textarget][multiview_eye]); - } - return NULL; -} - -static GPUTexture **gpu_get_movieclip_gputexture(MovieClip *clip, - MovieClipUser *cuser, - eGPUTextureTarget textarget) -{ - LISTBASE_FOREACH (MovieClip_RuntimeGPUTexture *, tex, &clip->runtime.gputextures) { - if (memcmp(&tex->user, cuser, sizeof(MovieClipUser)) == 0) { - if (tex == NULL) { - tex = (MovieClip_RuntimeGPUTexture *)MEM_mallocN(sizeof(MovieClip_RuntimeGPUTexture), - __func__); - - for (int i = 0; i < TEXTARGET_COUNT; i++) { - tex->gputexture[i] = NULL; - } - - memcpy(&tex->user, cuser, sizeof(MovieClipUser)); - BLI_addtail(&clip->runtime.gputextures, tex); - } - - return &tex->gputexture[textarget]; - } - } - return NULL; -} - -/** - * Apply colormanagement and scale buffer if needed. - * *r_freedata is set to true if the returned buffer need to be manually freed. - **/ -static void *IMB_gpu_get_data(const ImBuf *ibuf, - const bool do_rescale, - const int rescale_size[2], - const bool compress_as_srgb, - const bool store_premultiplied, - bool *r_freedata) -{ - const bool is_float_rect = (ibuf->rect_float != NULL); - void *data_rect = (is_float_rect) ? (void *)ibuf->rect_float : (void *)ibuf->rect; - - if (is_float_rect) { - /* Float image is already in scene linear colorspace or non-color data by - * convention, no colorspace conversion needed. But we do require 4 channels - * currently. */ - if (ibuf->channels != 4 || !store_premultiplied) { - data_rect = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__); - *r_freedata = true; - - if (data_rect == NULL) { - return NULL; - } - - IMB_colormanagement_imbuf_to_float_texture( - (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied); - } - } - else { - /* Byte image is in original colorspace from the file. If the file is sRGB - * scene linear, or non-color data no conversion is needed. Otherwise we - * compress as scene linear + sRGB transfer function to avoid precision loss - * in common cases. - * - * We must also convert to premultiplied for correct texture interpolation - * and consistency with float images. */ - if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) { - data_rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__); - *r_freedata = true; - - if (data_rect == NULL) { - return NULL; - } - - /* Texture storage of images is defined by the alpha mode of the image. The - * downside of this is that there can be artifacts near alpha edges. However, - * this allows us to use sRGB texture formats and preserves color values in - * zero alpha areas, and appears generally closer to what game engines that we - * want to be compatible with do. */ - IMB_colormanagement_imbuf_to_byte_texture( - (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied); - } - } - - if (do_rescale) { - uint *rect = (is_float_rect) ? NULL : (uint *)data_rect; - float *rect_float = (is_float_rect) ? (float *)data_rect : NULL; - - ImBuf *scale_ibuf = IMB_allocFromBuffer(rect, rect_float, ibuf->x, ibuf->y, 4); - IMB_scaleImBuf(scale_ibuf, UNPACK2(rescale_size)); - - data_rect = (is_float_rect) ? (void *)scale_ibuf->rect_float : (void *)scale_ibuf->rect; - *r_freedata = true; - /* Steal the rescaled buffer to avoid double free. */ - scale_ibuf->rect_float = NULL; - scale_ibuf->rect = NULL; - IMB_freeImBuf(scale_ibuf); - } - return data_rect; -} - -static void IMB_gpu_get_format(const ImBuf *ibuf, - bool high_bitdepth, - eGPUDataFormat *r_data_format, - eGPUTextureFormat *r_texture_format) -{ - const bool float_rect = (ibuf->rect_float != NULL); - const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) && - !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)); - high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth); - - *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE; - - if (float_rect) { - *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F; - } - else { - *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8; - } -} - -#ifdef WITH_DDS -/* Return false if no suitable format was found. */ -static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format) -{ - /* For DDS we only support data, scene linear and sRGB. Converting to - * different colorspace would break the compression. */ - const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) && - !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)); - - if (ibuf->dds_data.fourcc == FOURCC_DXT1) { - *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT1 : GPU_RGBA8_DXT1; - } - else if (ibuf->dds_data.fourcc == FOURCC_DXT3) { - *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT3 : GPU_RGBA8_DXT3; - } - else if (ibuf->dds_data.fourcc == FOURCC_DXT5) { - *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT5 : GPU_RGBA8_DXT5; - } - else { - return false; - } - return true; -} -#endif - -static bool mipmap_enabled(void) -{ - /* This used to be a userpref option. Maybe it will be re-introduce late. */ - return true; + return power_of_2_min_i(GPU_texture_size_with_limit(num)); } -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name UDIM gpu texture - * \{ */ - static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye) { GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye]; @@ -421,7 +222,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) BKE_image_release_ibuf(ima, ibuf, NULL); } - if (mipmap_enabled()) { + if (GPU_mipmap_enabled()) { GPU_texture_generate_mipmap(tex); GPU_texture_mipmap_mode(tex, true, true); if (ima) { @@ -443,76 +244,37 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) /** \name Regular gpu texture * \{ */ -static GPUTexture *IMB_create_gpu_texture(ImBuf *ibuf, bool use_high_bitdepth, bool use_premult) +static GPUTexture **get_image_gpu_texture_ptr(Image *ima, + eGPUTextureTarget textarget, + const int multiview_eye) { - GPUTexture *tex = NULL; - bool do_rescale = is_over_resolution_limit(ibuf->x, ibuf->y); - -#ifdef WITH_DDS - if (ibuf->ftype == IMB_FTYPE_DDS) { - eGPUTextureFormat compressed_format; - if (!IMB_gpu_get_compressed_format(ibuf, &compressed_format)) { - fprintf(stderr, "Unable to find a suitable DXT compression,"); - } - else if (do_rescale) { - fprintf(stderr, "Unable to load DXT image resolution,"); - } - else if (!is_power_of_2_resolution(ibuf->x, ibuf->y)) { - fprintf(stderr, "Unable to load non-power-of-two DXT image resolution,"); - } - else { - tex = GPU_texture_create_compressed( - ibuf->x, ibuf->y, ibuf->dds_data.nummipmaps, compressed_format, ibuf->dds_data.data); - - if (tex != NULL) { - return tex; - } - else { - fprintf(stderr, "ST3C support not found,"); - } - } - /* Fallback to uncompressed texture. */ - fprintf(stderr, " falling back to uncompressed.\n"); - } -#endif - - eGPUDataFormat data_format; - eGPUTextureFormat tex_format; - IMB_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format); + const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT); + BLI_assert(in_range); - int size[2] = {ibuf->x, ibuf->y}; - if (do_rescale) { - size[0] = smaller_power_of_2_limit(size[0]); - size[1] = smaller_power_of_2_limit(size[1]); + if (in_range) { + return &(ima->gputexture[textarget][multiview_eye]); } + return NULL; +} - const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8); - bool freebuf = false; - - void *data = IMB_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf); - - /* Create Texture. */ - tex = GPU_texture_create_nD(UNPACK2(size), 0, 2, data, tex_format, data_format, 0, false, NULL); - - GPU_texture_anisotropic_filter(tex, true); - - if (freebuf) { - MEM_SAFE_FREE(data); +static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget) +{ + switch (textarget) { + case TEXTARGET_2D_ARRAY: + return GPU_texture_create_error(2, true); + case TEXTARGET_TILE_MAPPING: + return GPU_texture_create_error(1, true); + case TEXTARGET_2D: + default: + return GPU_texture_create_error(2, false); } - - return tex; } -/* 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. */ -GPUTexture *GPU_texture_from_blender(Image *ima, - ImageUser *iuser, - ImBuf *ibuf, - eGPUTextureTarget textarget) +static GPUTexture *image_get_gpu_texture(Image *ima, + ImageUser *iuser, + ImBuf *ibuf, + eGPUTextureTarget textarget) { -#ifndef GPU_STANDALONE if (ima == NULL) { return NULL; } @@ -523,7 +285,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, /* currently, gpu refresh tagging is used by ima sequences */ if (ima->gpuflag & IMA_GPU_REFRESH) { - gpu_free_image(ima, true); + image_free_gpu(ima, true); ima->gpuflag &= ~IMA_GPU_REFRESH; } @@ -531,7 +293,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, BKE_image_tag_time(ima); /* Test if we already have a texture. */ - GPUTexture **tex = gpu_get_image_gputexture(ima, textarget, iuser ? iuser->multiview_eye : 0); + GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, iuser ? iuser->multiview_eye : 0); if (*tex) { return *tex; } @@ -540,7 +302,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, * texture with zero bindcode so we don't keep trying. */ ImageTile *tile = BKE_image_get_tile(ima, 0); if (tile == NULL || tile->ok == 0) { - *tex = GPU_texture_create_error(textarget); + *tex = image_gpu_texture_error_create(textarget); return *tex; } @@ -549,7 +311,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, if (ibuf_intern == NULL) { ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL); if (ibuf_intern == NULL) { - *tex = GPU_texture_create_error(textarget); + *tex = image_gpu_texture_error_create(textarget); return *tex; } } @@ -568,7 +330,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, *tex = IMB_create_gpu_texture(ibuf_intern, use_high_bitdepth, store_premultiplied); - if (mipmap_enabled()) { + if (GPU_mipmap_enabled()) { GPU_texture_bind(*tex, 0); GPU_texture_generate_mipmap(*tex); GPU_texture_unbind(*tex); @@ -590,45 +352,150 @@ GPUTexture *GPU_texture_from_blender(Image *ima, GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y); return *tex; -#endif - return NULL; } -GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser) +GPUTexture *BKE_image_get_gpu_texture(Image *image, ImageUser *iuser, ImBuf *ibuf) { -#ifndef GPU_STANDALONE - if (clip == NULL) { - return NULL; + return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_2D); +} + +GPUTexture *BKE_image_get_gpu_tiles(Image *image, ImageUser *iuser, ImBuf *ibuf) +{ + return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_2D_ARRAY); +} + +GPUTexture *BKE_image_get_gpu_tilemap(Image *image, ImageUser *iuser, ImBuf *ibuf) +{ + return image_get_gpu_texture(image, iuser, ibuf, TEXTARGET_TILE_MAPPING); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delayed GPU texture free + * + * Image datablocks can be deleted by any thread, but there may not be any active OpenGL context. + * In that case we push them into a queue and free the buffers later. + * \{ */ + +static LinkNode *gpu_texture_free_queue = NULL; +static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER; + +static void gpu_free_unused_buffers(void) +{ + if (gpu_texture_free_queue == NULL) { + return; } - GPUTexture **tex = gpu_get_movieclip_gputexture(clip, cuser, TEXTARGET_2D); - if (*tex) { - return *tex; + BLI_mutex_lock(&gpu_texture_queue_mutex); + + if (gpu_texture_free_queue != NULL) { + GPUTexture *tex; + while ((tex = (GPUTexture *)BLI_linklist_pop(&gpu_texture_free_queue))) { + GPU_texture_free(tex); + } + gpu_texture_free_queue = NULL; } - /* check if we have a valid image buffer */ - ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, cuser); - if (ibuf == NULL) { - *tex = GPU_texture_create_error(TEXTARGET_2D); - return *tex; + BLI_mutex_unlock(&gpu_texture_queue_mutex); +} + +void BKE_image_free_unused_gpu_textures() +{ + if (BLI_thread_is_main()) { + gpu_free_unused_buffers(); } +} + +/** \} */ - /* This only means RGBA16F instead of RGBA32F. */ - const bool high_bitdepth = false; - const bool store_premultiplied = ibuf->rect_float ? false : true; - *tex = IMB_create_gpu_texture(ibuf, high_bitdepth, store_premultiplied); +/* -------------------------------------------------------------------- */ +/** \name Deletion + * \{ */ - /* Do not generate mips for movieclips... too slow. */ - GPU_texture_mipmap_mode(*tex, false, true); +static void image_free_gpu(Image *ima, const bool immediate) +{ + for (int eye = 0; eye < 2; eye++) { + for (int i = 0; i < TEXTARGET_COUNT; i++) { + if (ima->gputexture[i][eye] != NULL) { + if (immediate) { + GPU_texture_free(ima->gputexture[i][eye]); + } + else { + BLI_mutex_lock(&gpu_texture_queue_mutex); + BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]); + BLI_mutex_unlock(&gpu_texture_queue_mutex); + } - IMB_freeImBuf(ibuf); + ima->gputexture[i][eye] = NULL; + } + } + } - return *tex; -#else - return NULL; -#endif + ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE; +} + +void BKE_image_free_gputextures(Image *ima) +{ + image_free_gpu(ima, BLI_thread_is_main()); +} + +void BKE_image_free_all_gputextures(Main *bmain) +{ + if (bmain) { + LISTBASE_FOREACH (Image *, ima, &bmain->images) { + BKE_image_free_gputextures(ima); + } + } } +/* same as above but only free animated images */ +void BKE_image_free_anim_gputextures(Main *bmain) +{ + if (bmain) { + LISTBASE_FOREACH (Image *, ima, &bmain->images) { + if (BKE_image_is_animated(ima)) { + BKE_image_free_gputextures(ima); + } + } + } +} + +void BKE_image_free_old_gputextures(Main *bmain) +{ + static int lasttime = 0; + int ctime = (int)PIL_check_seconds_timer(); + + /* + * Run garbage collector once for every collecting period of time + * if textimeout is 0, that's the option to NOT run the collector + */ + if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime) { + return; + } + + /* of course not! */ + if (G.is_rendering) { + return; + } + + lasttime = ctime; + + LISTBASE_FOREACH (Image *, ima, &bmain->images) { + if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) { + /* If it's in GL memory, deallocate and set time tag to current time + * This gives textures a "second chance" to be used before dying. */ + if (BKE_image_has_opengl_texture(ima)) { + BKE_image_free_gputextures(ima); + ima->lastused = ctime; + } + /* Otherwise, just kill the buffers */ + else { + BKE_image_free_buffers(ima); + } + } + } +} /** \} */ /* -------------------------------------------------------------------- */ @@ -745,10 +612,6 @@ static void gpu_texture_update_unscaled(GPUTexture *tex, static void gpu_texture_update_from_ibuf( GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h) { - /* Partial update of texture for texture painting. This is often much - * quicker than fully updating the texture for high resolution images. */ - GPU_texture_bind(tex, 0); - bool scaled; if (tile != NULL) { int *tilesize = tile->runtime.tilearray_size; @@ -814,6 +677,8 @@ static void gpu_texture_update_from_ibuf( } } + GPU_texture_bind(tex, 0); + if (scaled) { /* Slower update where we first have to scale the input pixels. */ if (tile != NULL) { @@ -850,7 +715,7 @@ static void gpu_texture_update_from_ibuf( MEM_freeN(rect_float); } - if (mipmap_enabled()) { + if (GPU_mipmap_enabled()) { GPU_texture_generate_mipmap(tex); } else { @@ -860,7 +725,9 @@ static void gpu_texture_update_from_ibuf( GPU_texture_unbind(tex); } -void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h) +/* Partial update of texture for texture painting. This is often much + * quicker than fully updating the texture for high resolution images. */ +void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h) { #ifndef GPU_STANDALONE ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); @@ -868,7 +735,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i if ((ibuf == NULL) || (w == 0) || (h == 0)) { /* Full reload of texture. */ - GPU_free_image(ima); + BKE_image_free_gputextures(ima); } GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0]; @@ -891,9 +758,8 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i * temporary disabling/enabling mipmapping on all images for quick texture * updates with glTexSubImage2D. images that didn't change don't have to be * re-uploaded to OpenGL */ -void GPU_paint_set_mipmap(Main *bmain, bool mipmap) +void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap) { -#ifndef GPU_STANDALONE LISTBASE_FOREACH (Image *, ima, &bmain->images) { if (BKE_image_has_opengl_texture(ima)) { if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) { @@ -909,163 +775,13 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap) } } else { - GPU_free_image(ima); + BKE_image_free_gputextures(ima); } } else { ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE; } } -#endif /* GPU_STANDALONE */ -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Delayed GPU texture free - * - * Image datablocks can be deleted by any thread, but there may not be any active OpenGL context. - * In that case we push them into a queue and free the buffers later. - * \{ */ - -static LinkNode *gpu_texture_free_queue = NULL; -static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER; - -static void gpu_free_unused_buffers() -{ - if (gpu_texture_free_queue == NULL) { - return; - } - - BLI_mutex_lock(&gpu_texture_queue_mutex); - - if (gpu_texture_free_queue != NULL) { - GPUTexture *tex; - while ((tex = (GPUTexture *)BLI_linklist_pop(&gpu_texture_free_queue))) { - GPU_texture_free(tex); - } - gpu_texture_free_queue = NULL; - } - - BLI_mutex_unlock(&gpu_texture_queue_mutex); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Deletion - * \{ */ - -static void gpu_free_image(Image *ima, const bool immediate) -{ - for (int eye = 0; eye < 2; eye++) { - for (int i = 0; i < TEXTARGET_COUNT; i++) { - if (ima->gputexture[i][eye] != NULL) { - if (immediate) { - GPU_texture_free(ima->gputexture[i][eye]); - } - else { - BLI_mutex_lock(&gpu_texture_queue_mutex); - BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye]); - BLI_mutex_unlock(&gpu_texture_queue_mutex); - } - - ima->gputexture[i][eye] = NULL; - } - } - } - - ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE; -} - -void GPU_free_unused_buffers() -{ - if (BLI_thread_is_main()) { - gpu_free_unused_buffers(); - } -} - -void GPU_free_image(Image *ima) -{ - gpu_free_image(ima, BLI_thread_is_main()); -} - -void GPU_free_movieclip(struct MovieClip *clip) -{ - /* number of gpu textures to keep around as cache - * We don't want to keep too many GPU textures for - * movie clips around, as they can be large.*/ - const int MOVIECLIP_NUM_GPUTEXTURES = 1; - - while (BLI_listbase_count(&clip->runtime.gputextures) > MOVIECLIP_NUM_GPUTEXTURES) { - MovieClip_RuntimeGPUTexture *tex = (MovieClip_RuntimeGPUTexture *)BLI_pophead( - &clip->runtime.gputextures); - for (int i = 0; i < TEXTARGET_COUNT; i++) { - /* free glsl image binding */ - if (tex->gputexture[i]) { - GPU_texture_free(tex->gputexture[i]); - tex->gputexture[i] = NULL; - } - } - MEM_freeN(tex); - } -} - -void GPU_free_images(Main *bmain) -{ - if (bmain) { - LISTBASE_FOREACH (Image *, ima, &bmain->images) { - GPU_free_image(ima); - } - } -} - -/* same as above but only free animated images */ -void GPU_free_images_anim(Main *bmain) -{ - if (bmain) { - LISTBASE_FOREACH (Image *, ima, &bmain->images) { - if (BKE_image_is_animated(ima)) { - GPU_free_image(ima); - } - } - } -} - -void GPU_free_images_old(Main *bmain) -{ - static int lasttime = 0; - int ctime = (int)PIL_check_seconds_timer(); - - /* - * Run garbage collector once for every collecting period of time - * if textimeout is 0, that's the option to NOT run the collector - */ - if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime) { - return; - } - - /* of course not! */ - if (G.is_rendering) { - return; - } - - lasttime = ctime; - - LISTBASE_FOREACH (Image *, ima, &bmain->images) { - if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) { - /* If it's in GL memory, deallocate and set time tag to current time - * This gives textures a "second chance" to be used before dying. */ - if (BKE_image_has_opengl_texture(ima)) { - GPU_free_image(ima); - ima->lastused = ctime; - } - /* Otherwise, just kill the buffers */ - else { - BKE_image_free_buffers(ima); - } - } - } } -/** \} */ +/** \} */
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index d79ef9525cd..e21e0a7d510 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1867,3 +1867,84 @@ void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, MovieClip DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip); movieclip_selection_sync(clip, (MovieClip *)clip->id.orig_id); } + +/* -------------------------------------------------------------------- */ +/** \name GPU textures + * \{ */ + +static GPUTexture **movieclip_get_gputexture_ptr(MovieClip *clip, + MovieClipUser *cuser, + eGPUTextureTarget textarget) +{ + LISTBASE_FOREACH (MovieClip_RuntimeGPUTexture *, tex, &clip->runtime.gputextures) { + if (memcmp(&tex->user, cuser, sizeof(MovieClipUser)) == 0) { + if (tex == NULL) { + tex = (MovieClip_RuntimeGPUTexture *)MEM_mallocN(sizeof(MovieClip_RuntimeGPUTexture), + __func__); + + for (int i = 0; i < TEXTARGET_COUNT; i++) { + tex->gputexture[i] = NULL; + } + + memcpy(&tex->user, cuser, sizeof(MovieClipUser)); + BLI_addtail(&clip->runtime.gputextures, tex); + } + + return &tex->gputexture[textarget]; + } + } + return NULL; +} + +GPUTexture *BKE_movieclip_get_gpu_texture(MovieClip *clip, MovieClipUser *cuser) +{ + if (clip == NULL) { + return NULL; + } + + GPUTexture **tex = movieclip_get_gputexture_ptr(clip, cuser, TEXTARGET_2D); + if (*tex) { + return *tex; + } + + /* check if we have a valid image buffer */ + ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, cuser); + if (ibuf == NULL) { + *tex = GPU_texture_create_error(2, false); + return *tex; + } + + /* This only means RGBA16F instead of RGBA32F. */ + const bool high_bitdepth = false; + const bool store_premultiplied = ibuf->rect_float ? false : true; + *tex = IMB_create_gpu_texture(ibuf, high_bitdepth, store_premultiplied); + + /* Do not generate mips for movieclips... too slow. */ + GPU_texture_mipmap_mode(*tex, false, true); + + IMB_freeImBuf(ibuf); + + return *tex; +} + +void BKE_movieclip_free_gputexture(struct MovieClip *clip) +{ + /* number of gpu textures to keep around as cache + * We don't want to keep too many GPU textures for + * movie clips around, as they can be large.*/ + const int MOVIECLIP_NUM_GPUTEXTURES = 1; + + while (BLI_listbase_count(&clip->runtime.gputextures) > MOVIECLIP_NUM_GPUTEXTURES) { + MovieClip_RuntimeGPUTexture *tex = (MovieClip_RuntimeGPUTexture *)BLI_pophead( + &clip->runtime.gputextures); + for (int i = 0; i < TEXTARGET_COUNT; i++) { + /* free glsl image binding */ + if (tex->gputexture[i]) { + GPU_texture_free(tex->gputexture[i]); + tex->gputexture[i] = NULL; + } + } + MEM_freeN(tex); + } +} +/** \} */
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index f42c60b04bf..7bf4c78d870 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -32,6 +32,8 @@ #include "DNA_world_types.h" +#include "IMB_imbuf.h" + #include "eevee_private.h" #include "eevee_engine.h" /* own include */ diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c index d2aa0a45660..ed443b2c73f 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c @@ -63,7 +63,7 @@ static struct GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); if (ibuf != NULL && ibuf->rect != NULL) { - gpu_tex = GPU_texture_from_blender(image, &iuser, ibuf, TEXTARGET_2D); + gpu_tex = BKE_image_get_gpu_texture(image, &iuser, ibuf); *r_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL); } BKE_image_release_ibuf(image, ibuf, lock); diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c index 0c18c90128d..d456e147c15 100644 --- a/source/blender/draw/engines/overlay/overlay_image.c +++ b/source/blender/draw/engines/overlay/overlay_image.c @@ -175,7 +175,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp } width = ibuf->x; height = ibuf->y; - tex = GPU_texture_from_blender(image, iuser, ibuf, TEXTARGET_2D); + tex = BKE_image_get_gpu_texture(image, iuser, ibuf); BKE_image_release_ibuf(image, ibuf, lock); iuser->scene = NULL; @@ -203,7 +203,7 @@ static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgp } BKE_movieclip_user_set_frame(&bgpic->cuser, ctime); - tex = GPU_texture_from_movieclip(clip, &bgpic->cuser); + tex = BKE_movieclip_get_gpu_texture(clip, &bgpic->cuser); if (tex == NULL) { return NULL; } @@ -232,7 +232,7 @@ static void OVERLAY_image_free_movieclips_textures(OVERLAY_Data *data) LinkData *link; while ((link = BLI_pophead(&data->stl->pd->bg_movie_clips))) { MovieClip *clip = (MovieClip *)link->data; - GPU_free_movieclip(clip); + BKE_movieclip_free_gputexture(clip); MEM_freeN(link); } } @@ -383,7 +383,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob) if (ima != NULL) { ImageUser iuser = *ob->iuser; camera_background_images_stereo_setup(draw_ctx->scene, draw_ctx->v3d, ima, &iuser); - tex = GPU_texture_from_blender(ima, &iuser, NULL, TEXTARGET_2D); + tex = BKE_image_get_gpu_texture(ima, &iuser, NULL); if (tex) { size[0] = GPU_texture_orig_width(tex); size[1] = GPU_texture_orig_height(tex); diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c index 44eded94e63..25b8a953ba7 100644 --- a/source/blender/draw/engines/overlay/overlay_paint.c +++ b/source/blender/draw/engines/overlay/overlay_paint.c @@ -22,6 +22,8 @@ #include "DRW_render.h" +#include "BKE_image.h" + #include "DNA_mesh_types.h" #include "DEG_depsgraph_query.h" @@ -136,7 +138,7 @@ void OVERLAY_paint_cache_init(OVERLAY_Data *vedata) state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state); - GPUTexture *tex = GPU_texture_from_blender(imapaint->stencil, NULL, NULL, TEXTARGET_2D); + GPUTexture *tex = BKE_image_get_gpu_texture(imapaint->stencil, NULL, NULL); const bool mask_premult = (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL); const bool mask_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0; diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 9956ba5da11..b59e20e9df3 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -262,11 +262,11 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, if (ima) { if (ima->source == IMA_SRC_TILED) { - tex = GPU_texture_from_blender(ima, iuser, NULL, TEXTARGET_2D_ARRAY); - tex_tile_data = GPU_texture_from_blender(ima, iuser, NULL, TEXTARGET_TILE_MAPPING); + tex = BKE_image_get_gpu_tiles(ima, iuser, NULL); + tex_tile_data = BKE_image_get_gpu_tilemap(ima, iuser, NULL); } else { - tex = GPU_texture_from_blender(ima, iuser, NULL, TEXTARGET_2D); + tex = BKE_image_get_gpu_texture(ima, iuser, NULL); } } diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 00cd91323f0..dc41f34e0ea 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -1293,13 +1293,10 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass } static void drw_shgroup_material_texture(DRWShadingGroup *grp, - GPUMaterialTexture *tex, + GPUTexture *gputex, const char *name, - eGPUSamplerState state, - eGPUTextureTarget textarget) + eGPUSamplerState state) { - GPUTexture *gputex = GPU_texture_from_blender(tex->ima, tex->iuser, NULL, textarget); - DRW_shgroup_uniform_texture_ex(grp, name, gputex, state); GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images); @@ -1315,15 +1312,16 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial LISTBASE_FOREACH (GPUMaterialTexture *, tex, &textures) { if (tex->ima) { /* Image */ + GPUTexture *gputex; if (tex->tiled_mapping_name[0]) { - drw_shgroup_material_texture( - grp, tex, tex->sampler_name, tex->sampler_state, TEXTARGET_2D_ARRAY); - drw_shgroup_material_texture( - grp, tex, tex->tiled_mapping_name, tex->sampler_state, TEXTARGET_TILE_MAPPING); + gputex = BKE_image_get_gpu_tiles(tex->ima, tex->iuser, NULL); + drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state); + gputex = BKE_image_get_gpu_tilemap(tex->ima, tex->iuser, NULL); + drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state); } else { - drw_shgroup_material_texture( - grp, tex, tex->sampler_name, tex->sampler_state, TEXTARGET_2D); + gputex = BKE_image_get_gpu_texture(tex->ima, tex->iuser, NULL); + drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state); } } else if (tex->colorband) { diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index baa24ab2f4e..d67bd54bd69 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -60,7 +60,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "GPU_draw.h" /* GPU_free_image */ +#include "GPU_draw.h" /* BKE_image_free_gputextures */ #include "WM_api.h" #include "WM_types.h" @@ -530,7 +530,7 @@ static void multiresbake_freejob(void *bkv) /* delete here, since this delete will be called from main thread */ for (link = data->images.first; link; link = link->next) { Image *ima = (Image *)link->data; - GPU_free_image(ima); + BKE_image_free_gputextures(ima); } MEM_freeN(data->ob_image.array); diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index c4cb21a67f3..7b122cd7b93 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -308,7 +308,7 @@ static void refresh_images(BakeImages *bake_images) Image *ima = bake_images->data[i].image; LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { if (tile->ok == IMA_OK_LOADED) { - GPU_free_image(ima); + BKE_image_free_gputextures(ima); DEG_id_tag_update(&ima->id, 0); break; } diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 7ee3d991eb7..4a1153e0ca1 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -182,7 +182,7 @@ void imapaint_image_update( int h = imapaintpartial.y2 - imapaintpartial.y1; if (w && h) { /* Testing with partial update in uv editor too */ - GPU_paint_update_image(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h); + BKE_image_update_gputexture(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h); } } } @@ -1164,9 +1164,9 @@ void ED_object_texture_paint_mode_enter_ex(Main *bmain, Scene *scene, Object *ob BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint); if (U.glreslimit != 0) { - GPU_free_images(bmain); + BKE_image_free_all_gputextures(bmain); } - GPU_paint_set_mipmap(bmain, 0); + BKE_image_paint_set_mipmap(bmain, 0); toggle_paint_cursor(scene, true); @@ -1189,9 +1189,9 @@ void ED_object_texture_paint_mode_exit_ex(Main *bmain, Scene *scene, Object *ob) ob->mode &= ~OB_MODE_TEXTURE_PAINT; if (U.glreslimit != 0) { - GPU_free_images(bmain); + BKE_image_free_all_gputextures(bmain); } - GPU_paint_set_mipmap(bmain, 1); + BKE_image_paint_set_mipmap(bmain, 1); toggle_paint_cursor(scene, false); Mesh *me = BKE_mesh_from_object(ob); diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index a7f09390a3d..0bd6a00cf47 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -1784,7 +1784,7 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final) if (final) { if (s->image && !(s->sima && s->sima->lock)) { - GPU_free_image(s->image); + BKE_image_free_gputextures(s->image); } /* compositor listener deals with updating */ diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 5af3a3f4241..b7df628b2ff 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -6134,7 +6134,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) project_image_refresh_tagged(&ps); for (a = 0; a < ps.image_tot; a++) { - GPU_free_image(ps.projImages[a].ima); + BKE_image_free_gputextures(ps.projImages[a].ima); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ps.projImages[a].ima); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 4e410d35df0..705b28adc4f 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -2769,7 +2769,7 @@ static int image_invert_exec(bContext *C, wmOperator *op) ED_image_undo_push_end(); /* force GPU reupload, all image is invalid */ - GPU_free_image(ima); + BKE_image_free_gputextures(ima); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); @@ -2860,7 +2860,7 @@ static int image_scale_exec(bContext *C, wmOperator *op) ED_image_undo_push_end(); /* force GPU reupload, all image is invalid */ - GPU_free_image(ima); + BKE_image_free_gputextures(ima); DEG_id_tag_update(&ima->id, 0); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index e0c44c3a0ba..b34f0e8613f 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -295,7 +295,8 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles) SWAP(uint *, ptile->rect.uint, tmpibuf->rect); } - GPU_free_image(image); /* force OpenGL reload (maybe partial update will operate better?) */ + BKE_image_free_gputextures( + image); /* force OpenGL reload (maybe partial update will operate better?) */ if (ibuf->rect_float) { ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ } @@ -570,7 +571,7 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init) if (changed) { BKE_image_mark_dirty(image, ibuf); - GPU_free_image(image); /* force OpenGL reload */ + BKE_image_free_gputextures(image); /* force OpenGL reload */ if (ibuf->rect_float) { ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 84b3578e978..fa1568c61f2 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -36,6 +36,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_global.h" +#include "BKE_image.h" #include "BKE_key.h" #include "BKE_layer.h" #include "BKE_main.h" @@ -1617,7 +1618,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region) view3d_draw_view(C, region); DRW_cache_free_old_batches(bmain); - GPU_free_images_old(bmain); + BKE_image_free_old_gputextures(bmain); GPU_pass_cache_garbage_collect(); /* XXX This is in order to draw UI batches with the DRW @@ -1707,7 +1708,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph, { /* free images which can have changed on frame-change * warning! can be slow so only free animated images - campbell */ - GPU_free_images_anim(G.main); /* XXX :((( */ + BKE_image_free_anim_gputextures(G.main); /* XXX :((( */ } GPU_matrix_push_projection(); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 179d003facd..5e980f07c38 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -80,7 +80,6 @@ set(SRC intern/gpu_shader_interface.c intern/gpu_state.cc intern/gpu_texture.cc - intern/gpu_texture_image.c intern/gpu_texture_fluid.c intern/gpu_uniformbuffer.cc intern/gpu_vertex_buffer.cc diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 91f2442712b..3a22588e703 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -26,29 +26,11 @@ #include "BLI_utildefines.h" -#include "DNA_image_types.h" -#include "DNA_object_enums.h" - #ifdef __cplusplus extern "C" { #endif struct FluidModifierData; -struct GPUTexture; -struct Image; -struct ImageUser; -struct ImBuf; -struct Main; -struct MovieClip; -struct MovieClipUser; - -/* Texture creation from blender datablocks. */ -struct GPUTexture *GPU_texture_from_blender(struct Image *ima, - struct ImageUser *iuser, - struct ImBuf *ibuf, - eGPUTextureTarget target); - -struct GPUTexture *GPU_texture_from_movieclip(struct MovieClip *clip, struct MovieClipUser *cuser); /* Fluid simulation. */ void GPU_create_smoke(struct FluidModifierData *fmd, int highres); @@ -56,25 +38,9 @@ void GPU_create_smoke_coba_field(struct FluidModifierData *fmd); void GPU_create_smoke_velocity(struct FluidModifierData *fmd); /* Image updates and free. */ -void GPU_free_image(struct Image *ima); -void GPU_free_movieclip(struct MovieClip *clip); void GPU_free_smoke(struct FluidModifierData *fmd); void GPU_free_smoke_velocity(struct FluidModifierData *fmd); -void GPU_free_images(struct Main *bmain); -void GPU_free_images_anim(struct Main *bmain); -void GPU_free_images_old(struct Main *bmain); - -void GPU_paint_update_image( - struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h); -void GPU_paint_set_mipmap(struct Main *bmain, bool mipmap); - -/* Delayed free of OpenGL buffers by main thread */ -void GPU_free_unused_buffers(void); - -/* For internal use. */ -struct GPUTexture *GPU_texture_create_error(eGPUTextureTarget target); - #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 263deeaf28d..0d8954dc16c 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -52,6 +52,8 @@ bool GPU_context_local_shaders_workaround(void); bool GPU_texture_copy_workaround(void); bool GPU_crappy_amd_driver(void); +int GPU_texture_size_with_limit(int res); + bool GPU_mem_stats_supported(void); void GPU_mem_stats_get(int *totalmem, int *freemem); diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index 8d50330ac93..a71b44507ba 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -87,6 +87,7 @@ bool GPU_depth_mask_get(void); void GPU_stencil_mask(uint stencil); void GPU_unpack_row_length_set(uint len); void GPU_clip_distances(int enabled_len); +bool GPU_mipmap_enabled(void); void GPU_flush(void); void GPU_finish(void); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 31b8e6c9b6a..1fbcfd41dec 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -233,6 +233,8 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint bu GPUTexture *GPU_texture_create_compressed( int w, int h, int miplen, eGPUTextureFormat format, const void *data); +GPUTexture *GPU_texture_create_error(int dimension, bool array); + void GPU_texture_add_mipmap(GPUTexture *tex, eGPUDataFormat gpu_data_format, int miplvl, diff --git a/source/blender/gpu/intern/gpu_extensions.cc b/source/blender/gpu/intern/gpu_extensions.cc index a9ab25cbb41..32c1bf6e2d3 100644 --- a/source/blender/gpu/intern/gpu_extensions.cc +++ b/source/blender/gpu/intern/gpu_extensions.cc @@ -31,6 +31,8 @@ #include "BKE_global.h" #include "MEM_guardedalloc.h" +#include "DNA_userdef_types.h" + #include "GPU_extensions.h" #include "GPU_framebuffer.h" #include "GPU_glew.h" @@ -239,6 +241,13 @@ bool GPU_crappy_amd_driver(void) return GG.broken_amd_driver; } +int GPU_texture_size_with_limit(int res) +{ + int size = GPU_max_texture_size(); + int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size; + return min_ii(reslimit, res); +} + void gpu_extensions_init(void) { /* during 2.8 development each platform has its own OpenGL minimum requirements diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c index a0bd607e624..9c0692b76e2 100644 --- a/source/blender/gpu/intern/gpu_shader_builtin.c +++ b/source/blender/gpu/intern/gpu_shader_builtin.c @@ -153,7 +153,6 @@ const struct GPUShaderConfigData GPU_shader_cfg_data[GPU_SHADER_CFG_LEN] = { /* cache of built-in shaders (each is created on first use) */ static GPUShader *builtin_shaders[GPU_SHADER_CFG_LEN][GPU_SHADER_BUILTIN_LEN] = {{NULL}}; -static int g_shader_builtin_srgb_transform = 0; typedef struct { const char *vert; diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc index d52da70be42..794c7a3eb97 100644 --- a/source/blender/gpu/intern/gpu_state.cc +++ b/source/blender/gpu/intern/gpu_state.cc @@ -268,6 +268,12 @@ void GPU_clip_distances(int distances_new) distances_enabled = distances_new; } +bool GPU_mipmap_enabled(void) +{ + /* TODO(fclem) this used to be a userdef option. */ + return true; +} + /** \name GPU Push/Pop State * \{ */ diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index db9d961e2e3..7237cbd8999 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -1118,15 +1118,15 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint return tex; } -static GLenum convert_target_to_gl(eGPUTextureTarget target) -{ - switch (target) { - case TEXTARGET_2D: - return GL_TEXTURE_2D; - case TEXTARGET_2D_ARRAY: - return GL_TEXTURE_2D_ARRAY; - case TEXTARGET_TILE_MAPPING: - return GL_TEXTURE_1D_ARRAY; +static GLenum convert_target_to_gl(int dimension, bool is_array) +{ + switch (dimension) { + case 1: + return is_array ? GL_TEXTURE_1D : GL_TEXTURE_1D_ARRAY; + case 2: + return is_array ? GL_TEXTURE_2D : GL_TEXTURE_2D_ARRAY; + case 3: + return GL_TEXTURE_3D; default: BLI_assert(0); return GL_TEXTURE_2D; @@ -1134,9 +1134,9 @@ static GLenum convert_target_to_gl(eGPUTextureTarget target) } /* Create an error texture that will bind an invalid texture (pink) at draw time. */ -GPUTexture *GPU_texture_create_error(eGPUTextureTarget target) +GPUTexture *GPU_texture_create_error(int dimension, bool is_array) { - GLenum textarget = convert_target_to_gl(target); + GLenum textarget = convert_target_to_gl(dimension, is_array); GPUTexture *tex = (GPUTexture *)MEM_callocN(sizeof(GPUTexture), __func__); tex->bindcode = 0; diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index cad0be659ec..cf637a06405 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -23,6 +23,7 @@ set(INC ../blenkernel ../blenlib ../blenloader + ../gpu ../makesdna ../makesrna ../../../intern/guardedalloc @@ -63,6 +64,7 @@ set(SRC intern/thumbs_blend.c intern/thumbs_font.c intern/util.c + intern/util_gpu.c intern/writeimage.c IMB_colormanagement.h diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 478297e61b2..089174f8d5a 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -90,6 +90,12 @@ struct Stereo3dFormat; /** * + * \attention defined in GPU_texture.h + */ +struct GPUTexture; + +/** + * * \attention Defined in allocimbuf.c */ void IMB_init(void); @@ -729,6 +735,24 @@ const char *IMB_ffmpeg_last_error(void); /** * + * \attention defined in util_gpu.c + */ +void IMB_gpu_get_format(const struct ImBuf *ibuf, + bool high_bitdepth, + uint *r_data_format, + uint *r_texture_format); +void *IMB_gpu_get_data(const struct ImBuf *ibuf, + const bool do_rescale, + const int rescale_size[2], + const bool compress_as_srgb, + const bool store_premultiplied, + bool *r_freedata); +struct GPUTexture *IMB_create_gpu_texture(struct ImBuf *ibuf, + bool use_high_bitdepth, + bool use_premult); + +/** + * * \attention defined in stereoimbuf.c */ void IMB_stereo3d_write_dimensions(const char mode, diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c new file mode 100644 index 00000000000..f150b2bf65e --- /dev/null +++ b/source/blender/imbuf/intern/util_gpu.c @@ -0,0 +1,213 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * util.c + */ + +/** \file + * \ingroup imbuf + */ + +#include "imbuf.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" +#include "MEM_guardedalloc.h" + +#include "BKE_global.h" + +#include "GPU_extensions.h" +#include "GPU_texture.h" + +#include "IMB_colormanagement.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +/* gpu ibuf utils */ + +void IMB_gpu_get_format(const ImBuf *ibuf, + bool high_bitdepth, + uint *r_data_format /* eGPUDataFormat */, + uint *r_texture_format /* eGPUTextureFormat */) +{ + const bool float_rect = (ibuf->rect_float != NULL); + const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) && + !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)); + high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth); + + *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE; + + if (float_rect) { + *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F; + } + else { + *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8; + } +} + +/* Return false if no suitable format was found. */ +#ifdef WITH_DDS +static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format) +{ + /* For DDS we only support data, scene linear and sRGB. Converting to + * different colorspace would break the compression. */ + const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) && + !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)); + + if (ibuf->dds_data.fourcc == FOURCC_DXT1) { + *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT1 : GPU_RGBA8_DXT1; + } + else if (ibuf->dds_data.fourcc == FOURCC_DXT3) { + *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT3 : GPU_RGBA8_DXT3; + } + else if (ibuf->dds_data.fourcc == FOURCC_DXT5) { + *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT5 : GPU_RGBA8_DXT5; + } + else { + return false; + } + return true; +} +#endif + +/** + * Apply colormanagement and scale buffer if needed. + * *r_freedata is set to true if the returned buffer need to be manually freed. + **/ +void *IMB_gpu_get_data(const ImBuf *ibuf, + const bool do_rescale, + const int rescale_size[2], + const bool compress_as_srgb, + const bool store_premultiplied, + bool *r_freedata) +{ + const bool is_float_rect = (ibuf->rect_float != NULL); + void *data_rect = (is_float_rect) ? (void *)ibuf->rect_float : (void *)ibuf->rect; + + if (is_float_rect) { + /* Float image is already in scene linear colorspace or non-color data by + * convention, no colorspace conversion needed. But we do require 4 channels + * currently. */ + if (ibuf->channels != 4 || !store_premultiplied) { + data_rect = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__); + *r_freedata = true; + + if (data_rect == NULL) { + return NULL; + } + + IMB_colormanagement_imbuf_to_float_texture( + (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied); + } + } + else { + /* Byte image is in original colorspace from the file. If the file is sRGB + * scene linear, or non-color data no conversion is needed. Otherwise we + * compress as scene linear + sRGB transfer function to avoid precision loss + * in common cases. + * + * We must also convert to premultiplied for correct texture interpolation + * and consistency with float images. */ + if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) { + data_rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__); + *r_freedata = true; + + if (data_rect == NULL) { + return NULL; + } + + /* Texture storage of images is defined by the alpha mode of the image. The + * downside of this is that there can be artifacts near alpha edges. However, + * this allows us to use sRGB texture formats and preserves color values in + * zero alpha areas, and appears generally closer to what game engines that we + * want to be compatible with do. */ + IMB_colormanagement_imbuf_to_byte_texture( + (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied); + } + } + + if (do_rescale) { + uint *rect = (is_float_rect) ? NULL : (uint *)data_rect; + float *rect_float = (is_float_rect) ? (float *)data_rect : NULL; + + ImBuf *scale_ibuf = IMB_allocFromBuffer(rect, rect_float, ibuf->x, ibuf->y, 4); + IMB_scaleImBuf(scale_ibuf, UNPACK2(rescale_size)); + + data_rect = (is_float_rect) ? (void *)scale_ibuf->rect_float : (void *)scale_ibuf->rect; + *r_freedata = true; + /* Steal the rescaled buffer to avoid double free. */ + scale_ibuf->rect_float = NULL; + scale_ibuf->rect = NULL; + IMB_freeImBuf(scale_ibuf); + } + return data_rect; +} + +GPUTexture *IMB_create_gpu_texture(ImBuf *ibuf, bool use_high_bitdepth, bool use_premult) +{ + GPUTexture *tex = NULL; + int size[2] = {GPU_texture_size_with_limit(ibuf->x), GPU_texture_size_with_limit(ibuf->y)}; + bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]); + +#ifdef WITH_DDS + if (ibuf->ftype == IMB_FTYPE_DDS) { + eGPUTextureFormat compressed_format; + if (!IMB_gpu_get_compressed_format(ibuf, &compressed_format)) { + fprintf(stderr, "Unable to find a suitable DXT compression,"); + } + else if (do_rescale) { + fprintf(stderr, "Unable to load DXT image resolution,"); + } + else if (!is_power_of_2_i(ibuf->x) || !is_power_of_2_i(ibuf->y)) { + fprintf(stderr, "Unable to load non-power-of-two DXT image resolution,"); + } + else { + tex = GPU_texture_create_compressed( + ibuf->x, ibuf->y, ibuf->dds_data.nummipmaps, compressed_format, ibuf->dds_data.data); + + if (tex != NULL) { + return tex; + } + else { + fprintf(stderr, "ST3C support not found,"); + } + } + /* Fallback to uncompressed texture. */ + fprintf(stderr, " falling back to uncompressed.\n"); + } +#endif + + eGPUDataFormat data_format; + eGPUTextureFormat tex_format; + IMB_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format); + + const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8); + bool freebuf = false; + + void *data = IMB_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf); + + /* Create Texture. */ + tex = GPU_texture_create_nD(UNPACK2(size), 0, 2, data, tex_format, data_format, 0, false, NULL); + + GPU_texture_anisotropic_filter(tex, true); + + if (freebuf) { + MEM_freeN(data); + } + + return tex; +}
\ No newline at end of file diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index e0bcdc504fb..23f9f70e470 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -200,7 +200,7 @@ static void rna_Image_gpu_texture_update(Main *UNUSED(bmain), Image *ima = (Image *)ptr->owner_id; if (!G.background) { - GPU_free_image(ima); + BKE_image_free_gputextures(ima); } WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id); @@ -516,7 +516,7 @@ static void rna_Image_pixels_set(PointerRNA *ptr, const float *values) ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_MIPMAP_INVALID; BKE_image_mark_dirty(ima, ibuf); if (!G.background) { - GPU_free_image(ima); + BKE_image_free_gputextures(ima); } WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id); } diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index a57efbcf1b3..6f876923e52 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -220,7 +220,7 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame) BKE_imageuser_default(&iuser); iuser.framenr = frame; - GPUTexture *tex = GPU_texture_from_blender(image, &iuser, NULL, TEXTARGET_2D); + GPUTexture *tex = BKE_image_get_gpu_texture(image, &iuser, NULL); if (tex == NULL) { BKE_reportf(reports, RPT_ERROR, "Failed to load image texture '%s'", image->id.name + 2); @@ -246,7 +246,7 @@ static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame) static void rna_Image_gl_free(Image *image) { - GPU_free_image(image); + BKE_image_free_gputextures(image); /* remove the nocollect flag, image is available for garbage collection again */ image->flag &= ~IMA_NOCOLLECT; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b13b9f5c11d..490bcb88f22 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -179,6 +179,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = { # include "BKE_blender.h" # include "BKE_global.h" # include "BKE_idprop.h" +# include "BKE_image.h" # include "BKE_main.h" # include "BKE_mesh_runtime.h" # include "BKE_paint.h" @@ -371,7 +372,7 @@ static void rna_userdef_anisotropic_update(Main *bmain, Scene *scene, PointerRNA static void rna_userdef_gl_texture_limit_update(Main *bmain, Scene *scene, PointerRNA *ptr) { - GPU_free_images(bmain); + BKE_image_free_all_gputextures(bmain); rna_userdef_update(bmain, scene, ptr); } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 16454e473cc..43364c84ec6 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -999,7 +999,7 @@ void wm_draw_update(bContext *C) wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; - GPU_free_unused_buffers(); + BKE_image_free_unused_gpu_textures(); for (win = wm->windows.first; win; win = win->next) { #ifdef WIN32 diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index a757b0fabd2..a15ca81ddef 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -59,6 +59,7 @@ #include "BKE_font.h" #include "BKE_global.h" #include "BKE_icons.h" +#include "BKE_image.h" #include "BKE_keyconfig.h" #include "BKE_lib_remap.h" #include "BKE_main.h" @@ -575,7 +576,7 @@ void WM_exit_ex(bContext *C, const bool do_python) BKE_subdiv_exit(); if (opengl_is_init) { - GPU_free_unused_buffers(); + BKE_image_free_unused_gpu_textures(); } BKE_blender_free(); /* blender.c, does entire library and spacetypes */ |