Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
dev_snapshot.c
Go to the documentation of this file.
1/*
2 This file is part of ansel,
3 Copyright (C) 2025-2026 Guillaume STUTIN.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
20
21#include "common/darktable.h"
22#include "common/history.h"
24#include "common/iop_order.h"
25#include "common/mipmap_cache.h"
26#include "develop/dev_history.h"
27#include "develop/develop.h"
30
31#include <math.h>
32
34{
35 if(IS_NULL_PTR(snap)) return;
36 if(!IS_NULL_PTR(snap->display_image)) cairo_surface_destroy(snap->display_image);
37 if(!IS_NULL_PTR(snap->image)) cairo_surface_destroy(snap->image);
38 snap->image = NULL;
39 snap->display_image = NULL;
40 snap->display_scale = 0.0f;
41 snap->crop_x = snap->crop_y = snap->crop_w = snap->crop_h = 0;
42 snap->sample_scale = 1.0f;
43}
44
45// Run a dedicated, one-shot pixelpipe over `frozen`'s history and copy its output into a new
46// full-resolution cairo surface. `frozen` is never dev->pipe/dev->preview_pipe and is not shared
47// with any other thread, so this can safely run on the caller's thread (typically the GUI
48// thread, behind a busy cursor -- see the callers in libs/snapshots.c and libs/duplicate.c).
49// Returns NULL on failure.
50static cairo_surface_t *_render(dt_develop_t *frozen, float scale)
51{
52 cairo_surface_t *surface = NULL;
53 dt_mipmap_buffer_t buf = { 0 };
54 gboolean pipe_ready = FALSE;
55 dt_dev_pixelpipe_t pipe = { 0 };
56 dt_pixel_cache_entry_t *entry = NULL;
57 void *data = NULL;
58 const char *fail_reason = "unknown";
59 const dt_dev_pixelpipe_t *live_preview = NULL;
60 dt_iop_roi_t roi = { 0 };
62 int bw = 0, bh = 0, src_stride = 0, dst_stride = 0;
63 uint8_t *dst = NULL;
64
67 if(IS_NULL_PTR(buf.buf) || buf.width <= 0 || buf.height <= 0)
68 {
69 fail_reason = "mipmap full unavailable";
70 goto cleanup;
71 }
72
73 if(!dt_dev_pixelpipe_init_preview(&pipe, frozen))
74 {
75 fail_reason = "pixelpipe init failed";
76 goto cleanup;
77 }
78 pipe_ready = TRUE;
79
80 // Reuse the live darkroom's ICC settings if any image is currently open in darkroom, so a
81 // captured snapshot/preview soft-proofs the same way the live pipe does. Harmless when frozen
82 // is the same image dev->preview_pipe already reflects; still correct when it's a different
83 // one, since ICC intent/profile are a display-wide GUI setting, not per-image state.
84 live_preview = darktable.develop ? darktable.develop->preview_pipe : NULL;
87 if(!IS_NULL_PTR(live_preview))
88 dt_dev_pixelpipe_set_icc(&pipe, live_preview->icc_type, live_preview->icc_filename, live_preview->icc_intent);
92
93 roi = (dt_iop_roi_t){ .x = 0, .y = 0,
94 .width = MAX(1, (int)roundf(scale * pipe.processed_width)),
95 .height = MAX(1, (int)roundf(scale * pipe.processed_height)),
96 .scale = scale };
97
98 if(dt_dev_pixelpipe_process(&pipe, roi))
99 {
100 fail_reason = "pixelpipe process failed";
101 goto cleanup;
102 }
103
104 hash = dt_dev_backbuf_get_hash(&pipe.backbuf);
106 {
107 fail_reason = "backbuffer hash invalid";
108 goto cleanup;
109 }
110
112 || IS_NULL_PTR(data) || IS_NULL_PTR(entry))
113 {
114 fail_reason = "cache peek failed";
115 goto cleanup;
116 }
117
118 bw = pipe.backbuf.width;
119 bh = pipe.backbuf.height;
120 src_stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, bw);
121 if(bw <= 0 || bh <= 0
122 || dt_pixel_cache_entry_get_size(entry) < (size_t)src_stride * (size_t)bh)
123 {
124 fail_reason = "invalid backbuffer";
125 goto cleanup;
126 }
127
128 surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, bw, bh);
129 if(IS_NULL_PTR(surface))
130 {
131 fail_reason = "cairo surface create failed";
132 goto cleanup;
133 }
134 cairo_surface_set_device_scale(surface, darktable.gui->ppd, darktable.gui->ppd);
135
137 dst = cairo_image_surface_get_data(surface);
138 dst_stride = cairo_image_surface_get_stride(surface);
139 for(int y = 0; y < bh; y++)
140 memcpy(dst + (size_t)y * dst_stride, (const uint8_t *)data + (size_t)y * src_stride, (size_t)src_stride);
141 cairo_surface_mark_dirty(surface);
143
144cleanup:
146 if(pipe_ready) dt_dev_pixelpipe_cleanup(&pipe);
148 if(IS_NULL_PTR(surface))
149 dt_print(DT_DEBUG_DEV, "[dev_snapshot] render failed: imgid=%d reason=%s\n",
150 frozen->image_storage.id, fail_reason);
151 return surface;
152}
153
154gboolean dt_dev_snapshot_capture(dt_dev_snapshot_t *snap, int32_t imgid, float scale,
155 GList *history_override, GList *iop_order_override,
156 int32_t history_end_override)
157{
158 dt_develop_t *frozen = NULL;
159
161 if(IS_NULL_PTR(snap) || imgid <= 0) goto fail;
162
163 frozen = (dt_develop_t *)calloc(1, sizeof(dt_develop_t));
164 if(IS_NULL_PTR(frozen)) goto fail;
165 dt_dev_init(frozen, 0);
166
167 if(dt_dev_load_image(frozen, imgid))
168 {
169 dt_print(DT_DEBUG_DEV, "[dev_snapshot] capture failed: dt_dev_load_image failed for imgid=%d\n", imgid);
170 dt_dev_cleanup(frozen);
171 dt_free(frozen);
172 goto fail;
173 }
174
175 if(history_override)
176 {
178 frozen->history = history_override;
179 history_override = NULL; // ownership transferred to frozen; do not free again below
180 g_list_free_full(frozen->iop_order_list, dt_free_gpointer);
181 frozen->iop_order_list = iop_order_override;
182 iop_order_override = NULL;
183
184 for(GList *history = g_list_first(frozen->history); history; history = g_list_next(history))
185 {
186 dt_dev_history_item_t *hist = (dt_dev_history_item_t *)history->data;
187 if(IS_NULL_PTR(hist)) continue;
188 hist->module = dt_dev_get_module_instance(frozen, hist->op_name, hist->multi_name, hist->multi_priority);
189 if(IS_NULL_PTR(hist->module))
190 hist->module = dt_dev_create_module_instance(frozen, hist->op_name, hist->multi_name, hist->multi_priority, FALSE);
191 if(IS_NULL_PTR(hist->module))
192 hist->module = dt_iop_get_module_by_op_priority(frozen->iop, hist->op_name, -1);
193 if(IS_NULL_PTR(hist->module))
194 {
196 "[dev_snapshot] capture failed: unresolved module op=%s multi=%s priority=%d for imgid=%d\n",
197 hist->op_name, hist->multi_name, hist->multi_priority, imgid);
198 dt_dev_cleanup(frozen);
199 dt_free(frozen);
200 goto fail;
201 }
202 }
203
204 dt_dev_set_history_end_ext(frozen, history_end_override);
206 }
207
208 snap->image = _render(frozen, scale);
209 snap->sample_scale = scale;
210 dt_dev_cleanup(frozen);
211 dt_free(frozen);
212 return !IS_NULL_PTR(snap->image);
213
214fail:
215 if(history_override) g_list_free_full(history_override, dt_free_gpointer);
216 if(iop_order_override) g_list_free_full(iop_order_override, dt_free_gpointer);
217 return FALSE;
218}
219
220// Rebuild snap->display_image by Mitchell-resampling a crop of snap->image at render_scale.
221// The crop covers [vis_x0,vis_x1] x [vis_y0,vis_y1] (the visible viewport, in snap->image
222// source-pixel space), padded by half a viewport on each side so subsequent panning can reuse
223// the cached crop, plus the interpolator's tap margin. Noop if the cached crop already covers
224// the requested window at the same scale.
225static void _build_display_image(dt_dev_snapshot_t *snap, float render_scale,
226 float vis_x0, float vis_y0, float vis_x1, float vis_y1)
227{
228 if(IS_NULL_PTR(snap->image)) return;
229
230 // Below 100%, we're discarding detail anyway: cairo's own scaling is cheap and good
231 // enough once downsampling, so reserve the manual float round-trip + Mitchell for
232 // zoom >= 100%, where reconstruction quality actually matters.
233 if(render_scale < 1.0f)
234 {
235 if(!IS_NULL_PTR(snap->display_image))
236 {
237 cairo_surface_destroy(snap->display_image);
238 snap->display_image = NULL;
239 }
240 snap->display_scale = 0.0f;
241 snap->crop_x = snap->crop_y = snap->crop_w = snap->crop_h = 0;
242 return;
243 }
244
245 const int src_w = cairo_image_surface_get_width(snap->image);
246 const int src_h = cairo_image_surface_get_height(snap->image);
247
249
250 // Taps span `mitchell->width` samples on the output side; render_scale >= 1 here, so the
251 // support never widens past that half-width (see _prepare_resampling_plan for the general,
252 // downscale-widening case).
253 const int tap_margin = (int)mitchell->width + 1;
254 const float pad_x = 0.5f * (vis_x1 - vis_x0);
255 const float pad_y = 0.5f * (vis_y1 - vis_y0);
256
257 int want_x0 = (int)floorf(vis_x0 - pad_x) - tap_margin;
258 int want_y0 = (int)floorf(vis_y0 - pad_y) - tap_margin;
259 int want_x1 = (int)ceilf(vis_x1 + pad_x) + tap_margin;
260 int want_y1 = (int)ceilf(vis_y1 + pad_y) + tap_margin;
261
262 want_x0 = CLAMP(want_x0, 0, src_w);
263 want_y0 = CLAMP(want_y0, 0, src_h);
264 want_x1 = CLAMP(want_x1, want_x0, src_w);
265 want_y1 = CLAMP(want_y1, want_y0, src_h);
266
267 const int vis_ix0 = (int)floorf(vis_x0);
268 const int vis_iy0 = (int)floorf(vis_y0);
269 const int vis_ix1 = (int)ceilf(vis_x1);
270 const int vis_iy1 = (int)ceilf(vis_y1);
271
272 const gboolean scale_ok = !IS_NULL_PTR(snap->display_image) && fabsf(snap->display_scale - render_scale) < 1e-4f;
273 const gboolean crop_ok = scale_ok
274 && snap->crop_x <= vis_ix0 && snap->crop_y <= vis_iy0
275 && snap->crop_x + snap->crop_w >= vis_ix1
276 && snap->crop_y + snap->crop_h >= vis_iy1;
277 if(crop_ok) return;
278
279 if(!IS_NULL_PTR(snap->display_image))
280 {
281 cairo_surface_destroy(snap->display_image);
282 snap->display_image = NULL;
283 }
284 snap->display_scale = 0.0f;
285
286 const int crop_w = MAX(1, want_x1 - want_x0);
287 const int crop_h = MAX(1, want_y1 - want_y0);
288 const int dst_w = MAX(1, (int)roundf((float)crop_w * render_scale));
289 const int dst_h = MAX(1, (int)roundf((float)crop_h * render_scale));
290
291 float *in_f = dt_alloc_align_float((size_t)crop_w * crop_h * 4);
292 if(IS_NULL_PTR(in_f)) return;
293 float *out_f = dt_alloc_align_float((size_t)dst_w * dst_h * 4);
294 if(IS_NULL_PTR(out_f)) { dt_free_align(in_f); return; }
295
296 // uint8 Cairo RGB24 (BGRa on LE) → float RGBa, restricted to the crop window
297 cairo_surface_flush(snap->image);
298 const uint8_t *src = cairo_image_surface_get_data(snap->image);
299 const int src_stride = cairo_image_surface_get_stride(snap->image);
300 for(int y = 0; y < crop_h; y++)
301 {
302 const uint8_t *row = src + (size_t)(y + want_y0) * src_stride + (size_t)want_x0 * 4;
303 float *frow = in_f + (size_t)y * crop_w * 4;
304 for(int x = 0; x < crop_w; x++)
305 {
306 frow[x * 4 + 0] = (float)row[x * 4 + 2] * (1.0f / 255.0f); // R
307 frow[x * 4 + 1] = (float)row[x * 4 + 1] * (1.0f / 255.0f); // G
308 frow[x * 4 + 2] = (float)row[x * 4 + 0] * (1.0f / 255.0f); // B
309 frow[x * 4 + 3] = 0.0f;
310 }
311 }
312
313 // roi_in/roi_out both origin at (0,0): the crop was copied into its own zero-based buffer,
314 // so the resampler must not be told its absolute position in the source image -- passing
315 // the crop's true offset here would offset the resampled result (see the comment in
316 // iop/finalscale.c process() about roi.x/y needing to stay at 0 for a pure resample).
317 const dt_iop_roi_t roi_in = { .x = 0, .y = 0, .width = crop_w, .height = crop_h, .scale = 1.0f };
318 const dt_iop_roi_t roi_out = { .x = 0, .y = 0, .width = dst_w, .height = dst_h, .scale = render_scale };
319 dt_interpolation_resample(mitchell, out_f, &roi_out, in_f, &roi_in);
320 dt_free_align(in_f);
321
322 // float RGBa → uint8 Cairo RGB24 (BGRa on LE)
323 cairo_surface_t *display = cairo_image_surface_create(CAIRO_FORMAT_RGB24, dst_w, dst_h);
324 if(!IS_NULL_PTR(display))
325 {
326 cairo_surface_set_device_scale(display, darktable.gui->ppd, darktable.gui->ppd);
327 uint8_t *dst = cairo_image_surface_get_data(display);
328 const int dst_stride = cairo_image_surface_get_stride(display);
329 for(int y = 0; y < dst_h; y++)
330 {
331 const float *frow = out_f + (size_t)y * dst_w * 4;
332 uint8_t *drow = dst + (size_t)y * dst_stride;
333 for(int x = 0; x < dst_w; x++)
334 {
335 drow[x * 4 + 2] = (uint8_t)CLAMP(frow[x * 4 + 0] * 255.0f + 0.5f, 0.0f, 255.0f); // R
336 drow[x * 4 + 1] = (uint8_t)CLAMP(frow[x * 4 + 1] * 255.0f + 0.5f, 0.0f, 255.0f); // G
337 drow[x * 4 + 0] = (uint8_t)CLAMP(frow[x * 4 + 2] * 255.0f + 0.5f, 0.0f, 255.0f); // B
338 }
339 }
340 cairo_surface_mark_dirty(display);
341 snap->display_image = display;
342 snap->display_scale = render_scale;
343 snap->crop_x = want_x0;
344 snap->crop_y = want_y0;
345 snap->crop_w = crop_w;
346 snap->crop_h = crop_h;
347 }
348 dt_free_align(out_f);
349}
350
351void dt_dev_snapshot_draw(dt_dev_snapshot_t *snap, cairo_t *cri, struct dt_develop_t *dev,
352 int32_t width, int32_t height,
353 double clip_x, double clip_y, double clip_w, double clip_h)
354{
355 if(IS_NULL_PTR(snap) || IS_NULL_PTR(snap->image) || IS_NULL_PTR(dev) || IS_NULL_PTR(cri)) return;
356 if(clip_w <= 0.0 || clip_h <= 0.0) return;
357
358 const float snapshot_scale = snap->sample_scale > 1e-6f ? snap->sample_scale : 1.0f;
359 const float zoom_level = dt_dev_get_zoom_level(dev);
360 const float render_scale = zoom_level / snapshot_scale;
361 const float ppd = darktable.gui->ppd;
362
363 // tx/ty map snap->image source-pixel (0,0) to widget space; this only depends on the full
364 // source size, never on the clip rect, so compute it before building the display crop (which
365 // needs the reverse mapping to know what part of snap->image is actually visible).
366 const int src_w = cairo_image_surface_get_width(snap->image);
367 const int src_h = cairo_image_surface_get_height(snap->image);
368 const float disp_logical_w = src_w / ppd;
369 const float disp_logical_h = src_h / ppd;
370 const double tx = 0.5 * width - dev->roi.x * disp_logical_w * render_scale;
371 const double ty = 0.5 * height - dev->roi.y * disp_logical_h * render_scale;
372
373 // Map the clip rect back to snap->image source-pixel space so we only ever Mitchell-resample
374 // the part of the snapshot that can actually be painted on screen. Falls back to the whole
375 // image when the current zoom is degenerate (should not happen once darkroom is showing an
376 // image, but avoids a division by ~0 turning into an out-of-range int cast below).
377 float vis_x0 = 0.0f, vis_y0 = 0.0f, vis_x1 = (float)src_w, vis_y1 = (float)src_h;
378 if(isfinite(render_scale) && render_scale > 1e-6f)
379 {
380 vis_x0 = (clip_x - tx) * ppd / render_scale;
381 vis_y0 = (clip_y - ty) * ppd / render_scale;
382 vis_x1 = (clip_x + clip_w - tx) * ppd / render_scale;
383 vis_y1 = (clip_y + clip_h - ty) * ppd / render_scale;
384 }
385
386 _build_display_image(snap, render_scale, vis_x0, vis_y0, vis_x1, vis_y1);
387 cairo_surface_t *disp = IS_NULL_PTR(snap->display_image) ? snap->image : snap->display_image;
388
389 // If Mitchell resampling succeeded, the scaling is baked into disp, and its origin is offset
390 // by the cached crop's top-left corner -- no cairo_scale needed, but tx/ty must be shifted
391 // accordingly. Fallback to snap->image draws the full, uncropped frame as before.
392 const gboolean use_mitchell = !IS_NULL_PTR(snap->display_image);
393 const double crop_tx = use_mitchell ? snap->crop_x * (double)render_scale / ppd : 0.0;
394 const double crop_ty = use_mitchell ? snap->crop_y * (double)render_scale / ppd : 0.0;
395
396 cairo_save(cri);
397 cairo_rectangle(cri, clip_x, clip_y, clip_w, clip_h);
398 cairo_clip(cri);
399 cairo_translate(cri, tx + crop_tx, ty + crop_ty);
400 if(!use_mitchell) cairo_scale(cri, render_scale, render_scale);
401 cairo_set_source_surface(cri, disp, 0.0, 0.0);
402 // Mitchell already baked the exact target size into disp, so nearest is an exact 1:1 copy
403 // there. Below 100% zoom (no Mitchell, see _build_display_image), cairo needs to downsample
404 // itself, so ask it for its area-averaging filter instead of nearest, which would alias.
405 cairo_pattern_set_filter(cairo_get_source(cri), use_mitchell ? CAIRO_FILTER_NEAREST : CAIRO_FILTER_GOOD);
406 cairo_paint(cri);
407 cairo_restore(cri);
408}
409
410// clang-format off
411// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
412// vim: shiftwidth=2 expandtab tabstop=2 cindent
413// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
414// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:164
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static const int row
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
#define dt_free_align(ptr)
Definition darktable.h:503
@ DT_DEBUG_DEV
Definition darktable.h:739
static float * dt_alloc_align_float(size_t pixels)
Definition darktable.h:516
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:485
#define dt_free(ptr)
Definition darktable.h:478
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:293
dt_iop_module_t * dt_dev_get_module_instance(dt_develop_t *dev, const char *op, const char *multi_name, const int multi_priority)
Find a module instance by op name and instance metadata.
dt_iop_module_t * dt_dev_create_module_instance(dt_develop_t *dev, const char *op, const char *multi_name, const int multi_priority, gboolean use_next_priority)
Create a new module instance from an existing base .so.
void dt_dev_history_free_history(dt_develop_t *dev)
Free the whole history list attached to dev->history.
uint64_t dt_dev_history_compute_hash(dt_develop_t *dev)
Get the integrity checksum of the whole history stack. This should be done ONLY when history is chang...
void dt_dev_set_history_end_ext(struct dt_develop_t *dev, const uint32_t index)
Set the history end index (GUI perspective).
Definition develop.c:1729
void dt_dev_pixelpipe_propagate_formats(dt_dev_pixelpipe_t *pipe)
void dt_dev_pixelpipe_get_roi_out(dt_dev_pixelpipe_t *pipe, const int width_in, const int height_in, int *width, int *height)
static cairo_surface_t * _render(dt_develop_t *frozen, float scale)
void dt_dev_snapshot_draw(dt_dev_snapshot_t *snap, cairo_t *cri, struct dt_develop_t *dev, int32_t width, int32_t height, double clip_x, double clip_y, double clip_w, double clip_h)
void dt_dev_snapshot_clear(dt_dev_snapshot_t *snap)
gboolean dt_dev_snapshot_capture(dt_dev_snapshot_t *snap, int32_t imgid, float scale, GList *history_override, GList *iop_order_override, int32_t history_end_override)
static void _build_display_image(dt_dev_snapshot_t *snap, float render_scale, float vis_x0, float vis_y0, float vis_x1, float vis_y1)
void dt_dev_cleanup(dt_develop_t *dev)
Definition develop.c:225
dt_dev_image_storage_t dt_dev_load_image(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:940
float dt_dev_get_zoom_level(const dt_develop_t *dev)
Definition develop.c:1816
void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
Definition develop.c:128
static void dt_dev_set_history_hash(dt_develop_t *dev, const uint64_t history_hash)
Definition develop.h:515
dt_iop_module_t * dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
Definition imageop.c:3160
const struct dt_interpolation * dt_interpolation_new(enum dt_interpolation_type type)
void dt_interpolation_resample(const struct dt_interpolation *itor, float *out, const dt_iop_roi_t *const roi_out, const float *const in, const dt_iop_roi_t *const roi_in)
@ DT_INTERPOLATION_MITCHELL
static const float x
static float mitchell(const float x)
Definition liquify.c:1559
#define dt_mipmap_cache_get(A, B, C, D, E, F)
@ DT_MIPMAP_BLOCKING
#define dt_mipmap_cache_release(A, B)
@ DT_MIPMAP_FULL
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
gboolean dt_dev_pixelpipe_cache_ref_entry_by_hash(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cache entry by hash.
size_t dt_pixel_cache_entry_get_size(dt_pixel_cache_entry_t *entry)
Peek the size (in bytes) reserved for the host buffer of a cache entry.
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
Pixelpipe cache for storing intermediate results in the pixelpipe.
#define DT_PIXELPIPE_CACHE_HASH_INVALID
void dt_dev_pixelpipe_set_input(dt_dev_pixelpipe_t *pipe, int32_t imgid, int width, int height, float iscale, dt_mipmap_size_t size)
void dt_dev_pixelpipe_set_icc(dt_dev_pixelpipe_t *pipe, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent)
int dt_dev_pixelpipe_init_preview(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
void dt_dev_pixelpipe_create_nodes(dt_dev_pixelpipe_t *pipe)
void dt_dev_pixelpipe_cleanup(dt_dev_pixelpipe_t *pipe)
int dt_dev_pixelpipe_process(dt_dev_pixelpipe_t *pipe, dt_iop_roi_t roi)
#define dt_dev_pixelpipe_synch_all(pipe)
static uint64_t dt_dev_backbuf_get_hash(const dt_backbuf_t *backbuf)
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:818
struct dt_gui_gtk_t * gui
Definition darktable.h:803
struct dt_mipmap_cache_t * mipmap_cache
Definition darktable.h:804
struct dt_develop_t * develop
Definition darktable.h:798
dt_colorspaces_color_profile_type_t icc_type
dt_backbuf_t backbuf
dt_iop_color_intent_t icc_intent
cairo_surface_t * image
cairo_surface_t * display_image
GList * iop_order_list
Definition develop.h:291
dt_image_t image_storage
Definition develop.h:259
GList * iop
Definition develop.h:285
struct dt_dev_pixelpipe_t * preview_pipe
Definition develop.h:247
GList * history
Definition develop.h:275
struct dt_develop_t::@17 roi
double ppd
Definition gtk.h:205
int32_t id
Definition image.h:319
Region of interest passed through the pixelpipe.
Definition imageop.h:72
typedef double((*spd)(unsigned long int wavelength, double TempK))
#define MAX(a, b)
Definition thinplate.c:29