diff --git a/data/darktableconfig.xml.in b/data/darktableconfig.xml.in
index 8e106a6e1557..e9c8f0c62d6f 100644
--- a/data/darktableconfig.xml.in
+++ b/data/darktableconfig.xml.in
@@ -1349,6 +1349,8 @@
+
+
@@ -1368,6 +1370,8 @@
+
+
@@ -1408,6 +1412,8 @@
+
+
never
diff --git a/src/common/mipmap_cache.c b/src/common/mipmap_cache.c
index 19cc83122ca4..aa528352f4ed 100644
--- a/src/common/mipmap_cache.c
+++ b/src/common/mipmap_cache.c
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
- Copyright (C) 2011-2025 darktable developers.
+ Copyright (C) 2011-2026 darktable developers.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -466,7 +466,7 @@ static void _mipmap_cache_allocate_dynamic(void *data, dt_cache_entry_t *entry)
// alloc mere minimum for the header + broken image buffer:
if(!dsc)
{
- if(mip == DT_MIPMAP_8)
+ if(mip == DT_MIPMAP_LDR_MAX)
{
int imgfw= 0, imgfh= 0;
// be sure that we have the right size values
@@ -516,10 +516,10 @@ static void _mipmap_cache_allocate_dynamic(void *data, dt_cache_entry_t *entry)
assert(dsc->size >= sizeof(*dsc));
int loaded_from_disk = 0;
- if(mip < DT_MIPMAP_F)
+ if(mip <= DT_MIPMAP_LDR_MAX)
{
- if(cache->cachedir[0] && ((dt_conf_get_bool("cache_disk_backend") && mip < DT_MIPMAP_8)
- || (dt_conf_get_bool("cache_disk_backend_full") && mip == DT_MIPMAP_8)))
+ if(cache->cachedir[0] && ((dt_conf_get_bool("cache_disk_backend") && mip < DT_MIPMAP_LDR_MAX)
+ || (dt_conf_get_bool("cache_disk_backend_full") && mip == DT_MIPMAP_LDR_MAX)))
{
// try and load from disk, if successful set flag
char filename[PATH_MAX] = {0};
@@ -576,7 +576,7 @@ static void _mipmap_cache_allocate_dynamic(void *data, dt_cache_entry_t *entry)
// to make sure quota is meaningful.
if(mip >= DT_MIPMAP_F)
entry->cost = 1;
- else if(mip == DT_MIPMAP_8)
+ else if(mip == DT_MIPMAP_LDR_MAX)
entry->cost = entry->data_size;
else
entry->cost = cache->buffer_size[mip];
@@ -603,7 +603,7 @@ static void _mipmap_cache_deallocate_dynamic(void *data, dt_cache_entry_t *entry
{
dt_mipmap_cache_t *cache = (dt_mipmap_cache_t *)data;
const dt_mipmap_size_t mip = _get_size(entry->key);
- if(mip < DT_MIPMAP_F)
+ if(mip <= DT_MIPMAP_LDR_MAX)
{
dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)entry->data;
// don't write skulls:
@@ -613,8 +613,8 @@ static void _mipmap_cache_deallocate_dynamic(void *data, dt_cache_entry_t *entry
{
_mipmap_cache_unlink_ondisk_thumbnail(data, _get_imgid(entry->key), mip);
}
- else if(cache->cachedir[0] && ((dt_conf_get_bool("cache_disk_backend") && mip < DT_MIPMAP_8)
- || (dt_conf_get_bool("cache_disk_backend_full") && mip == DT_MIPMAP_8)))
+ else if(cache->cachedir[0] && ((dt_conf_get_bool("cache_disk_backend") && mip < DT_MIPMAP_LDR_MAX)
+ || (dt_conf_get_bool("cache_disk_backend_full") && mip == DT_MIPMAP_LDR_MAX)))
{
// serialize to disk
char filename[PATH_MAX] = {0};
@@ -705,25 +705,26 @@ void dt_mipmap_cache_init()
{ 1920, 1200 }, // mip4 - covers 1080p and 1600x1200
{ 2560, 1600 }, // mip5 - covers 2560x1440
{ 4096, 2560 }, // mip6 - covers 4K and UHD
- { 5120, 3200 }, // mip7 - covers 5120x2880 panels
- { 999999999, 999999999 }, // mip8 - used for full preview at full size
+ { 5120, 3200 }, // mip7 - covers 5K
+ { 6144, 3456 }, // mip8 - covers 6K
+ { 7680, 4320 }, // mip9 - covers 8K
+ { 999999999, 999999999 }, // mip10 - used for full preview at full size
};
- // Set mipf to mip2 size as at most the user will be using an 8K screen and
- // have a preview that's ~4x smaller
+ // Set mipf to mip3 size, which is ~4x smaller than a 6K screen screen
const char *preview_downsample = dt_conf_get_string_const("preview_downsampling");
const float downsample = (!g_strcmp0(preview_downsample, "original")) ? 1.0f
: (!g_strcmp0(preview_downsample, "to 1/2")) ? 0.5f
: (!g_strcmp0(preview_downsample, "to 1/3")) ? 1/3.0f
: 0.25f;
- cache->max_width[DT_MIPMAP_F] = mipsizes[DT_MIPMAP_2][0] * downsample;
- cache->max_height[DT_MIPMAP_F] = mipsizes[DT_MIPMAP_2][1] * downsample;
- for(int k = DT_MIPMAP_F-1; k >= 0; k--)
+ cache->max_width[DT_MIPMAP_F] = mipsizes[DT_MIPMAP_3][0] * downsample;
+ cache->max_height[DT_MIPMAP_F] = mipsizes[DT_MIPMAP_3][1] * downsample;
+ for(int k = DT_MIPMAP_LDR_MAX; k >= 0; k--)
{
cache->max_width[k] = mipsizes[k][0];
cache->max_height[k] = mipsizes[k][1];
}
- // header + buffer
- for(int k = DT_MIPMAP_F-1; k >= 0; k--)
+ // header + buffer
+ for(int k = DT_MIPMAP_LDR_MAX; k >= 0; k--)
cache->buffer_size[k] = sizeof(dt_mipmap_buffer_dsc_t)
+ (size_t)cache->max_width[k] * cache->max_height[k] * 4;
@@ -1063,7 +1064,7 @@ void dt_mipmap_cache_get_with_caller(dt_mipmap_buffer_t *buf,
const dt_imageio_retval_t ret = img ? img->load_status : DT_IMAGEIO_FILE_NOT_FOUND;
dt_image_cache_read_release(img);
dt_print(DT_DEBUG_PIPE, "[mipmap cache get] got a zero-sized ID=%d mip %d!", imgid, mip);
- if(mip < DT_MIPMAP_F)
+ if(mip <= DT_MIPMAP_LDR_MAX)
{
switch(ret)
{
@@ -1130,7 +1131,7 @@ void dt_mipmap_cache_get_with_caller(dt_mipmap_buffer_t *buf,
}
}
// couldn't find a smaller thumb, try larger ones only now (these will be slightly slower due to cairo rescaling):
- dt_mipmap_size_t max_mip = (mip >= DT_MIPMAP_F) ? mip : DT_MIPMAP_F-1;
+ dt_mipmap_size_t max_mip = (mip >= DT_MIPMAP_F) ? mip : DT_MIPMAP_LDR_MAX;
for(int k = mip+1; k <= max_mip; k++)
{
// already loaded?
@@ -1196,7 +1197,7 @@ dt_mipmap_size_t dt_mipmap_cache_get_matching_size(const int32_t width,
dt_mipmap_cache_t *cache = darktable.mipmap_cache;
dt_mipmap_size_t best = DT_MIPMAP_NONE;
assert(cache);
- for(int k = DT_MIPMAP_0; k < DT_MIPMAP_F; k++)
+ for(int k = DT_MIPMAP_0; k <= DT_MIPMAP_LDR_MAX; k++)
{
best = k;
if((cache->max_width[k] >= width) && (cache->max_height[k] >= height))
@@ -1215,6 +1216,8 @@ dt_mipmap_size_t dt_mipmap_cache_get_min_mip_from_pref(const char *value)
if(strcmp(value, "WQXGA") == 0) return DT_MIPMAP_5;
if(strcmp(value, "4K") == 0) return DT_MIPMAP_6;
if(strcmp(value, "5K") == 0) return DT_MIPMAP_7;
+ if(strcmp(value, "6K") == 0) return DT_MIPMAP_8;
+ if(strcmp(value, "8K") == 0) return DT_MIPMAP_9;
return DT_MIPMAP_NONE;
}
@@ -1223,7 +1226,7 @@ void dt_mipmap_cache_remove_at_size(const dt_imgid_t imgid,
{
dt_mipmap_cache_t *cache = darktable.mipmap_cache;
assert(cache);
- if(!cache || mip > DT_MIPMAP_8 || mip < DT_MIPMAP_0) return;
+ if(!cache || mip > DT_MIPMAP_LDR_MAX || mip < DT_MIPMAP_0) return;
// get rid of all ldr thumbnails:
const uint32_t key = _get_key(imgid, mip);
dt_cache_entry_t *entry = dt_cache_testget(&_get_cache(cache, mip)->cache, key, 'w');
@@ -1246,7 +1249,7 @@ void dt_mipmap_cache_remove_at_size(const dt_imgid_t imgid,
void dt_mipmap_cache_remove(const dt_imgid_t imgid)
{
- for(dt_mipmap_size_t k = DT_MIPMAP_0; k < DT_MIPMAP_F; k++)
+ for(dt_mipmap_size_t k = DT_MIPMAP_0; k <= DT_MIPMAP_LDR_MAX; k++)
{
dt_mipmap_cache_remove_at_size(imgid, k);
}
@@ -1266,7 +1269,7 @@ void dt_mipmap_cache_evict_at_size(const dt_imgid_t imgid,
void dt_mipmap_cache_evict(const dt_imgid_t imgid)
{
dt_mipmap_cache_t *cache = darktable.mipmap_cache;
- for(dt_mipmap_size_t k = DT_MIPMAP_0; k < DT_MIPMAP_F; k++)
+ for(dt_mipmap_size_t k = DT_MIPMAP_0; k <= DT_MIPMAP_LDR_MAX; k++)
{
const uint32_t key = _get_key(imgid, k);
@@ -1533,7 +1536,7 @@ static void _init_8(uint8_t *buf,
if(res)
{
//try to generate mip from larger mip
- for(dt_mipmap_size_t k = size + 1; k < DT_MIPMAP_F; k++)
+ for(dt_mipmap_size_t k = size + 1; k <= DT_MIPMAP_LDR_MAX; k++)
{
dt_mipmap_buffer_t tmp;
dt_mipmap_cache_get(&tmp, imgid, k, DT_MIPMAP_TESTLOCK, 'r');
@@ -1618,7 +1621,7 @@ void dt_mipmap_cache_copy_thumbnails(const dt_imgid_t dst_imgid,
&& dt_is_valid_imgid(src_imgid)
&& dt_is_valid_imgid(dst_imgid))
{
- for(dt_mipmap_size_t mip = DT_MIPMAP_0; mip < DT_MIPMAP_F; mip++)
+ for(dt_mipmap_size_t mip = DT_MIPMAP_0; mip <= DT_MIPMAP_LDR_MAX; mip++)
{
// try and load from disk, if successful set flag
char srcpath[PATH_MAX] = {0};
diff --git a/src/common/mipmap_cache.h b/src/common/mipmap_cache.h
index 1c3aef8e3c63..54895b0fdba4 100644
--- a/src/common/mipmap_cache.h
+++ b/src/common/mipmap_cache.h
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
- Copyright (C) 2011-2025 darktable developers.
+ Copyright (C) 2011-2026 darktable developers.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@ G_BEGIN_DECLS
// sizes stored in the mipmap cache, set to fixed values in mipmap_cache.c
typedef enum dt_mipmap_size_t {
+ // 8 bit, downscaled, for lighttable thumbnails
DT_MIPMAP_0 = 0,
DT_MIPMAP_1,
DT_MIPMAP_2,
@@ -35,11 +36,18 @@ typedef enum dt_mipmap_size_t {
DT_MIPMAP_6,
DT_MIPMAP_7,
DT_MIPMAP_8,
+ DT_MIPMAP_9,
+ // 8 bit, full resolution, for zoomed in thumbnail
+ DT_MIPMAP_10,
+ // float, downscaled, for preview pixelpipe
DT_MIPMAP_F,
+ // float, full resolution, for full/export pixelpipe
DT_MIPMAP_FULL,
DT_MIPMAP_NONE
} dt_mipmap_size_t;
+static const dt_mipmap_size_t DT_MIPMAP_LDR_MAX = DT_MIPMAP_10;
+
// type to be passed to getter functions
typedef enum dt_mipmap_get_flags_t
{
diff --git a/src/control/crawler.c b/src/control/crawler.c
index f5bec053640a..71e39e90c658 100644
--- a/src/control/crawler.c
+++ b/src/control/crawler.c
@@ -861,7 +861,7 @@ static inline gboolean _lighttable_silent(void)
static inline gboolean _valid_mip(dt_mipmap_size_t mip)
{
- return mip > DT_MIPMAP_0 && mip < DT_MIPMAP_8;
+ return mip > DT_MIPMAP_0 && mip < DT_MIPMAP_LDR_MAX;
}
static inline gboolean _still_thumbing(void)
@@ -990,7 +990,7 @@ void dt_update_thumbs_thread(void *p)
}
// return if any thumbcache dir is not writable
- for(dt_mipmap_size_t k = DT_MIPMAP_1; k <= DT_MIPMAP_7; k++)
+ for(dt_mipmap_size_t k = DT_MIPMAP_1; k <= DT_MIPMAP_LDR_MAX-1; k++)
{
char dirname[PATH_MAX] = { 0 };
snprintf(dirname, sizeof(dirname), "%s.d/%d", darktable.mipmap_cache->cachedir, k);
diff --git a/src/dtgtk/thumbnail.c b/src/dtgtk/thumbnail.c
index dc3e011729f1..1106832c1b61 100644
--- a/src/dtgtk/thumbnail.c
+++ b/src/dtgtk/thumbnail.c
@@ -467,7 +467,7 @@ static void _get_dimensions_for_img_to_fit(const dt_thumbnail_t *thumb,
// decimal, so not enough accurate so we compute it from the larger
// available mipmap
float ar = 0.0f;
- for(int k = DT_MIPMAP_7; k >= DT_MIPMAP_0; k--)
+ for(int k = DT_MIPMAP_LDR_MAX; k >= DT_MIPMAP_0; k--)
{
dt_mipmap_buffer_t tmp;
dt_mipmap_cache_get(&tmp, thumb->imgid, k, DT_MIPMAP_TESTLOCK, 'r');
diff --git a/src/dtgtk/thumbtable.c b/src/dtgtk/thumbtable.c
index 1037da19955a..2c3d3f6a36ff 100644
--- a/src/dtgtk/thumbtable.c
+++ b/src/dtgtk/thumbtable.c
@@ -1676,8 +1676,8 @@ static void _thumbs_ask_for_discard(dt_thumbtable_t *table)
dt_mipmap_size_t embeddedl = dt_mipmap_cache_get_min_mip_from_pref(embedded);
- int min_level = 8;
- int max_level = 0;
+ int min_level = DT_MIPMAP_LDR_MAX;
+ int max_level = DT_MIPMAP_0;
if(hql != table->pref_hq)
{
min_level = MIN(table->pref_hq, hql);
@@ -1696,9 +1696,9 @@ static void _thumbs_ask_for_discard(dt_thumbtable_t *table)
gchar *txt =
g_strdup(_("you have changed the settings related to"
" how thumbnails are generated.\n"));
- if(max_level >= DT_MIPMAP_8 && min_level == DT_MIPMAP_0)
+ if(max_level >= DT_MIPMAP_LDR_MAX && min_level == DT_MIPMAP_0)
dt_util_str_cat(&txt, _("all cached thumbnails need to be invalidated.\n\n"));
- else if(max_level >= DT_MIPMAP_8)
+ else if(max_level >= DT_MIPMAP_LDR_MAX)
dt_util_str_cat
(&txt,
_("cached thumbnails starting from level %d need to be invalidated.\n\n"),
diff --git a/src/generate-cache/main.c b/src/generate-cache/main.c
index eb75ab089217..94b384e3ee70 100644
--- a/src/generate-cache/main.c
+++ b/src/generate-cache/main.c
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
- Copyright (C) 2015-2024 darktable developers.
+ Copyright (C) 2015-2026 darktable developers.
darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -181,12 +181,12 @@ int main(int argc, char *arg[])
else if((!strcmp(arg[k], "-m") || !strcmp(arg[k], "--max-mip")) && argc > k + 1)
{
k++;
- max_mip = (dt_mipmap_size_t)MIN(MAX(atoi(arg[k]), DT_MIPMAP_0), DT_MIPMAP_8);
+ max_mip = (dt_mipmap_size_t)MIN(MAX(atoi(arg[k]), DT_MIPMAP_0), DT_MIPMAP_LDR_MAX);
}
else if(!strcmp(arg[k], "--min-mip") && argc > k + 1)
{
k++;
- min_mip = (dt_mipmap_size_t)MIN(MAX(atoi(arg[k]), DT_MIPMAP_0), DT_MIPMAP_8);
+ min_mip = (dt_mipmap_size_t)MIN(MAX(atoi(arg[k]), DT_MIPMAP_0), DT_MIPMAP_LDR_MAX);
}
else if(!strcmp(arg[k], "--min-imgid") && argc > k + 1)
{