Fix T90825: Performance texture painting with limited scale.

Improve texture painting/uv editing performance when limited scale is active.
Cause of the slow down is that the image editor draws the image in maximum resolution,
but the 3d viewport uses the limited scale. The variation reuses the same GPU texture
and needed to be uploaded/scaled twice to the GPU.

This patch will adds texture slots that can hold the scaled down and the maximum
resolution image. This would allow better cache hits and reuse of existing caches.

Maximum resolution textures are reused for limited scale when they fit to reduce memory
and CPU footprint.

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D12388
This commit is contained in:
Jeroen Bakker 2021-09-08 09:52:06 +02:00 committed by Jeroen Bakker
parent 54f5c174a8
commit 2b2d427bba
Notes: blender-bot 2023-02-14 06:45:14 +01:00
Referenced by issue #92016, Crash when undo the operator which contains load img action
Referenced by issue #91501, Crash using Undo after Append a file
Referenced by issue #91294, Draw: Crash on undo after adding new texture
Referenced by issue #90825, Viewport Texture Size Limit causes lags when uv editing with textured viewport on the side
4 changed files with 220 additions and 101 deletions

View File

@ -155,7 +155,9 @@ static void image_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
image_dst->gputexture[i][eye] = NULL;
for (int slot = 0; slot < IMA_TEXTURE_RESOLUTION_LEN; slot++) {
image_dst->gputexture[i][eye][slot] = NULL;
}
}
}
@ -208,9 +210,11 @@ static void image_foreach_cache(ID *id,
for (int eye = 0; eye < 2; eye++) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
key.offset_in_ID = offsetof(Image, gputexture[a][eye]);
key.cache_v = image->gputexture[a][eye];
function_callback(id, &key, (void **)&image->gputexture[a][eye], 0, user_data);
for (int slot = 0; slot < IMA_TEXTURE_RESOLUTION_LEN; slot++) {
key.offset_in_ID = offsetof(Image, gputexture[a][eye][slot]);
key.cache_v = image->gputexture[a][eye];
function_callback(id, &key, (void **)&image->gputexture[a][eye][slot], 0, user_data);
}
}
}
@ -239,7 +243,9 @@ static void image_blend_write(BlendWriter *writer, ID *id, const void *id_addres
BLI_listbase_clear(&ima->gpu_refresh_areas);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
ima->gputexture[i][j] = NULL;
for (int slot = 0; slot < IMA_TEXTURE_RESOLUTION_LEN; slot++) {
ima->gputexture[i][j][slot] = NULL;
}
}
}
@ -677,8 +683,10 @@ bool BKE_image_has_opengl_texture(Image *ima)
{
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
if (ima->gputexture[i][eye] != NULL) {
return true;
for (int slot = 0; slot < IMA_TEXTURE_RESOLUTION_LEN; slot++) {
if (ima->gputexture[i][eye][slot] != NULL) {
return true;
}
}
}
}
@ -3531,9 +3539,11 @@ static void image_free_tile(Image *ima, ImageTile *tile)
}
for (int eye = 0; eye < 2; eye++) {
if (ima->gputexture[i][eye] != NULL) {
GPU_texture_free(ima->gputexture[i][eye]);
ima->gputexture[i][eye] = NULL;
for (int slot = 0; slot < IMA_TEXTURE_RESOLUTION_LEN; slot++) {
if (ima->gputexture[i][eye][slot] != NULL) {
GPU_texture_free(ima->gputexture[i][eye][slot]);
ima->gputexture[i][eye][slot] = NULL;
}
}
}
}
@ -3801,14 +3811,16 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la
}
for (int eye = 0; eye < 2; eye++) {
/* Reallocate GPU tile array. */
if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != NULL) {
GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]);
ima->gputexture[TEXTARGET_2D_ARRAY][eye] = NULL;
}
if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != NULL) {
GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]);
ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = NULL;
for (int slot = 0; slot < IMA_TEXTURE_RESOLUTION_LEN; slot++) {
/* Reallocate GPU tile array. */
if (ima->gputexture[TEXTARGET_2D_ARRAY][eye][slot] != NULL) {
GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye][slot]);
ima->gputexture[TEXTARGET_2D_ARRAY][eye][slot] = NULL;
}
if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye][slot] != NULL) {
GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye][slot]);
ima->gputexture[TEXTARGET_TILE_MAPPING][eye][slot] = NULL;
}
}
}
@ -3863,14 +3875,17 @@ void BKE_image_reassign_tile(struct Image *ima, ImageTile *tile, int new_tile_nu
}
for (int eye = 0; eye < 2; eye++) {
/* Reallocate GPU tile array. */
if (ima->gputexture[TEXTARGET_2D_ARRAY][eye] != NULL) {
GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye]);
ima->gputexture[TEXTARGET_2D_ARRAY][eye] = NULL;
}
if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye] != NULL) {
GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye]);
ima->gputexture[TEXTARGET_TILE_MAPPING][eye] = NULL;
for (int slot = 0; slot < IMA_TEXTURE_RESOLUTION_LEN; slot++) {
/* Reallocate GPU tile array. */
if (ima->gputexture[TEXTARGET_2D_ARRAY][eye][slot] != NULL) {
GPU_texture_free(ima->gputexture[TEXTARGET_2D_ARRAY][eye][slot]);
ima->gputexture[TEXTARGET_2D_ARRAY][eye][slot] = NULL;
}
if (ima->gputexture[TEXTARGET_TILE_MAPPING][eye][slot] != NULL) {
GPU_texture_free(ima->gputexture[TEXTARGET_TILE_MAPPING][eye][slot]);
ima->gputexture[TEXTARGET_TILE_MAPPING][eye][slot] = NULL;
}
}
}
}

View File

@ -49,6 +49,7 @@
/* Prototypes. */
static void gpu_free_unused_buffers(void);
static void image_free_gpu(Image *ima, const bool immediate);
static void image_free_gpu_limited_scale(Image *ima);
static void image_update_gputexture_ex(
Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h);
@ -97,9 +98,11 @@ static int smaller_power_of_2_limit(int num, bool limit_gl_texture_size)
return power_of_2_min_i(GPU_texture_size_with_limit(num, limit_gl_texture_size));
}
static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
static GPUTexture *gpu_texture_create_tile_mapping(
Image *ima, const int multiview_eye, const eImageTextureResolution texture_resolution)
{
GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye];
const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye][resolution];
if (tilearray == NULL) {
return 0;
@ -121,13 +124,14 @@ static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multivi
}
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
int i = tile->tile_number - 1001;
data[4 * i] = tile->runtime.tilearray_layer;
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
data[4 * i] = tile_runtime->tilearray_layer;
float *tile_info = &data[4 * width + 4 * i];
tile_info[0] = tile->runtime.tilearray_offset[0] / array_w;
tile_info[1] = tile->runtime.tilearray_offset[1] / array_h;
tile_info[2] = tile->runtime.tilearray_size[0] / array_w;
tile_info[3] = tile->runtime.tilearray_size[1] / array_h;
tile_info[0] = tile_runtime->tilearray_offset[0] / array_w;
tile_info[1] = tile_runtime->tilearray_offset[1] / array_h;
tile_info[2] = tile_runtime->tilearray_size[0] / array_w;
tile_info[3] = tile_runtime->tilearray_size[1] / array_h;
}
GPUTexture *tex = GPU_texture_create_1d_array(ima->id.name + 2, width, 2, 1, GPU_RGBA32F, data);
@ -152,9 +156,12 @@ static int compare_packtile(const void *a, const void *b)
return tile_a->pack_score < tile_b->pack_score;
}
static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
static GPUTexture *gpu_texture_create_tile_array(Image *ima,
ImBuf *main_ibuf,
const eImageTextureResolution texture_resolution)
{
const bool limit_gl_texture_size = (ima->gpuflag & IMA_GPU_MAX_RESOLUTION) == 0;
const bool limit_gl_texture_size = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED;
const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
int arraywidth = 0, arrayheight = 0;
ListBase boxes = {NULL};
@ -200,14 +207,15 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
LISTBASE_FOREACH (PackTile *, packtile, &packed) {
ImageTile *tile = packtile->tile;
int *tileoffset = tile->runtime.tilearray_offset;
int *tilesize = tile->runtime.tilearray_size;
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
tileoffset[0] = packtile->boxpack.x;
tileoffset[1] = packtile->boxpack.y;
tilesize[0] = packtile->boxpack.w;
tilesize[1] = packtile->boxpack.h;
tile->runtime.tilearray_layer = arraylayers;
tile_runtime->tilearray_layer = arraylayers;
}
BLI_freelistN(&packed);
@ -221,9 +229,10 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
/* Upload each tile one by one. */
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
int tilelayer = tile->runtime.tilearray_layer;
int *tileoffset = tile->runtime.tilearray_offset;
int *tilesize = tile->runtime.tilearray_size;
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int tilelayer = tile_runtime->tilearray_layer;
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
if (tilesize[0] == 0 || tilesize[1] == 0) {
continue;
@ -268,16 +277,33 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
/** \name Regular gpu texture
* \{ */
static bool image_max_resolution_texture_fits_in_limited_scale(Image *ima,
eGPUTextureTarget textarget,
const int multiview_eye)
{
BLI_assert_msg(U.glreslimit != 0,
"limited scale function called without limited scale being set.");
GPUTexture *max_resolution_texture =
ima->gputexture[textarget][multiview_eye][IMA_TEXTURE_RESOLUTION_FULL];
if (max_resolution_texture && GPU_texture_width(max_resolution_texture) <= U.glreslimit &&
GPU_texture_height(max_resolution_texture) <= U.glreslimit) {
return true;
}
return false;
}
static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
eGPUTextureTarget textarget,
const int multiview_eye)
const int multiview_eye,
const eImageTextureResolution texture_resolution)
{
const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT);
BLI_assert(in_range);
BLI_assert(multiview_eye == 0 || multiview_eye == 1);
const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
if (in_range) {
return &(ima->gputexture[textarget][multiview_eye]);
return &(ima->gputexture[textarget][multiview_eye][resolution]);
}
return NULL;
}
@ -296,6 +322,21 @@ static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget)
}
}
static void image_update_reusable_textures(Image *ima,
eGPUTextureTarget textarget,
const int multiview_eye)
{
if ((ima->gpuflag & IMA_GPU_HAS_LIMITED_SCALE_TEXTURES) == 0) {
return;
}
if (ELEM(textarget, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
if (image_max_resolution_texture_fits_in_limited_scale(ima, textarget, multiview_eye)) {
image_free_gpu_limited_scale(ima);
}
}
}
static GPUTexture *image_get_gpu_texture(Image *ima,
ImageUser *iuser,
ImBuf *ibuf,
@ -315,24 +356,17 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
short requested_pass = iuser ? iuser->pass : 0;
short requested_layer = iuser ? iuser->layer : 0;
short requested_view = iuser ? iuser->multi_index : 0;
const bool limit_resolution = U.glreslimit != 0 &&
((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) ||
(iuser == NULL));
short requested_gpu_flags = limit_resolution ? 0 : IMA_GPU_MAX_RESOLUTION;
#define GPU_FLAGS_TO_CHECK (IMA_GPU_MAX_RESOLUTION)
/* There is room for 2 multiview textures. When a higher number is requested we should always
* target the first view slot. This is fine as multi view images aren't used together. */
if (requested_view < 2) {
requested_view = 0;
}
if (ima->gpu_pass != requested_pass || ima->gpu_layer != requested_layer ||
ima->gpu_view != requested_view ||
((ima->gpuflag & GPU_FLAGS_TO_CHECK) != requested_gpu_flags)) {
ima->gpu_view != requested_view) {
ima->gpu_pass = requested_pass;
ima->gpu_layer = requested_layer;
ima->gpu_view = requested_view;
ima->gpuflag &= ~GPU_FLAGS_TO_CHECK;
ima->gpuflag |= requested_gpu_flags | IMA_GPU_REFRESH;
ima->gpuflag |= IMA_GPU_REFRESH;
}
#undef GPU_FLAGS_TO_CHECK
@ -369,7 +403,14 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
if (current_view >= 2) {
current_view = 0;
}
GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view);
const bool limit_resolution = U.glreslimit != 0 &&
((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) ||
(iuser == NULL)) &&
((ima->gpuflag & IMA_GPU_REUSE_MAX_RESOLUTION) == 0);
const eImageTextureResolution texture_resolution = limit_resolution ?
IMA_TEXTURE_RESOLUTION_LIMITED :
IMA_TEXTURE_RESOLUTION_FULL;
GPUTexture **tex = get_image_gpu_texture_ptr(ima, textarget, current_view, texture_resolution);
if (*tex) {
return *tex;
}
@ -392,22 +433,19 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
if (textarget == TEXTARGET_2D_ARRAY) {
*tex = gpu_texture_create_tile_array(ima, ibuf_intern);
*tex = gpu_texture_create_tile_array(ima, ibuf_intern, texture_resolution);
}
else if (textarget == TEXTARGET_TILE_MAPPING) {
*tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
*tex = gpu_texture_create_tile_mapping(
ima, iuser ? iuser->multiview_eye : 0, texture_resolution);
}
else {
const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH);
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima,
ibuf_intern);
const bool limit_gl_texture_size = (ima->gpuflag & IMA_GPU_MAX_RESOLUTION) == 0;
*tex = IMB_create_gpu_texture(ima->id.name + 2,
ibuf_intern,
use_high_bitdepth,
store_premultiplied,
limit_gl_texture_size);
*tex = IMB_create_gpu_texture(
ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied, limit_resolution);
if (*tex) {
GPU_texture_wrap_mode(*tex, true, false);
@ -425,6 +463,20 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
}
switch (texture_resolution) {
case IMA_TEXTURE_RESOLUTION_LIMITED:
ima->gpuflag |= IMA_GPU_HAS_LIMITED_SCALE_TEXTURES;
break;
case IMA_TEXTURE_RESOLUTION_FULL:
image_update_reusable_textures(ima, textarget, current_view);
break;
case IMA_TEXTURE_RESOLUTION_LEN:
BLI_assert_unreachable();
break;
}
/* if `ibuf` was given, we don't own the `ibuf_intern` */
if (ibuf == NULL) {
BKE_image_release_ibuf(ima, ibuf_intern, NULL);
@ -497,22 +549,39 @@ 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);
}
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
if (ima->gputexture[i][eye][resolution] != NULL) {
if (immediate) {
GPU_texture_free(ima->gputexture[i][eye][resolution]);
}
else {
BLI_mutex_lock(&gpu_texture_queue_mutex);
BLI_linklist_prepend(&gpu_texture_free_queue, ima->gputexture[i][eye][resolution]);
BLI_mutex_unlock(&gpu_texture_queue_mutex);
}
ima->gputexture[i][eye] = NULL;
ima->gputexture[i][eye][resolution] = NULL;
}
}
}
}
ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_HAS_LIMITED_SCALE_TEXTURES);
}
static void image_free_gpu_limited_scale(Image *ima)
{
const eImageTextureResolution resolution = IMA_TEXTURE_RESOLUTION_LIMITED;
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
if (ima->gputexture[i][eye][resolution] != NULL) {
GPU_texture_free(ima->gputexture[i][eye][resolution]);
ima->gputexture[i][eye][resolution] = NULL;
}
}
}
ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_HAS_LIMITED_SCALE_TEXTURES);
}
void BKE_image_free_gputextures(Image *ima)
@ -689,12 +758,21 @@ static void gpu_texture_update_unscaled(GPUTexture *tex,
GPU_unpack_row_length_set(0);
}
static void gpu_texture_update_from_ibuf(
GPUTexture *tex, Image *ima, ImBuf *ibuf, ImageTile *tile, int x, int y, int w, int h)
static void gpu_texture_update_from_ibuf(GPUTexture *tex,
Image *ima,
ImBuf *ibuf,
ImageTile *tile,
int x,
int y,
int w,
int h,
eImageTextureResolution texture_resolution)
{
const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
bool scaled;
if (tile != NULL) {
int *tilesize = tile->runtime.tilearray_size;
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tilesize = tile_runtime->tilearray_size;
scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
}
else {
@ -758,9 +836,10 @@ static void gpu_texture_update_from_ibuf(
if (scaled) {
/* Slower update where we first have to scale the input pixels. */
if (tile != NULL) {
int *tileoffset = tile->runtime.tilearray_offset;
int *tilesize = tile->runtime.tilearray_size;
int tilelayer = tile->runtime.tilearray_layer;
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
int tilelayer = tile_runtime->tilearray_layer;
gpu_texture_update_scaled(
tex, rect, rect_float, ibuf->x, ibuf->y, x, y, tilelayer, tileoffset, tilesize, w, h);
}
@ -772,8 +851,9 @@ static void gpu_texture_update_from_ibuf(
else {
/* Fast update at same resolution. */
if (tile != NULL) {
int *tileoffset = tile->runtime.tilearray_offset;
int tilelayer = tile->runtime.tilearray_layer;
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tileoffset = tile_runtime->tilearray_offset;
int tilelayer = tile_runtime->tilearray_layer;
gpu_texture_update_unscaled(
tex, rect, rect_float, x, y, tilelayer, tileoffset, w, h, tex_stride, tex_offset);
}
@ -804,16 +884,20 @@ static void gpu_texture_update_from_ibuf(
static void image_update_gputexture_ex(
Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h)
{
GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
/* Check if we need to update the main gputexture. */
if (tex != NULL && tile == ima->tiles.first) {
gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h);
}
const int eye = 0;
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye][resolution];
eImageTextureResolution texture_resolution = resolution;
/* Check if we need to update the main gputexture. */
if (tex != NULL && tile == ima->tiles.first) {
gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h, texture_resolution);
}
/* Check if we need to update the array gputexture. */
tex = ima->gputexture[TEXTARGET_2D_ARRAY][0];
if (tex != NULL) {
gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
/* Check if we need to update the array gputexture. */
tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution];
if (tex != NULL) {
gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h, texture_resolution);
}
}
}
@ -917,12 +1001,14 @@ void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
if (BKE_image_has_opengl_texture(ima)) {
if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
for (int eye = 0; eye < 2; eye++) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
if (ELEM(a, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
GPUTexture *tex = ima->gputexture[a][eye];
if (tex != NULL) {
GPU_texture_mipmap_mode(tex, mipmap, true);
for (int a = 0; a < TEXTARGET_COUNT; a++) {
if (ELEM(a, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
for (int eye = 0; eye < 2; eye++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
GPUTexture *tex = ima->gputexture[a][eye][resolution];
if (tex != NULL) {
GPU_texture_mipmap_mode(tex, mipmap, true);
}
}
}
}

View File

@ -94,11 +94,17 @@ typedef struct RenderSlot {
struct RenderResult *render;
} RenderSlot;
typedef struct ImageTile_Runtime {
typedef struct ImageTile_RuntimeTextureSlot {
int tilearray_layer;
int _pad;
int tilearray_offset[2];
int tilearray_size[2];
} ImageTile_RuntimeTextureSlot;
typedef struct ImageTile_Runtime {
/* Data per `eImageTextureResolution`.
* Should match `IMA_TEXTURE_RESOLUTION_LEN` */
ImageTile_RuntimeTextureSlot slots[2];
} ImageTile_Runtime;
typedef struct ImageTile {
@ -132,6 +138,15 @@ typedef enum eGPUTextureTarget {
TEXTARGET_COUNT,
} eGPUTextureTarget;
/* Resolution variations that can be cached for an image. */
typedef enum eImageTextureResolution {
IMA_TEXTURE_RESOLUTION_FULL = 0,
IMA_TEXTURE_RESOLUTION_LIMITED,
/* Not an option, but holds the number of options defined for this struct. */
IMA_TEXTURE_RESOLUTION_LEN
} eImageTextureResolution;
typedef struct Image {
ID id;
@ -140,8 +155,8 @@ typedef struct Image {
/** Not written in file. */
struct MovieCache *cache;
/** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes. */
struct GPUTexture *gputexture[3][2];
/** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes, 2 = IMA_TEXTURE_RESOLUTION_LEN. */
struct GPUTexture *gputexture[3][2][2];
/* sources from: */
ListBase anims;
@ -233,8 +248,11 @@ enum {
IMA_GPU_PARTIAL_REFRESH = (1 << 1),
/** All mipmap levels in OpenGL texture set? */
IMA_GPU_MIPMAP_COMPLETE = (1 << 2),
/** Current texture resolution won't be limited by the GL Texture Limit user preference. */
IMA_GPU_MAX_RESOLUTION = (1 << 3),
/* Reuse the max resolution textures as they fit in the limited scale. */
IMA_GPU_REUSE_MAX_RESOLUTION = (1 << 3),
/* Has any limited scale textures been allocated.
* Adds additional checks to reuse max resolution images when they fit inside limited scale. */
IMA_GPU_HAS_LIMITED_SCALE_TEXTURES = (1 << 4),
};
/* Image.source, where the image comes from */

View File

@ -404,7 +404,7 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
static int rna_Image_bindcode_get(PointerRNA *ptr)
{
Image *ima = (Image *)ptr->data;
GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0][IMA_TEXTURE_RESOLUTION_FULL];
return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
}