Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2020-07-29 19:13:19 +0300
committerClément Foucault <foucault.clem@gmail.com>2020-07-30 00:06:37 +0300
commit5f6fb5bb41ed0057f0e2f0ccded717fbf04e55e2 (patch)
tree94ce813b25b5bf766136e694f893517e93432bf7
parent7e8d4937307e0be3ab4587c58c49f16211466987 (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`.
-rw-r--r--source/blender/blenkernel/BKE_image.h29
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h5
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/image.c3
-rw-r--r--source/blender/blenkernel/intern/image_gpu.c (renamed from source/blender/gpu/intern/gpu_texture_image.c)642
-rw-r--r--source/blender/blenkernel/intern/movieclip.c81
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_image.c8
-rw-r--r--source/blender/draw/engines/overlay/overlay_paint.c4
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c6
-rw-r--r--source/blender/draw/intern/draw_manager_data.c20
-rw-r--r--source/blender/editors/object/object_bake.c4
-rw-r--r--source/blender/editors/object/object_bake_api.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c4
-rw-r--r--source/blender/editors/space_image/image_undo.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c5
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_draw.h34
-rw-r--r--source/blender/gpu/GPU_extensions.h2
-rw-r--r--source/blender/gpu/GPU_state.h1
-rw-r--r--source/blender/gpu/GPU_texture.h2
-rw-r--r--source/blender/gpu/intern/gpu_extensions.cc9
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c1
-rw-r--r--source/blender/gpu/intern/gpu_state.cc6
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc22
-rw-r--r--source/blender/imbuf/CMakeLists.txt2
-rw-r--r--source/blender/imbuf/IMB_imbuf.h24
-rw-r--r--source/blender/imbuf/intern/util_gpu.c213
-rw-r--r--source/blender/makesrna/intern/rna_image.c4
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c3
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c2
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c3
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 */