Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
dev_roi_request.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel.
3 Copyright (C) 2026 Aurélien Pierre.
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
22#include "develop/develop.h"
24
25#include <string.h>
26
27/* Same publication protocol as the geometry record and the viewport: one writer (the GUI
28 * thread), a generation that is odd mid-publication, readers that copy and retry.
29 */
30
45static inline gboolean _payload_equal(const dt_dev_roi_request_t *a, const dt_dev_roi_request_t *b)
46{
47 return a->box_width == b->box_width
48 && a->box_height == b->box_height
49 && a->processed_width == b->processed_width
50 && a->processed_height == b->processed_height
51 && a->preview_width == b->preview_width
52 && a->preview_height == b->preview_height
53 && a->natural_scale == b->natural_scale
54 && a->scaling == b->scaling
55 && a->center_x == b->center_x
56 && a->center_y == b->center_y
57 && a->valid == b->valid;
58}
59
61{
63 memset(&request, 0, sizeof(request));
64 request.natural_scale = -1.f;
65 request.scaling = 1.f;
66 request.center_x = 0.5f;
67 request.center_y = 0.5f;
68 return request;
69}
70
78
80{
82 memset(&request, 0, sizeof(request));
83 if(IS_NULL_PTR(dev)) return request;
84
86
87 for(;;)
88 {
89 const uint64_t before = dt_atomic_get_uint64(&store->generation);
90 if(before & 1) continue;
91
92 request = store->value;
93
94 const uint64_t after = dt_atomic_get_uint64(&store->generation);
95 if(before == after) break;
96 }
97
98 return request;
99}
100
102{
103 if(IS_NULL_PTR(dev)) return 0;
104
105 // One coherent read of each input, so the request cannot mix two viewport states or two
106 // geometries -- the whole point of publishing them as records in the first place.
107 const dt_dev_viewport_state_t viewport = dt_dev_viewport_get(dev);
109
111
112 next.box_width = viewport.box_width;
113 next.box_height = viewport.box_height;
114 next.scaling = viewport.scaling;
115 next.center_x = viewport.center_x;
116 next.center_y = viewport.center_y;
117 next.processed_width = geometry.processed_width;
118 next.processed_height = geometry.processed_height;
119
120 // dt_dev_get_natural_scale()'s guard, reproduced: no viewport allocation or no raw geometry
121 // means there is nothing to fit the image into, and -1 is the sentinel every consumer of the
122 // product already handles.
123 next.natural_scale = (viewport.configured && geometry.raw_inited)
124 ? dt_dev_roi_natural_scale(viewport.box_width, viewport.box_height,
125 geometry.processed_width, geometry.processed_height)
126 : -1.f;
127
128 // roundf(), NOT a truncation: these must match the ROI the worker requests, which rounds too.
129 // A truncation here disagreed by 1px whenever the fraction was >= 0.5, which is image-dependent,
130 // and silently broke dt_dev_pixelpipe_has_preview_output() -- hence ashift structure detection
131 // and drawing -- on some images but not others.
134
135 // DERIVED, never asserted. This used to be an unconditional TRUE, which made the record claim
136 // it was usable from dt_dev_init() onwards -- before any viewport, any image, any pipe -- and
137 // made dt_dev_reset_roi()'s invalidation unobservable, since the viewport reset republishes on
138 // the very next line.
139 //
140 // Each of these three flags is FALSE only while its own numbers are still zero: box_* is
141 // written only by dt_dev_viewport_set_box(), which sets `configured' in the same publication;
142 // raw_* only by _dt_dev_mipmap_prefetch_full(), which pairs a FALSE with 0x0; processed_* only
143 // by dt_dev_geometry_set_processed_size(), which always sets its flag. So a FALSE here always
144 // travels with a zero, which is what keeps _darkroom_pipeline_inputs_ready() (it tests the
145 // numbers, not the flags) rejecting exactly the states this reports as unusable -- the worker
146 // naps and retries instead of reaching _update_darkroom_roi(), whose !valid branch returns
147 // without writing its out-params and would leave the caller planning a 0x0 ROI.
148 //
149 // Do not clear one of these flags without zeroing its numbers, and do not gate this on
150 // anything a publication cannot re-derive.
151 next.valid = viewport.configured && geometry.raw_inited && geometry.processed_inited;
152
153 // Advance the generation only on a real change, so a consumer can use it as a cache key
154 // without being invalidated by every republication of identical numbers.
156 if(_payload_equal(&dev->roi_request.value, &next)) return published;
157
158 next.generation = published + 2; // stays even: the store's counter is the odd/even flag
160 dev->roi_request.value = next;
162
163 return next.generation;
164}
165
167{
168 if(IS_NULL_PTR(pipe) || IS_NULL_PTR(request)) return;
169
172 pipe->roi_request.value = *request;
174}
175
177{
179 if(IS_NULL_PTR(pipe)) return request;
180
181 for(;;)
182 {
184 if(before & 1) continue;
185
186 request = pipe->roi_request.value;
187
189 if(before == after) break;
190 }
191
192 return request;
193}
194
199
204
209
211{
212 return dt_dev_roi_request_get(dev).valid;
213}
214
215// clang-format off
216// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
217// vim: shiftwidth=2 expandtab tabstop=2 cindent
218// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
219// clang-format on
uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
dt_dev_image_geometry_t dt_dev_geometry_snapshot(const dt_develop_t *dev)
dt_dev_roi_request_t dt_dev_roi_request_neutral(void)
The value a pipe carries before the worker has latched anything.
int32_t dt_dev_roi_request_preview_height(const dt_develop_t *dev)
void dt_dev_roi_request_latch(dt_dev_pixelpipe_t *pipe, const dt_dev_roi_request_t *request)
Publish onto a pipe the request its next run is planned from. Darkroom worker only.
float dt_dev_roi_request_natural_scale(const dt_develop_t *dev)
int32_t dt_dev_roi_request_preview_width(const dt_develop_t *dev)
dt_dev_roi_request_t dt_dev_roi_request_of_pipe(const dt_dev_pixelpipe_t *pipe)
static gboolean _payload_equal(const dt_dev_roi_request_t *a, const dt_dev_roi_request_t *b)
Do these two records carry the same numbers, ignoring the generation stamp?
uint64_t dt_dev_roi_request_publish(dt_develop_t *dev)
Recompute the derived members from the viewport and the geometry record, and publish if anything chan...
void dt_dev_roi_request_init(dt_develop_t *dev)
gboolean dt_dev_roi_request_valid(const dt_develop_t *dev)
dt_dev_roi_request_t dt_dev_roi_request_get(const dt_develop_t *dev)
static float dt_dev_roi_natural_scale(const int32_t box_width, const int32_t box_height, const int32_t processed_width, const int32_t processed_height)
natural scaling = MIN(box / processed, 1): the image fits the widget minus its borders.
dt_dev_viewport_state_t dt_dev_viewport_get(const dt_develop_t *dev)
int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid, dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total, const gboolean high_quality, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_export_metadata_t *metadata)
Definition disk.c:250
#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 macros.h:65
unsigned __int64 uint64_t
Definition strptime.c:75
Objective facts about the image a dev is working on.
dt_dev_roi_request_store_t roi_request
The viewport snapshot this run was planned from.
dt_dev_roi_request_t value
The coherent set of numbers a darkroom pipe plans its ROI from.
What the darkroom view asks the pipeline to show: the window onto the image.
dt_dev_roi_request_store_t roi_request
What the darkroom pipes plan their ROI from: the viewport and the geometry, combined and derived once...
Definition develop.h:210