diff --git a/meson.build b/meson.build index 7bbf6c9632e30688be4eba533150be6ee3147f54..093db7825fc8b1e76d4e5931e926f97fccc812dc 100644 --- a/meson.build +++ b/meson.build @@ -12,6 +12,7 @@ project('libplacebo', ['c', 'cpp'], 5, # API version { + '222': 'add `pl_icc_params.cache_save/load`', '221': 'add `pl_source_frame.first_field`', '220': 'add deinterlacing-related fields to `pl_frame` and `pl_render_params`', '219': 'add pl_source_frame.duration, deprecating pl_queue_params.frame_duration', diff --git a/src/include/libplacebo/shaders/icc.h b/src/include/libplacebo/shaders/icc.h index 95714e8252586f424b141812ce91bee3e70823a1..3eab83c2c2b8d94f24128c7c0d616b74f1505ecf 100644 --- a/src/include/libplacebo/shaders/icc.h +++ b/src/include/libplacebo/shaders/icc.h @@ -48,6 +48,28 @@ struct pl_icc_params { // if unavailable. float max_luma; + // 3DLUT caching API. Providing these functions can help speed up ICC LUT + // generation by saving/loading profiles to/from disk. Both of these + // callbacks are optional. + void *cache_priv; + // + // This is called to inform users of new cache entries. The user may store + // this cache to disk or some other internal caching mechanism. + void (*cache_save)(void *priv, uint64_t sig, const uint8_t *cache, size_t size); + // + // This is called to query for existing cache entries. The user should look + // up this cache entry and write its contents to `cache`, ensuring that no + // more than `size` bytes are written, and return `true` on success. + bool (*cache_load)(void *priv, uint64_t sig, uint8_t *cache, size_t size); + // + // Note: The `signature` of a cache entry is NOT equal to the `signature` + // of the underlying `pl_icc_object` - it is split up into separate entries + // for `pl_icc_decode` and `pl_icc_encode`, and also includes a hashed + // representation of the encoded parameters. + // + // Note: These callbacks will only be called from within `pl_icc_decode` / + // `pl_icc_encode`, so `cache_priv` should exceed this lifetime. + // Deprecated / removed options. bool use_display_contrast PL_DEPRECATED; // Always on }; diff --git a/src/shaders/icc.c b/src/shaders/icc.c index 888ea020f18d9482033651aef377a57f1c87383e..5b6b8c188c6d0a86c98d43c9499de34321b2e1b1 100644 --- a/src/shaders/icc.c +++ b/src/shaders/icc.c @@ -420,6 +420,15 @@ error: return NULL; } +static inline bool cache_load(pl_icc_object icc, uint64_t sig, + uint8_t *cache, size_t size) +{ + if (icc->params.cache_load) + return icc->params.cache_load(icc->params.cache_priv, sig, cache, size); + + return false; +} + static void fill_lut(void *datap, const struct sh_lut_params *params, bool decode) { pl_icc_object icc = params->priv; @@ -428,6 +437,13 @@ static void fill_lut(void *datap, const struct sh_lut_params *params, bool decod cmsHPROFILE srcp = decode ? p->profile : p->approx; cmsHPROFILE dstp = decode ? p->approx : p->profile; + int s_r = params->width, s_g = params->height, s_b = params->depth; + size_t data_size = s_r * s_g * s_b * sizeof(uint16_t[4]); + if (cache_load(icc, params->signature, datap, data_size)) { + pl_info(log, "Using cached 3DLUT (0x%"PRIX64")", params->signature); + return; + } + clock_t start = clock(); cmsHTRANSFORM tf = cmsCreateTransformTHR(p->cms, srcp, TYPE_RGB_16, dstp, TYPE_RGBA_16, @@ -440,7 +456,6 @@ static void fill_lut(void *datap, const struct sh_lut_params *params, bool decod clock_t after_transform = clock(); pl_log_cpu_time(log, start, after_transform, "creating ICC transform"); - int s_r = params->width, s_g = params->height, s_b = params->depth; uint16_t *tmp = pl_alloc(NULL, s_r * 3 * sizeof(tmp[0])); for (int b = 0; b < s_b; b++) { for (int g = 0; g < s_g; g++) { @@ -460,6 +475,11 @@ static void fill_lut(void *datap, const struct sh_lut_params *params, bool decod pl_log_cpu_time(log, after_transform, clock(), "generating ICC 3DLUT"); cmsDeleteTransform(tf); pl_free(tmp); + + if (icc->params.cache_save) { + icc->params.cache_save(icc->params.cache_priv, params->signature, + datap, data_size); + } } static void fill_decode(void *datap, const struct sh_lut_params *params)