120 const gint64 interval_us);
128 gboolean outer_loop);
131#if defined(_OPENMP) && OUTER_LOOP
132static guint _rasterize_dab_batch_outer_loop(
const GArray *dabs, guint max_dabs,
float distance_percent,
138static gboolean _dab_batch_supports_outer_loop(
const GArray *dabs, guint count);
144#if defined(_OPENMP) && OUTER_LOOP
148#define DRAWLAYER_BATCH_TILE_SIZE 128
149#define DRAWLAYER_HEARTBEAT_PATCH_NAME "drawlayer heartbeat patch"
150#define DRAWLAYER_HEARTBEAT_MASK_NAME "drawlayer heartbeat stroke mask"
151#define DRAWLAYER_OUTER_LIVE_BATCH_MULTIPLIER 2u
159 float lx = input->
lx;
160 float ly = input->
ly;
194 const float base_radius = radius;
195 const float base_opacity = opacity;
196 const float base_flow = flow;
197 const float base_hardness = hardness;
199 if(map_pressure_size) radius *= pressure_coeff;
200 if(map_pressure_opacity) opacity *= pressure_coeff;
201 if(map_pressure_flow) flow *= pressure_coeff;
202 if(map_pressure_softness) hardness *= pressure_coeff;
204 if(map_tilt_size) radius *= tilt_coeff;
205 if(map_tilt_opacity) opacity *= tilt_coeff;
206 if(map_tilt_flow) flow *= tilt_coeff;
207 if(map_tilt_softness) hardness *= tilt_coeff;
209 if(map_accel_size) radius *= accel_coeff;
210 if(map_accel_opacity) opacity *= accel_coeff;
211 if(map_accel_flow) flow *= accel_coeff;
212 if(map_accel_softness) hardness *= accel_coeff;
214 radius = fmaxf(radius, 0.5f);
218 if(
state->have_last_input_dab)
220 const float dx = lx -
state->last_input_dab.x;
221 const float dy = ly -
state->last_input_dab.y;
222 const float dir_len = hypotf(dx, dy);
225 dir_x = dx / dir_len;
226 dir_y = dy / dir_len;
243 .hardness = hardness,
252 if((map_pressure_size || map_pressure_opacity || map_pressure_flow || map_pressure_softness || map_tilt_size
253 || map_tilt_opacity || map_tilt_flow || map_tilt_softness || map_accel_size || map_accel_opacity
254 || map_accel_flow || map_accel_softness)
256 || ((
state->history && (
state->history->len & 15u) == 0u))))
259 "[drawlayer] map p=%.4f t=%.4f a=%.4f coeff[p=%.4f t=%.4f a=%.4f] "
260 "base[r=%.2f o=%.3f f=%.3f h=%.3f] out[r=%.2f o=%.3f f=%.3f h=%.3f] "
261 "flags[p=%d%d%d%d t=%d%d%d%d a=%d%d%d%d]\n",
262 pressure_norm, tilt_norm, accel_norm, pressure_coeff, tilt_coeff, accel_coeff, base_radius,
264 map_pressure_size ? 1 : 0, map_pressure_opacity ? 1 : 0, map_pressure_flow ? 1 : 0,
265 map_pressure_softness ? 1 : 0, map_tilt_size ? 1 : 0, map_tilt_opacity ? 1 : 0, map_tilt_flow ? 1 : 0,
266 map_tilt_softness ? 1 : 0, map_accel_size ? 1 : 0, map_accel_opacity ? 1 : 0, map_accel_flow ? 1 : 0,
267 map_accel_softness ? 1 : 0);
277 return (ctx && ctx->
self)
310 const int sample_count = (int)
g->stroke.stroke_sample_count;
343 const gint64 input_ts = input->
event_ts ? input->
event_ts : g_get_monotonic_time();
363 g->process.cache_dirty =
TRUE;
381 patch, 1.0f, stroke_mask, &step_damage, stroke))
384 if(step_damage.
valid && batch_damage)
387 return step_damage.
valid;
497#if defined(_OPENMP) && OUTER_LOOP
504#if defined(_OPENMP) && OUTER_LOOP
505static gboolean _dab_batch_supports_outer_loop(
const GArray *dabs,
const guint count)
508 for(guint
i = 0;
i < count;
i++)
518 const double elapsed_ms,
const gboolean outer_loop)
522 tag ? tag :
"unknown", processed_dabs, thread_count, outer_loop ? 1 : 0, elapsed_ms);
526 const gint64 interval_us)
546 || dab->
radius <= 0.0f || dab->
opacity <= 0.0f || scale <= 0.0f)
549 const float support_radius = dab->
radius;
551 bounds->
nw[0] =
MAX(0, (
int)floorf((dab->
x - support_radius) * scale) - patch->
x);
552 bounds->
nw[1] =
MAX(0, (
int)floorf((dab->
y - support_radius) * scale) - patch->
y);
553 bounds->
se[0] =
MIN(patch->
width, (
int)ceilf((dab->
x + support_radius) * scale) - patch->
x + 1);
554 bounds->
se[1] =
MIN(patch->
height, (
int)ceilf((dab->
y + support_radius) * scale) - patch->
y + 1);
555 return bounds->
se[0] > bounds->
nw[0] && bounds->
se[1] > bounds->
nw[1];
569 for(guint
i = 0;
i < max_dabs;
i++)
577 return batch_bounds->
valid;
586 const int width = batch_bounds->
se[0] - batch_bounds->
nw[0];
587 const int height = batch_bounds->
se[1] - batch_bounds->
nw[1];
607 const int src_x0 = dst->
x - src->
x;
608 const int src_y0 = dst->
y - src->
y;
609 if(src_x0 < 0 || src_y0 < 0 || src_x0 + dst->
width > src->
width || src_y0 + dst->
height > src->
height)
return;
611 for(
int y = 0; y < dst->
height; y++)
613 const float *src_row = src->
pixels + 4 * ((size_t)(src_y0 + y) * src->
width + src_x0);
614 float *dst_row = dst->
pixels + 4 * ((size_t)y * dst->
width);
615 memcpy(dst_row, src_row, (
size_t)dst->
width * 4 *
sizeof(
float));
630 const int src_x0 = dst->
x - src->
x;
631 const int src_y0 = dst->
y - src->
y;
638 for(
int y = 0; y < dst->
height; y++)
640 const float *src_row = src->
pixels + (size_t)(src_y0 + y) * src->
width + src_x0;
641 float *dst_row = dst->
pixels + (size_t)y * dst->
width;
642 memcpy(dst_row, src_row, (
size_t)dst->
width *
sizeof(
float));
654 *absolute_damage = *local_damage;
655 absolute_damage->
nw[0] += patch->
x;
656 absolute_damage->
nw[1] += patch->
y;
657 absolute_damage->
se[0] += patch->
x;
658 absolute_damage->
se[1] += patch->
y;
669 const int copy_w = local_damage->
se[0] - local_damage->
nw[0];
670 const int copy_h = local_damage->
se[1] - local_damage->
nw[1];
671 if(copy_w <= 0 || copy_h <= 0)
return;
673 const int dst_x0 = src->
x + local_damage->
nw[0] - dst->
x;
674 const int dst_y0 = src->
y + local_damage->
nw[1] - dst->
y;
675 if(dst_x0 < 0 || dst_y0 < 0 || dst_x0 + copy_w > dst->
width || dst_y0 + copy_h > dst->
height)
return;
677 for(
int y = 0; y < copy_h; y++)
679 const float *src_row = src->
pixels + 4 * ((size_t)(local_damage->
nw[1] + y) * src->
width + local_damage->
nw[0]);
680 float *dst_row = dst->
pixels + 4 * ((size_t)(dst_y0 + y) * dst->
width + dst_x0);
681 memcpy(dst_row, src_row, (
size_t)copy_w * 4 *
sizeof(
float));
692 const int copy_w = local_damage->
se[0] - local_damage->
nw[0];
693 const int copy_h = local_damage->
se[1] - local_damage->
nw[1];
694 if(copy_w <= 0 || copy_h <= 0)
return;
696 const int dst_x0 = src->
x + local_damage->
nw[0] - dst->
x;
697 const int dst_y0 = src->
y + local_damage->
nw[1] - dst->
y;
698 if(dst_x0 < 0 || dst_y0 < 0 || dst_x0 + copy_w > dst->
width || dst_y0 + copy_h > dst->
height)
return;
700 for(
int y = 0; y < copy_h; y++)
702 const float *src_row = src->
pixels + (size_t)(local_damage->
nw[1] + y) * src->
width + local_damage->
nw[0];
703 float *dst_row = dst->
pixels + (size_t)(dst_y0 + y) * dst->
width + dst_x0;
704 memcpy(dst_row, src_row, (
size_t)copy_w *
sizeof(
float));
714 const int clear_w = local_damage->
se[0] - local_damage->
nw[0];
715 const int clear_h = local_damage->
se[1] - local_damage->
nw[1];
716 if(clear_w <= 0 || clear_h <= 0)
return;
718 for(
int y = 0; y < clear_h; y++)
720 float *
row = patch->
pixels + 4 * ((size_t)(local_damage->
nw[1] + y) * patch->
width + local_damage->
nw[0]);
721 memset(
row, 0, (
size_t)clear_w * 4 *
sizeof(
float));
731 const int clear_w = local_damage->
se[0] - local_damage->
nw[0];
732 const int clear_h = local_damage->
se[1] - local_damage->
nw[1];
733 if(clear_w <= 0 || clear_h <= 0)
return;
735 for(
int y = 0; y < clear_h; y++)
737 float *
row = patch->
pixels + (size_t)(local_damage->
nw[1] + y) * patch->
width + local_damage->
nw[0];
738 memset(
row, 0, (
size_t)clear_w *
sizeof(
float));
742#if defined(_OPENMP) && OUTER_LOOP
758 if(!runtime || !*runtime)
return;
759 if((*runtime)->dab_window) g_array_free((*runtime)->dab_window,
TRUE);
760 (*runtime)->dab_window = NULL;
764static void _lock_batch_tiles(omp_lock_t *locks,
const int tile_cols,
const int tile_origin_x,
767 if(!locks || tile_cols <= 0 ||
IS_NULL_PTR(bounds) || !bounds->
valid)
return;
772 for(
int ty = ty0; ty <= ty1; ty++)
773 for(
int tx = tx0; tx <= tx1; tx++)
774 omp_set_lock(&locks[ty * tile_cols + tx]);
777static void _unlock_batch_tiles(omp_lock_t *locks,
const int tile_cols,
const int tile_origin_x,
780 if(!locks || tile_cols <= 0 ||
IS_NULL_PTR(bounds) || !bounds->
valid)
return;
785 for(
int ty = ty1; ty >= ty0; ty--)
786 for(
int tx = tx1; tx >= tx0; tx--)
787 omp_unset_lock(&locks[ty * tile_cols + tx]);
790static guint _rasterize_dab_batch_outer_loop(
const GArray *dabs,
const guint max_dabs,
const float distance_percent,
801 for(guint
i = 0;
i < max_dabs;
i++)
808 if(!batch_bounds.
valid)
return 0;
816 omp_lock_t *tile_locks = g_malloc0((
size_t)tile_cols * tile_rows *
sizeof(*tile_locks));
817 if(!thread_runtime ||
IS_NULL_PTR(thread_damage) || !tile_locks)
819 g_free(thread_runtime);
820 g_free(thread_damage);
825 for(guint
i = 0;
i < thread_count;
i++)
827 thread_runtime[
i] = _create_batch_runtime();
828 if(!thread_runtime[
i])
830 for(guint
k = 0;
k <
i;
k++) _destroy_batch_runtime(&thread_runtime[
k]);
831 g_free(thread_runtime);
832 g_free(thread_damage);
838 for(
int i = 0;
i < tile_cols * tile_rows;
i++)
839 omp_init_lock(&tile_locks[
i]);
842#pragma omp parallel for default(shared)
843 for(guint
i = 0;
i < max_dabs;
i++)
858 _lock_batch_tiles(tile_locks, tile_cols, tile_origin_x, tile_origin_y, &bounds);
860 &runtime_damage, runtime);
861 _unlock_batch_tiles(tile_locks, tile_cols, tile_origin_x, tile_origin_y, &bounds);
869 for(guint
i = 0;
i < thread_count;
i++)
872 _destroy_batch_runtime(&thread_runtime[
i]);
874 for(
int i = 0;
i < tile_cols * tile_rows;
i++)
875 omp_destroy_lock(&tile_locks[
i]);
877 g_free(thread_runtime);
878 g_free(thread_damage);
892 if(
IS_NULL_PTR(
g->process.base_patch.pixels) ||
g->process.base_patch.width <= 0 ||
g->process.base_patch.height <= 0)
897 const guint batch_dabs = (budget_us > 0)
900 if(batch_dabs == 0)
return 0;
905 g_array_remove_range(stroke->
pending_dabs, 0, batch_dabs);
913 guint processed_dabs = 0;
914 gboolean used_outer_loop =
FALSE;
924#if defined(_OPENMP) && OUTER_LOOP
925 if(batch_dabs >= min_batch && _dab_batch_supports_outer_loop(stroke->
pending_dabs, batch_dabs))
927 used_outer_loop =
TRUE;
928 processed_dabs = _rasterize_dab_batch_outer_loop(stroke->
pending_dabs, batch_dabs,
930 &
g->process.base_patch, heartbeat_patch, 1.0f,
931 heartbeat_mask, &batch_damage,
"heartbeat");
934 while(processed_dabs < batch_dabs)
938 _process_backend_dab(dab, ctx, &
g->process.base_patch, heartbeat_patch, heartbeat_mask, &batch_damage);
943 const gint64 elapsed_us = (gint64)(1000000.0 * (
dt_get_wtime() - batch_t0));
944 if(processed_dabs >= min_batch && elapsed_us >= budget_us)
break;
950 if(processed_dabs == 0)
return 0;
954 g_array_remove_range(stroke->
pending_dabs, 0, processed_dabs);
956 if(batch_damage.
valid)
968 g->process.base_patch.cache_entry, -1);
972 g->process.cache_dirty =
TRUE;
976 g->stroke.last_dab_valid =
TRUE;
977 g->stroke.last_dab_x = last_dab->
x;
978 g->stroke.last_dab_y = last_dab->
y;
984 return processed_dabs;
1067#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
1068 struct sched_param
param = { 0 };
1069 const int max_prio = sched_get_priority_max(SCHED_FIFO);
1072 param.sched_priority =
MIN(max_prio, 80);
1073 pthread_setschedparam(pthread_self(), SCHED_FIFO, &
param);
1106 gboolean active =
FALSE;
1117 gboolean active =
FALSE;
1139 guint processed_dabs = 0;
1144 if(should_stop)
break;
1147 if(processed_dabs == 0)
break;
1153 gboolean should_commit =
FALSE;
1225 gboolean *painting, gboolean *finish_commit_pending,
1226 guint *stroke_sample_count, uint32_t *current_stroke_batch)
1231 rt = g_malloc0(
sizeof(*rt));
1269 if(worker->
stop)
break;
1299 gboolean have_event =
FALSE;
1300 gboolean have_backlog =
FALSE;
1418 pthread_join(worker->
thread, NULL);
1479 gboolean ok =
FALSE;
1499 worker->
ring[last_index] = end_event;
1506 dt_control_log(_(
"drawing worker queue is full, stroke aborted"));
1520 if(input) end_input = *input;
1532 gboolean *painting, gboolean *finish_commit_pending,
1533 guint *stroke_sample_count, uint32_t *current_stroke_batch)
1535 _rt_init_state(self, worker, painting, finish_commit_pending, stroke_sample_count, current_stroke_batch);
1638 return worker ? worker->
stroke : NULL;
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ DT_DRAWLAYER_BRUSH_MODE_SMUDGE
Definition brush.h:51
const float i
Definition colorspaces_inline_conversions.h:440
const float g
Definition colorspaces_inline_conversions.h:674
static const int row
Definition colorspaces_inline_conversions.h:35
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_control_log(const char *msg,...)
Definition control.c:530
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
Definition control.c:630
gboolean dt_drawlayer_widget_to_layer_coords(dt_iop_module_t *self, const double wx, const double wy, float *lx, float *ly)
Definition coordinates.c:81
gboolean dt_drawlayer_layer_to_widget_coords(dt_iop_module_t *self, const float x, const float y, float *wx, float *wy)
Definition coordinates.c:94
darktable_t darktable
Definition darktable.c:173
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1448
@ DT_DEBUG_INPUT
Definition darktable.h:728
@ DT_DEBUG_PERF
Definition darktable.h:718
#define omp_get_max_threads()
Definition darktable.h:254
#define dt_free(ptr)
Definition darktable.h:456
#define omp_get_thread_num()
Definition darktable.h:255
static double dt_get_wtime(void)
Definition darktable.h:913
#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:281
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...
Definition dev_history.c:848
gboolean dt_dev_add_history_item_ext(dt_develop_t *dev, struct dt_iop_module_t *module, gboolean enable, gboolean force_new_item)
Append or update a history item for a module.
Definition dev_history.c:745
static void dt_dev_set_history_hash(dt_develop_t *dev, const uint64_t history_hash)
Definition develop.h:478
void dt_drawlayer_touch_stroke_commit_hash(dt_iop_drawlayer_params_t *params, const int dab_count, const gboolean have_last_dab, const float last_dab_x, const float last_dab_y, const uint32_t publish_serial)
Definition drawlayer.c:1521
#define _commit_dabs
Definition drawlayer.c:117
int dt_pthread_create(pthread_t *thread, void *(*start_routine)(void *), void *arg, const gboolean realtime)
Definition dtpthread.c:45
void dt_pthread_setname(const char *name)
Definition dtpthread.c:118
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:359
#define dt_pthread_rwlock_wrlock
Definition dtpthread.h:394
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:379
static int dt_pthread_cond_wait(pthread_cond_t *cond, dt_pthread_mutex_t *mutex)
Definition dtpthread.h:384
#define dt_pthread_rwlock_unlock
Definition dtpthread.h:392
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
int dt_gui_throttle_get_pipe_runtime_us(const dt_dev_pixelpipe_type_t pipe_type)
Definition gui_throttle.c:217
static float _clamp01(const float v)
Clamp scalar to [0,1].
Definition iop/drawlayer/brush.c:38
static float _mapping_profile_value(const drawlayer_mapping_profile_t profile, const float x)
Definition iop/drawlayer/module.h:77
@ DRAWLAYER_INPUT_MAP_ACCEL_SIZE
Definition iop/drawlayer/module.h:34
@ DRAWLAYER_INPUT_MAP_ACCEL_FLOW
Definition iop/drawlayer/module.h:36
@ DRAWLAYER_INPUT_MAP_PRESSURE_SOFTNESS
Definition iop/drawlayer/module.h:29
@ DRAWLAYER_INPUT_MAP_TILT_SOFTNESS
Definition iop/drawlayer/module.h:33
@ DRAWLAYER_INPUT_MAP_TILT_OPACITY
Definition iop/drawlayer/module.h:31
@ DRAWLAYER_INPUT_MAP_PRESSURE_OPACITY
Definition iop/drawlayer/module.h:27
@ DRAWLAYER_INPUT_MAP_TILT_FLOW
Definition iop/drawlayer/module.h:32
@ DRAWLAYER_INPUT_MAP_ACCEL_OPACITY
Definition iop/drawlayer/module.h:35
@ DRAWLAYER_INPUT_MAP_TILT_SIZE
Definition iop/drawlayer/module.h:30
@ DRAWLAYER_INPUT_MAP_PRESSURE_FLOW
Definition iop/drawlayer/module.h:28
@ DRAWLAYER_INPUT_MAP_ACCEL_SOFTNESS
Definition iop/drawlayer/module.h:37
@ DRAWLAYER_INPUT_MAP_PRESSURE_SIZE
Definition iop/drawlayer/module.h:26
drawlayer_mapping_profile_t
Definition iop/drawlayer/module.h:15
@ DRAWLAYER_PROFILE_INV_QUADRATIC
Definition iop/drawlayer/module.h:21
@ DRAWLAYER_PROFILE_LINEAR
Definition iop/drawlayer/module.h:16
#define DRAWLAYER_WORKER_RING_CAPACITY
Definition iop/drawlayer/module.h:11
void dt_drawlayer_paint_path_state_reset(dt_drawlayer_paint_stroke_t *state)
Reset full stroke state including queued raw input events.
Definition iop/drawlayer/paint.c:476
void dt_drawlayer_paint_runtime_state_destroy(dt_drawlayer_damaged_rect_t **state)
Destroy stroke-damage accumulator state and null pointer.
Definition iop/drawlayer/paint.c:796
gboolean dt_drawlayer_paint_queue_raw_input(dt_drawlayer_paint_stroke_t *state, const dt_drawlayer_paint_raw_input_t *input)
Queue one raw input event (FIFO).
Definition iop/drawlayer/paint.c:642
void dt_drawlayer_paint_runtime_private_destroy(dt_drawlayer_paint_stroke_t **state)
Destroy stroke runtime payload and null pointer.
Definition iop/drawlayer/paint.c:820
void dt_drawlayer_paint_interpolate_path(dt_drawlayer_paint_stroke_t *state, const dt_drawlayer_paint_callbacks_t *callbacks, void *user_data)
Drain queued raw input events and append evenly spaced dabs to state->pending_dabs.
Definition iop/drawlayer/paint.c:666
void dt_drawlayer_paint_runtime_set_stroke_seed(dt_drawlayer_paint_stroke_t *state, const uint64_t seed)
Set deterministic stroke seed for noise-derived effects.
Definition iop/drawlayer/paint.c:839
void dt_drawlayer_paint_finalize_path(dt_drawlayer_paint_stroke_t *state)
Finalize stroke by force-emitting the pending first sample if needed.
Definition iop/drawlayer/paint.c:527
void dt_drawlayer_paint_runtime_private_reset(dt_drawlayer_paint_stroke_t *state)
Reset transient stroke runtime payload between strokes.
Definition iop/drawlayer/paint.c:828
gboolean dt_drawlayer_paint_runtime_get_stroke_damage(const dt_drawlayer_damaged_rect_t *state, dt_drawlayer_damaged_rect_t *out_rect)
Read accumulated stroke damage rectangle.
Definition iop/drawlayer/paint.c:940
gboolean dt_drawlayer_paint_rasterize_segment_to_buffer(const dt_drawlayer_brush_dab_t *dab, const float distance_percent, const dt_drawlayer_cache_patch_t *sample_patch, dt_drawlayer_cache_patch_t *patch, const float scale, dt_drawlayer_cache_patch_t *stroke_mask, dt_drawlayer_damaged_rect_t *runtime_state, dt_drawlayer_paint_stroke_t *runtime_private)
Replay one emitted dab segment into a float buffer through brush API.
Definition iop/drawlayer/paint.c:714
void dt_drawlayer_paint_runtime_state_reset(dt_drawlayer_damaged_rect_t *state)
Reset stroke-damage accumulator to empty/invalid.
Definition iop/drawlayer/paint.c:802
void dt_drawlayer_paint_runtime_note_dab_damage(dt_drawlayer_damaged_rect_t *state, const dt_drawlayer_damaged_rect_t *dab_rect)
Merge one dab rectangle into an accumulator rectangle.
Definition iop/drawlayer/paint.c:922
dt_drawlayer_damaged_rect_t * dt_drawlayer_paint_runtime_state_create(void)
Allocate zero-initialized stroke-damage accumulator state.
Definition iop/drawlayer/paint.c:788
gboolean dt_drawlayer_paint_merge_runtime_stroke_damage(dt_drawlayer_damaged_rect_t *path_state, dt_drawlayer_damaged_rect_t *target_rect)
Merge path-state damage into target rectangle and clear path-state accumulator.
Definition iop/drawlayer/paint.c:967
dt_drawlayer_paint_stroke_t * dt_drawlayer_paint_runtime_private_create(void)
Allocate stroke runtime payload object used by paint+brush internals.
Definition iop/drawlayer/paint.c:812
@ DT_DRAWLAYER_PAINT_STROKE_MIDDLE
Definition iop/drawlayer/paint.h:38
@ DT_DRAWLAYER_PAINT_STROKE_FIRST
Definition iop/drawlayer/paint.h:37
@ DT_DRAWLAYER_PAINT_STROKE_END
Definition iop/drawlayer/paint.h:39
float *const restrict const size_t k
Definition luminance_mask.h:78
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:39
gboolean dt_dev_pixelpipe_cache_flush_host_pinned_image(dt_dev_pixelpipe_cache_t *cache, void *host_ptr, dt_pixel_cache_entry_t *entry_hint, int devid)
Drop cached pinned OpenCL images associated with a given host buffer.
Definition pixelpipe_cache.c:845
const float uint32_t state[4]
Definition src/develop/noise_generator.h:72
const float const float param
Definition src/develop/noise_generator.h:108
void dt_drawlayer_cache_patch_wrunlock(const dt_drawlayer_cache_patch_t *patch)
Release write lock on shared patch cache entry.
Definition src/iop/drawlayer/cache.c:180
void dt_drawlayer_cache_patch_wrlock(const dt_drawlayer_cache_patch_t *patch)
Acquire write lock on shared patch cache entry.
Definition src/iop/drawlayer/cache.c:173
void dt_drawlayer_cache_patch_clear(dt_drawlayer_cache_patch_t *patch, const char *external_alloc_name)
Release patch storage and reset patch metadata.
Definition src/iop/drawlayer/cache.c:65
gboolean dt_drawlayer_cache_ensure_process_patch_buffer(dt_drawlayer_cache_patch_t *process_patch, dt_drawlayer_cache_patch_t *process_stroke_mask, const int width, const int height, const char *patch_buffer_name, const char *mask_buffer_name)
Ensure process patch and process-stroke-mask backing buffers exist.
Definition src/iop/drawlayer/cache.c:200
void dt_drawlayer_cache_patch_rdlock(const dt_drawlayer_cache_patch_t *patch)
Acquire read lock on shared patch cache entry.
Definition src/iop/drawlayer/cache.c:159
void dt_drawlayer_cache_patch_rdunlock(const dt_drawlayer_cache_patch_t *patch)
Release read lock on shared patch cache entry.
Definition src/iop/drawlayer/cache.c:166
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:789
int32_t unmuted
Definition darktable.h:759
dt_drawlayer_paint_stroke_t * stroke
Definition worker.c:101
dt_iop_module_t * self
Definition worker.c:99
dt_drawlayer_worker_t * worker
Definition worker.c:100
Per-worker callback vtable.
Definition worker.c:54
drawlayer_rt_sample_cb process_sample
Definition worker.c:56
const char * thread_name
Definition worker.c:55
drawlayer_rt_stroke_end_cb process_stroke_end
Definition worker.c:57
drawlayer_rt_idle_cb on_idle
Definition worker.c:58
dt_drawlayer_worker_t * rt
Definition worker.c:1278
One worker thread runtime including event ring buffer.
Definition worker.c:63
guint ring_head
Definition worker.c:68
guint ring_capacity
Definition worker.c:67
guint ring_count
Definition worker.c:70
pthread_t thread
Definition worker.c:64
guint ring_tail
Definition worker.c:69
gboolean stop
Definition worker.c:72
gboolean thread_started
Definition worker.c:65
dt_drawlayer_worker_state_t state
Definition worker.c:71
dt_drawlayer_paint_raw_input_t * ring
Definition worker.c:66
dt_pthread_rwlock_t history_mutex
Definition develop.h:252
Fully resolved input dab descriptor.
Definition brush.h:64
float x
Definition brush.h:65
float radius
Definition brush.h:69
int mode
Definition brush.h:83
float y
Definition brush.h:66
float opacity
Definition brush.h:74
Generic float RGBA patch stored either in malloc memory or pixel cache.
Definition iop/drawlayer/cache.h:37
int y
Definition iop/drawlayer/cache.h:39
int x
Definition iop/drawlayer/cache.h:38
int height
Definition iop/drawlayer/cache.h:41
float * pixels
Definition iop/drawlayer/cache.h:42
int width
Definition iop/drawlayer/cache.h:40
Integer axis-aligned rectangle in buffer coordinates.
Definition iop/drawlayer/paint.h:87
int se[2]
Definition iop/drawlayer/paint.h:90
int nw[2]
Definition iop/drawlayer/paint.h:89
gboolean valid
Definition iop/drawlayer/paint.h:88
Callback bundle used by stroke processing entry points.
Definition iop/drawlayer/paint.h:145
dt_drawlayer_paint_build_dab_cb build_dab
Definition iop/drawlayer/paint.h:146
Mutable stroke runtime state owned by worker/backend code.
Definition iop/drawlayer/paint.h:100
GArray * pending_dabs
Definition iop/drawlayer/paint.h:103
GArray * history
Definition iop/drawlayer/paint.h:101
float distance_percent
Definition iop/drawlayer/paint.h:112
GArray * dab_window
Definition iop/drawlayer/paint.h:105
dt_drawlayer_worker_state_t backend_state
Definition worker.h:40
guint backend_queue_count
Definition worker.h:41
gboolean commit_pending
Definition worker.h:42
Drawlayer worker global state shared with drawlayer module.
Definition worker.c:77
gboolean * finish_commit_pending
Definition worker.c:80
dt_drawlayer_damaged_rect_t * backend_path
Definition worker.c:89
uint32_t * current_stroke_batch
Definition worker.c:82
dt_drawlayer_cache_patch_t heartbeat_patch
Definition worker.c:90
guint * stroke_sample_count
Definition worker.c:81
GArray * stroke_raw_inputs
Definition worker.c:87
dt_drawlayer_cache_patch_t heartbeat_stroke_mask
Definition worker.c:91
drawlayer_rt_worker_t workers[DRAWLAYER_RT_WORKER_COUNT]
Definition worker.c:85
pthread_cond_t worker_cond
Definition worker.c:84
dt_drawlayer_damaged_rect_t live_publish_damage
Definition worker.c:94
uint32_t live_publish_serial
Definition worker.c:93
gint64 live_publish_ts
Definition worker.c:92
dt_pthread_mutex_t worker_mutex
Definition worker.c:83
GArray * backend_history
Definition worker.c:86
dt_iop_module_t * self
Definition worker.c:78
dt_drawlayer_paint_stroke_t * stroke
Definition worker.c:88
gboolean * painting
Definition worker.c:79
Definition src/iop/drawlayer/common.h:14
struct dt_develop_t * dev
Definition imageop.h:298
dt_iop_gui_data_t * gui_data
Definition imageop.h:313
dt_iop_params_t * params
Definition imageop.h:309
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
static void _backend_worker_on_idle(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Backend-worker idle hook.
Definition worker.c:1126
static gboolean _stroke_create(dt_drawlayer_worker_t *rt)
Create stroke runtime if missing.
Definition worker.c:411
#define DRAWLAYER_BATCH_TILE_SIZE
Definition worker.c:148
void(* drawlayer_rt_stroke_end_cb)(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Callback signature for stroke-end event processing.
Definition worker.c:48
void dt_drawlayer_worker_get_snapshot(const dt_drawlayer_worker_t *worker, dt_drawlayer_worker_snapshot_t *snapshot)
Return a thread-safe worker snapshot for runtime scheduling.
Definition worker.c:1566
static void _backend_worker_process_stroke_end(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Handle backend stroke end: flush, reset, and request commit.
Definition worker.c:1176
static gboolean _workers_active_locked(const dt_drawlayer_worker_t *rt)
Check whether workers still have pending activity (lock must be held).
Definition worker.c:1079
static void _copy_mask_damage_to_locked_patch(const dt_drawlayer_cache_patch_t *src, const dt_drawlayer_damaged_rect_t *local_damage, dt_drawlayer_cache_patch_t *dst)
Copy the written scratch mask sub-rectangle back into the locked base stroke mask.
Definition worker.c:686
static gboolean _worker_is_busy(const drawlayer_rt_worker_t *worker)
Definition worker.c:1040
static gboolean _translate_batch_damage(const dt_drawlayer_cache_patch_t *patch, const dt_drawlayer_damaged_rect_t *local_damage, dt_drawlayer_damaged_rect_t *absolute_damage)
Translate scratch-local damage coordinates back into base-patch coordinates.
Definition worker.c:647
static void _pause_worker(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Pause worker processing after current callback returns.
Definition worker.c:1429
static gboolean _rt_queue_full(const dt_drawlayer_worker_t *rt)
Test whether event queue is full.
Definition worker.c:1005
void dt_drawlayer_worker_stop(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Stop realtime and full-resolution worker threads.
Definition worker.c:1561
static guint _worker_batch_min_size(void)
Definition worker.c:495
static void _rt_destroy_state(dt_iop_module_t *self, dt_drawlayer_worker_t **rt_out)
Stop and free an existing worker state object.
Definition worker.c:1204
dt_drawlayer_paint_stroke_t * dt_drawlayer_worker_stroke(dt_drawlayer_worker_t *worker)
Read-only access to preserved stroke runtime.
Definition worker.c:1636
void dt_drawlayer_worker_cleanup(dt_drawlayer_worker_t **worker)
Public worker cleanup entry point.
Definition worker.c:1539
void dt_drawlayer_worker_reset_backend_path(dt_drawlayer_worker_t *worker)
Reset worker-owned backend damage accumulator.
Definition worker.c:1603
static guint _rasterize_pending_dab_batch(drawlayer_paint_backend_ctx_t *ctx, gint64 budget_us)
Definition worker.c:886
static gboolean _rt_queue_push_locked(dt_drawlayer_worker_t *rt, const dt_drawlayer_paint_raw_input_t *event)
Push one event in ring queue (lock must be held).
Definition worker.c:1012
drawlayer_rt_worker_kind_t
Internal worker slot kinds (currently backend only).
Definition worker.c:39
@ DRAWLAYER_RT_WORKER_COUNT
Definition worker.c:41
@ DRAWLAYER_RT_WORKER_BACKEND
Definition worker.c:40
static gboolean _backend_pending_dabs_locked(const dt_drawlayer_worker_t *rt)
Definition worker.c:1052
gboolean dt_drawlayer_worker_ensure_running(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Ensure realtime/backend worker threads are started.
Definition worker.c:1556
static gboolean _live_publish_deadline_reached(const dt_drawlayer_worker_t *rt, const gint64 input_ts, const gint64 interval_us)
Definition worker.c:525
static gboolean _start_worker(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Start backend worker thread if not running.
Definition worker.c:1364
static gboolean _enqueue_event(dt_iop_module_t *self, dt_drawlayer_worker_t *rt, const dt_drawlayer_paint_raw_input_t *event)
Generic enqueue helper ensuring worker startup.
Definition worker.c:1457
static void _clear_mask_damage_in_patch(dt_drawlayer_cache_patch_t *patch, const dt_drawlayer_damaged_rect_t *local_damage)
Clear only the flushed alpha-mask sub-rectangle in the heartbeat scratch mask.
Definition worker.c:726
static void _clear_rgba_damage_in_patch(dt_drawlayer_cache_patch_t *patch, const dt_drawlayer_damaged_rect_t *local_damage)
Clear only the flushed RGBA sub-rectangle in the heartbeat scratch patch.
Definition worker.c:709
static void _copy_mask_batch_from_locked_patch(const dt_drawlayer_cache_patch_t *src, dt_drawlayer_cache_patch_t *dst)
Copy one locked alpha-mask source region into the heartbeat scratch mask.
Definition worker.c:620
static void _reset_backend_path(dt_drawlayer_worker_t *rt)
Definition worker.c:467
gboolean dt_drawlayer_worker_enqueue_stroke_end(dt_drawlayer_worker_t *worker, const dt_drawlayer_paint_raw_input_t *input)
Public FIFO enqueue for stroke-end event.
Definition worker.c:1661
static void _process_backend_input(dt_iop_module_t *self, const dt_drawlayer_paint_raw_input_t *input, dt_drawlayer_paint_stroke_t *stroke)
Definition worker.c:325
#define DRAWLAYER_HEARTBEAT_MASK_NAME
Definition worker.c:150
static void _cancel_async_commit(dt_drawlayer_worker_t *rt)
Cancel deferred commit request state if any.
Definition worker.c:1393
#define DRAWLAYER_HEARTBEAT_PATCH_NAME
Definition worker.c:149
void dt_drawlayer_worker_init(dt_iop_module_t *self, dt_drawlayer_worker_t **worker, gboolean *painting, gboolean *finish_commit_pending, guint *stroke_sample_count, uint32_t *current_stroke_batch)
Public worker initialization entry point.
Definition worker.c:1531
static drawlayer_rt_worker_t * _backend_worker(dt_drawlayer_worker_t *rt)
Definition worker.c:480
static gboolean _workers_any_active_locked(const dt_drawlayer_worker_t *rt)
Check whether any worker activity remains.
Definition worker.c:1088
static void * _drawlayer_worker_main(void *user_data)
Worker main loop: FIFO dequeue, process, and idle scheduling.
Definition worker.c:1282
static gboolean _collect_batch_bounds(const GArray *dabs, const guint max_dabs, const dt_drawlayer_cache_patch_t *patch, dt_drawlayer_damaged_rect_t *batch_bounds)
Build the scratch patch bounds that cover the next heartbeat dab batch.
Definition worker.c:559
static void _paint_stroke_seed_cb(void *user_data, uint64_t stroke_seed)
Definition worker.c:289
static void _rt_set_worker_state(dt_drawlayer_worker_t *rt, const dt_drawlayer_worker_state_t state)
Set worker state atomically under caller synchronization.
Definition worker.c:1058
void dt_drawlayer_worker_flush_pending(dt_drawlayer_worker_t *worker)
Flush pending backend stroke inputs synchronously.
Definition worker.c:1592
static gboolean _rt_workers_any_active(dt_drawlayer_worker_t *rt)
Thread-safe wrapper for any worker activity.
Definition worker.c:1115
static void _rt_cleanup_state(dt_drawlayer_worker_t **rt_out)
Destroy worker state object and all owned resources.
Definition worker.c:1254
void(* drawlayer_rt_sample_cb)(dt_iop_module_t *self, dt_drawlayer_worker_t *rt, const dt_drawlayer_paint_raw_input_t *input)
Callback signature for one raw-input event processing.
Definition worker.c:45
static void _copy_rgba_batch_from_locked_patch(const dt_drawlayer_cache_patch_t *src, dt_drawlayer_cache_patch_t *dst)
Copy one locked RGBA source region into the heartbeat scratch patch.
Definition worker.c:602
static gboolean _dab_bounds_in_patch(const dt_drawlayer_cache_patch_t *patch, float scale, const dt_drawlayer_brush_dab_t *dab, dt_drawlayer_damaged_rect_t *bounds)
Definition worker.c:541
static void _reset_live_publish(dt_drawlayer_worker_t *rt)
Definition worker.c:472
static gboolean _enqueue_input(dt_iop_module_t *self, dt_drawlayer_worker_t *rt, const dt_drawlayer_paint_raw_input_t *input)
Enqueue raw input with saturation policy and stroke-abort fallback.
Definition worker.c:1471
static void _backend_worker_process_sample(dt_iop_module_t *self, dt_drawlayer_worker_t *rt, const dt_drawlayer_paint_raw_input_t *input)
Process one backend raw input event.
Definition worker.c:1161
static gboolean _worker_pause_requested(const drawlayer_rt_worker_t *worker)
Definition worker.c:1045
static gboolean _rt_workers_active(dt_drawlayer_worker_t *rt)
Thread-safe wrapper for active-workers status.
Definition worker.c:1104
gboolean dt_drawlayer_worker_active(const dt_drawlayer_worker_t *worker)
Public status query: TRUE when worker has pending activity.
Definition worker.c:1545
static void _set_current_thread_realtime_best_effort(void)
Try elevating current thread scheduling policy for lower-latency input.
Definition worker.c:1065
static void _stop_worker(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Stop worker thread and clear transient state.
Definition worker.c:1403
static gboolean _workers_ready_for_commit_locked(const dt_drawlayer_worker_t *rt)
Check if workers are idle and commit can be safely scheduled.
Definition worker.c:1094
void dt_drawlayer_worker_publish_backend_stroke_damage(dt_iop_module_t *self)
Publish accumulated backend stroke damage into drawlayer process/runtime state.
Definition worker.c:355
static void _rt_queue_clear_locked(dt_drawlayer_worker_t *rt)
Clear queued events (lock must be held).
Definition worker.c:988
void dt_drawlayer_worker_request_commit(dt_drawlayer_worker_t *worker)
Public commit request helper.
Definition worker.c:1582
gboolean dt_drawlayer_worker_any_active(const dt_drawlayer_worker_t *worker)
Public status query: TRUE when any worker still has pending activity.
Definition worker.c:1551
gboolean dt_drawlayer_worker_enqueue_input(dt_drawlayer_worker_t *worker, const dt_drawlayer_paint_raw_input_t *input)
Public FIFO enqueue for one raw input event.
Definition worker.c:1654
void dt_drawlayer_worker_reset_live_publish(dt_drawlayer_worker_t *worker)
Reset worker-owned transient live-publish state.
Definition worker.c:1611
guint dt_drawlayer_worker_pending_dab_count(const dt_drawlayer_worker_t *worker)
Return the number of interpolated-but-not-yet-rasterized dabs in the current stroke batch.
Definition worker.c:1641
GArray * dt_drawlayer_worker_raw_inputs(dt_drawlayer_worker_t *worker)
Read-only access to preserved raw input history.
Definition worker.c:1630
static gboolean _process_backend_dab(const dt_drawlayer_brush_dab_t *dab, drawlayer_paint_backend_ctx_t *ctx, const dt_drawlayer_cache_patch_t *sample_patch, dt_drawlayer_cache_patch_t *patch, dt_drawlayer_cache_patch_t *stroke_mask, dt_drawlayer_damaged_rect_t *batch_damage)
Definition worker.c:368
static void _publish_backend_progress(drawlayer_paint_backend_ctx_t *ctx, gboolean flush_pending)
Definition worker.c:296
static gboolean _rt_queue_empty(const dt_drawlayer_worker_t *rt)
Test whether event queue is empty.
Definition worker.c:998
static gboolean _paint_layer_to_widget_cb(void *user_data, float lx, float ly, float *wx, float *wy)
Definition worker.c:283
static gboolean _enqueue_stroke_end(dt_iop_module_t *self, dt_drawlayer_worker_t *rt, const dt_drawlayer_paint_raw_input_t *input)
Enqueue explicit stroke-end event (with optional raw release sample).
Definition worker.c:1514
static void _resume_worker(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Resume worker processing and wake sleeping thread.
Definition worker.c:1444
static gint64 _live_publish_interval_us(void)
Definition worker.c:490
void dt_drawlayer_worker_seal_for_commit(dt_drawlayer_worker_t *worker)
Seal current stroke for synchronous commit.
Definition worker.c:1598
static gboolean _paint_build_dab_cb(void *user_data, dt_drawlayer_paint_stroke_t *state, const dt_drawlayer_paint_raw_input_t *input, dt_drawlayer_brush_dab_t *out_dab)
Definition worker.c:273
static const drawlayer_rt_worker_t * _backend_worker_const(const dt_drawlayer_worker_t *rt)
Definition worker.c:485
static void _log_worker_batch_timing(const char *tag, guint processed_dabs, guint thread_count, double elapsed_ms, gboolean outer_loop)
Definition worker.c:517
static gboolean _worker_is_started(const drawlayer_rt_worker_t *worker)
Definition worker.c:1035
void dt_drawlayer_worker_reset_stroke(dt_drawlayer_worker_t *worker)
Clear preserved stroke runtime/history after commit completed.
Definition worker.c:1620
static gboolean _ensure_heartbeat_batch_buffers(dt_drawlayer_worker_t *rt, const dt_drawlayer_damaged_rect_t *batch_bounds)
Ensure worker-private heartbeat scratch buffers match the requested batch bounds.
Definition worker.c:581
void(* drawlayer_rt_idle_cb)(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Callback signature for idle transitions inside worker loop.
Definition worker.c:50
static void _rt_init_state(dt_iop_module_t *self, dt_drawlayer_worker_t **rt_out, gboolean *painting, gboolean *finish_commit_pending, guint *stroke_sample_count, uint32_t *current_stroke_batch)
Allocate and initialize worker state object and buffers.
Definition worker.c:1224
static gboolean _stroke_begin(dt_drawlayer_worker_t *rt)
Start new stroke runtime and reset history/path state.
Definition worker.c:436
gboolean dt_drawlayer_build_worker_input_dab(dt_iop_module_t *self, dt_drawlayer_paint_stroke_t *state, const dt_drawlayer_paint_raw_input_t *input, dt_drawlayer_brush_dab_t *dab)
Definition worker.c:153
static drawlayer_paint_backend_ctx_t _make_backend_ctx(dt_iop_module_t *self, dt_drawlayer_worker_t *worker, dt_drawlayer_paint_stroke_t *stroke)
Definition worker.c:531
static void _stroke_destroy(dt_drawlayer_worker_t *rt)
Destroy stroke runtime and owned dab window.
Definition worker.c:394
static gboolean _wait_worker_idle(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Wait until worker queue is drained and not busy.
Definition worker.c:1260
static gboolean _rt_queue_pop_locked(dt_drawlayer_worker_t *rt, dt_drawlayer_paint_raw_input_t *event)
Pop one event from ring queue (lock must be held).
Definition worker.c:1024
static const drawlayer_rt_callbacks_t _rt_callbacks[DRAWLAYER_RT_WORKER_COUNT]
Definition worker.c:390
static void _copy_rgba_damage_to_locked_patch(const dt_drawlayer_cache_patch_t *src, const dt_drawlayer_damaged_rect_t *local_damage, dt_drawlayer_cache_patch_t *dst)
Copy the written scratch sub-rectangle back into the locked base patch.
Definition worker.c:663
#define DRAWLAYER_OUTER_LIVE_BATCH_MULTIPLIER
Definition worker.c:151
static void _stroke_clear(dt_drawlayer_worker_t *rt)
Clear current stroke state while preserving allocations.
Definition worker.c:455
dt_drawlayer_worker_state_t
Definition worker.h:31
@ DT_DRAWLAYER_WORKER_STATE_STOPPED
Definition worker.h:32
@ DT_DRAWLAYER_WORKER_STATE_IDLE
Definition worker.h:33
@ DT_DRAWLAYER_WORKER_STATE_BUSY
Definition worker.h:34
@ DT_DRAWLAYER_WORKER_STATE_PAUSED
Definition worker.h:36
@ DT_DRAWLAYER_WORKER_STATE_PAUSING
Definition worker.h:35