60#include <glib/gstdio.h>
118#define _commit_dabs dt_drawlayer_commit_dabs
119#define _flush_layer_cache dt_drawlayer_flush_layer_cache
120#define _sync_widget_cache dt_drawlayer_sync_widget_cache
121#define _set_drawlayer_pipeline_realtime_mode dt_drawlayer_set_pipeline_realtime_mode
122#define _ensure_layer_cache dt_drawlayer_ensure_layer_cache
123#define _release_all_base_patch_extra_refs dt_drawlayer_release_all_base_patch_extra_refs
124#define _drawlayer_wait_for_rasterization_modal dt_drawlayer_wait_for_rasterization_modal
125#define _current_live_padding dt_drawlayer_current_live_padding
126#define _layer_to_widget_coords dt_drawlayer_layer_to_widget_coords
127#define _touch_stroke_commit_hash dt_drawlayer_touch_stroke_commit_hash
128#define _drawlayer_runtime_collect_inputs NULL
129#define _drawlayer_runtime_perform_action NULL
138 char *
name,
size_t name_size);
145 gboolean flush_pending);
159 if(!display_rgb ||
IS_NULL_PTR(pipeline_rgb))
return;
161 pipeline_rgb[0] =
_clamp01(display_rgb[0]);
162 pipeline_rgb[1] =
_clamp01(display_rgb[1]);
163 pipeline_rgb[2] =
_clamp01(display_rgb[2]);
173 float in[4] = { pipeline_rgb[0], pipeline_rgb[1], pipeline_rgb[2], 0.0f };
174 float out[4] = { pipeline_rgb[0], pipeline_rgb[1], pipeline_rgb[2], 0.0f };
176 "drawlayer brush color");
177 pipeline_rgb[0] =
out[0];
178 pipeline_rgb[1] =
out[1];
179 pipeline_rgb[2] =
out[2];
184 pipeline_rgb[0] *= gain;
185 pipeline_rgb[1] *= gain;
186 pipeline_rgb[2] *= gain;
195 g->ui.brush_display_color[0] =
_clamp01(display_rgb[0]);
196 g->ui.brush_display_color[1] =
_clamp01(display_rgb[1]);
197 g->ui.brush_display_color[2] =
_clamp01(display_rgb[2]);
199 g->ui.brush_color_valid =
TRUE;
207 uint32_t map_flags = 0u;
221 float display_rgb[3] = { 0.0f };
222 float pipeline_rgb[3] = { 0.0f };
225 memcpy(display_rgb,
g->ui.brush_display_color,
sizeof(display_rgb));
226 memcpy(pipeline_rgb,
g->ui.brush_pipeline_color,
sizeof(pipeline_rgb));
234 memcpy(display_rgb,
g->ui.brush_display_color,
sizeof(display_rgb));
235 memcpy(pipeline_rgb,
g->ui.brush_pipeline_color,
sizeof(pipeline_rgb));
240 display_rgb[0] =
_clamp01(display_rgb[0]);
241 display_rgb[1] =
_clamp01(display_rgb[1]);
242 display_rgb[2] =
_clamp01(display_rgb[2]);
261 input->
color[0] = pipeline_rgb[0];
262 input->
color[1] = pipeline_rgb[1];
263 input->
color[2] = pipeline_rgb[2];
288 "[drawlayer] raw-input batch=%u event=%u pos=%u widget=(%.3f,%.3f) raster=(%.3f,%.3f) ok=%d\n",
297 g_strlcpy(tmp,
name,
sizeof(tmp));
299 return tmp[0] !=
'\0';
303 char *
key,
const size_t key_size)
312 g_snprintf(
key, key_size,
"%d|%d|%s", (
int)work_profile->
type, (
int)work_profile->
intent,
314 return key[0] !=
'\0';
345 scratch = g_malloc0(
sizeof(*scratch));
353 int *layer_height,
int *origin_x,
int *origin_y)
365 int resolved_width = 0;
366 int resolved_height = 0;
394 if(!
IS_NULL_PTR(layer_width)) *layer_width = resolved_width;
395 if(!
IS_NULL_PTR(layer_height)) *layer_height = resolved_height;
396 return resolved_width > 0 && resolved_height > 0;
400 const int layer_width,
const int layer_height)
409 hash =
dt_hash(hash, (
const char *)&imgid,
sizeof(imgid));
410 hash =
dt_hash(hash, (
const char *)&layer_width,
sizeof(layer_width));
411 hash =
dt_hash(hash, (
const char *)&layer_height,
sizeof(layer_height));
418 return hash ? hash : 1u;
429 const uint64_t new_hash = _drawlayer_params_cache_hash(imgid, params, patch->
width, patch->
height);
451 patch->
width, patch->
height,
"drawlayer sidecar cache", &created))
464 "[drawlayer] cache rekey conflict old=%" PRIu64
" new=%" PRIu64
" -> published snapshot instead\n",
473 g->process.base_patch_loaded_ref =
TRUE;
480 g->process.base_patch_stroke_refs++;
491 g->process.base_patch_loaded_ref =
FALSE;
492 g->process.base_patch_stroke_refs = 0;
496 if(
g->process.base_patch_loaded_ref)
499 g->process.base_patch_loaded_ref =
FALSE;
502 while(
g->process.base_patch_stroke_refs > 0)
505 g->process.base_patch_stroke_refs--;
514 if(
params->layer_name[0] ==
'\0')
546 const gboolean have_sidecar = have_sidecar_path && g_file_test(path, G_FILE_TEST_EXISTS);
552 int layer_height = 0;
553 const gboolean have_pipe_geometry = _resolve_layer_geometry(self, pipe, piece, &layer_width, &layer_height, NULL, NULL);
563 layer_width = (int)info.
width;
564 layer_height = (int)info.
height;
566 else if(!have_pipe_geometry)
569 else if(!have_pipe_geometry)
573 layer_width = (int)info.
width;
574 layer_height = (int)info.
height;
595 if(layer_width > 0 && layer_height > 0)
601 (
size_t)layer_width * layer_height, layer_width, layer_height,
602 "drawlayer sidecar cache", &created))
614 gboolean warm_loaded =
FALSE;
615 if(have_sidecar && info.
found)
625 layer_height, &warm_patch);
652 const gboolean use_preview_bg,
const float preview_bg)
656 const dt_aligned_pixel_simd_t preview_base = { preview_bg, preview_bg, preview_bg, 1.0f };
658 for(
size_t kk = 0; kk < pixels; kk++)
660 const float *base = input + 4 * kk;
661 const float *layer = layerbuf + 4 * kk;
662 float *pixel = output + 4 * kk;
663 const float src_alpha =
_clamp01(layer[3]);
664 if(src_alpha > 1e-8f)
666 const dt_aligned_pixel_simd_t base_v = use_preview_bg ? preview_base : dt_load_simd_aligned(base);
667 dt_aligned_pixel_simd_t src_v = dt_load_simd_aligned(layer);
668 const float inv_alpha = 1.0f - src_alpha;
669 const dt_aligned_pixel_simd_t inv_alpha_v = { inv_alpha, inv_alpha, inv_alpha, inv_alpha };
670 src_v[3] = src_alpha;
675 const dt_aligned_pixel_simd_t base_v = use_preview_bg ? preview_base : dt_load_simd_aligned(base);
695 if(dirty_rect && dirty_rect->
valid)
697 const int dirty_x0 = CLAMP(dirty_rect->
nw[0], 0,
width);
698 const int dirty_y0 = CLAMP(dirty_rect->
nw[1], 0,
height);
699 const int dirty_x1 = CLAMP(dirty_rect->
se[0], 0,
width);
700 const int dirty_y1 = CLAMP(dirty_rect->
se[1], 0,
height);
701 const int dirty_w = dirty_x1 - dirty_x0;
702 const int dirty_h = dirty_y1 - dirty_y0;
703 if(dirty_w > 0 && dirty_h > 0 && (dirty_w <
width || dirty_h <
height))
705 const size_t origin[] = { (size_t)dirty_x0, (
size_t)dirty_y0, 0 };
706 const size_t region[] = { (size_t)dirty_w, (
size_t)dirty_h, 1 };
707 char *host_origin = (
char *)host_pixels + ((
size_t)dirty_y0 *
width + dirty_x0) * (
size_t)
bpp;
709 CL_TRUE) == CL_SUCCESS)
726 const gboolean force_device_copy,
const gboolean realtime_reuse,
727 const int source_w,
const int source_h,
734 if(force_device_copy)
744 if(realtime_reuse && resolved_entry)
747 gboolean reused_from_cache =
FALSE;
749 "drawlayer source", resolved_entry,
750 &reused_from_cache, NULL);
754 = (reused_from_cache &&
process) ? &
process->cache_dirty_rect : NULL;
756 4 *
sizeof(
float), dirty_rect))
769 4 *
sizeof(
float), CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, NULL);
777 devid, source_w, source_h, 4 *
sizeof(
float), (
void *)layer_pixels, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR);
781 4 *
sizeof(
float), NULL))
796 const int source_w,
const int source_h,
800 const gboolean can_copy_crop
801 = (fabs(target_roi->
scale - 1.0) <= 1e-6 && target_roi->
x >= 0
802 && target_roi->
y >= 0 && target_roi->
x + target_roi->
width <= source_w
803 && target_roi->
y + target_roi->
height <= source_h);
806 size_t src_origin[3] = { (size_t)target_roi->
x, (
size_t)target_roi->
y, 0 };
807 size_t dst_origin[3] = { 0, 0, 0 };
808 size_t region[3] = { (size_t)target_roi->
width, (
size_t)target_roi->
height, 1 };
811 if(copy_err == CL_SUCCESS)
return CL_SUCCESS;
826 const gboolean realtime_reuse,
const gboolean direct_copy,
827 cl_mem dev_source_rgba,
const int source_w,
const int source_h,
837 layer->
mem = dev_source_rgba;
841 if(realtime_reuse && resolved_entry)
844 "drawlayer layer", resolved_entry, NULL,
856 *err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
862 return *err == CL_SUCCESS;
866 cl_mem dev_background, cl_mem dev_layer_rgba, cl_mem dev_out,
867 const int width,
const int height,
const int background_offset_x,
868 const int background_offset_y)
870 const int offs[2] = { background_offset_x, background_offset_y };
879 if(err != CL_SUCCESS)
return err;
889#define DRAWLAYER_RESAMPLE_DAMAGE_MARGIN 8
906 const double scale = target_roi->
scale;
910 const double sx0 = (
double)src_damage->
nw[0] + source_roi->
x;
911 const double sy0 = (
double)src_damage->
nw[1] + source_roi->
y;
912 const double sx1 = (
double)src_damage->
se[0] + source_roi->
x;
913 const double sy1 = (
double)src_damage->
se[1] + source_roi->
y;
915 int tx0 = (int)floor(sx0 * scale - target_roi->
x) - margin;
916 int ty0 = (int)floor(sy0 * scale - target_roi->
y) - margin;
917 int tx1 = (int)ceil(sx1 * scale - target_roi->
x) + margin;
918 int ty1 = (int)ceil(sy1 * scale - target_roi->
y) + margin;
920 tx0 = CLAMP(tx0, 0, target_roi->
width);
921 ty0 = CLAMP(ty0, 0, target_roi->
height);
922 tx1 = CLAMP(tx1, 0, target_roi->
width);
923 ty1 = CLAMP(ty1, 0, target_roi->
height);
925 if(tx1 <= tx0 || ty1 <= ty0)
return FALSE;
927 if(tx0 == 0 && ty0 == 0 && tx1 == target_roi->
width && ty1 == target_roi->
height)
return FALSE;
936 cl_mem source_mem_override,
const int source_w,
const int source_h,
939 const gboolean direct_copy,
const gboolean use_preview_bg,
940 const float preview_bg,
const gboolean realtime_reuse,
941 const gboolean force_device_copy,
const gboolean allow_partial)
944 || source_h <= 0 || !target_roi || target_roi->width <= 0 || target_roi->
height <= 0)
946 if(kernel_premult_over < 0)
return FALSE;
949 gboolean resolved_entry_ref =
FALSE;
950 if(realtime_reuse && !resolved_entry)
954 resolved_entry_ref = (!
IS_NULL_PTR(resolved_entry));
964 const gboolean partial = allow_partial && !use_preview_bg && !direct_copy && !source_mem_override &&
process
966 source_roi, &target_damage);
970 cl_mem dev_layer_partial = NULL;
971 cl_mem dev_bg_partial = NULL;
972 cl_mem dev_out_partial = NULL;
973 cl_mem dev_background = NULL;
974 int err = CL_SUCCESS;
976 if(source_mem_override)
977 source.
mem = source_mem_override;
979 source_w, source_h,
process, &source))
984 const int dw = target_damage.
se[0] - target_damage.
nw[0];
985 const int dh = target_damage.
se[1] - target_damage.
nw[1];
986 size_t win_origin[3] = { (size_t)target_damage.
nw[0], (
size_t)target_damage.
nw[1], 0 };
987 size_t zero_origin[3] = { 0, 0, 0 };
988 size_t win_region[3] = { (size_t)dw, (
size_t)dh, 1 };
1003 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
1010 .
x = target_roi->
x + target_damage.
nw[0],
1011 .y = target_roi->
y + target_damage.
nw[1],
1014 .scale = target_roi->
scale,
1017 &sub_target_roi, source_roi);
1018 if(err != CL_SUCCESS)
goto cleanup;
1021 if(err != CL_SUCCESS)
goto cleanup;
1024 dev_out_partial, dw, dh, 0, 0);
1025 if(err != CL_SUCCESS)
goto cleanup;
1028 if(err != CL_SUCCESS)
goto cleanup;
1032 target_damage.
nw[0], target_damage.
nw[1], target_roi->
width, target_roi->
height);
1047 source_h, target_roi, source_roi, &layer, &err))
1052 const size_t out_pixels = (size_t)target_roi->
width * target_roi->
height;
1055 "drawlayer process scratch");
1058 for(
size_t kk = 0; kk < out_pixels; kk++)
1060 float *pixel = background + 4 * kk;
1061 pixel[0] = preview_bg;
1062 pixel[1] = preview_bg;
1063 pixel[2] = preview_bg;
1068 4 *
sizeof(
float), CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, NULL);
1072 dev_background = dev_in;
1076 if(err != CL_SUCCESS)
goto cleanup;
1099 (
void **)&dev_background);
1100 if(layer.
mem && layer.
mem != source.
mem)
1107 if(!source_mem_override && source.
is_pinned)
1109 (
void **)&source.
mem);
1112 else if(!source_mem_override && source.
mem)
1114 if(resolved_entry_ref)
1128 for(
const unsigned char *c = (
const unsigned char *)
value; *c; c++)
1132 else if(!g_ascii_isprint(*c))
1136 return separators >= 2;
1141 if(
IS_NULL_PTR(path) || path[0] ==
'\0' || !g_file_test(path, G_FILE_TEST_EXISTS))
return 0;
1143 GStatBuf st = { 0 };
1144 if(g_stat(path, &st) != 0)
return 0;
1145 return (int64_t)st.st_mtime;
1149 const float hardness)
1155 float display_rgb[3] = { 0.0f };
1158 const int size_px =
MAX(2, (
int)ceil((2.0f * widget_radius + 2.0f) * ppd));
1160 const gboolean needs_rebuild
1161 = !
g->ui.cursor_surface ||
g->ui.cursor_surface_size != size_px || fabs(
g->ui.cursor_surface_ppd - ppd) > 1e-9
1162 || fabsf(
g->ui.cursor_radius - widget_radius) > 1e-3f || fabsf(
g->ui.cursor_opacity - opacity) > 1e-6f
1163 || fabsf(
g->ui.cursor_hardness - hardness) > 1e-6f ||
g->ui.cursor_shape != shape
1164 || fabsf(
g->ui.cursor_color[0] - display_rgb[0]) > 1e-6f || fabsf(
g->ui.cursor_color[1] - display_rgb[1]) > 1e-6f
1165 || fabsf(
g->ui.cursor_color[2] - display_rgb[2]) > 1e-6f;
1166 if(!needs_rebuild)
return;
1169 g->ui.cursor_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size_px, size_px);
1170 if(cairo_surface_status(
g->ui.cursor_surface) != CAIRO_STATUS_SUCCESS)
1175 cairo_surface_set_device_scale(
g->ui.cursor_surface, ppd, ppd);
1177 unsigned char *data = cairo_image_surface_get_data(
g->ui.cursor_surface);
1178 const int stride = cairo_image_surface_get_stride(
g->ui.cursor_surface);
1179 memset(data, 0, (
size_t)stride * size_px);
1182 .
radius = fmaxf(widget_radius * (
float)ppd, 0.5f),
1184 .hardness = hardness,
1186 .display_color = { display_rgb[0], display_rgb[1], display_rgb[2] },
1189 const float half = 0.5f * (float)size_px;
1191 cairo_surface_mark_dirty(
g->ui.cursor_surface);
1193 g->ui.cursor_surface_size = size_px;
1194 g->ui.cursor_surface_ppd = ppd;
1195 g->ui.cursor_radius = widget_radius;
1196 g->ui.cursor_opacity = opacity;
1197 g->ui.cursor_hardness = hardness;
1198 g->ui.cursor_shape = shape;
1199 g->ui.cursor_color[0] = display_rgb[0];
1200 g->ui.cursor_color[1] = display_rgb[1];
1201 g->ui.cursor_color[2] = display_rgb[2];
1211 if(
main) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(
main));
1212 gtk_window_set_modal(GTK_WINDOW(dialog),
TRUE);
1213 gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog),
TRUE);
1214 gtk_window_set_deletable(GTK_WINDOW(dialog),
FALSE);
1215 gtk_window_set_resizable(GTK_WINDOW(dialog),
FALSE);
1216 gtk_window_set_title(GTK_WINDOW(dialog), title);
1217 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
1219 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1222 GtkWidget *label = gtk_label_new(message);
1223 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1224 gtk_box_pack_start(GTK_BOX(box), spinner,
FALSE,
FALSE, 0);
1225 gtk_box_pack_start(GTK_BOX(box), label,
TRUE,
TRUE, 0);
1227 gtk_box_pack_start(GTK_BOX(content), box,
TRUE,
TRUE, 0);
1228 gtk_spinner_start(GTK_SPINNER(spinner));
1229 gtk_widget_show_all(dialog);
1230 gtk_widget_show_now(dialog);
1231 gtk_window_present(GTK_WINDOW(dialog));
1232 GdkDisplay *display = gtk_widget_get_display(dialog);
1233 if(display) gdk_display_flush(display);
1238 for(
int k = 0;
k < 2;
k++)
1239 gtk_main_iteration_do(
FALSE);
1256 g_main_loop_quit(
state->loop);
1257 return G_SOURCE_REMOVE;
1260 return G_SOURCE_CONTINUE;
1264 const char *title,
const char *message)
1269 GMainLoop *loop = g_main_loop_new(NULL,
FALSE);
1277 g_main_loop_run(loop);
1279 if(source_id) g_source_remove(source_id);
1282 gtk_widget_destroy(wait.
dialog);
1285 g_main_loop_unref(loop);
1293 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1294 type, GTK_BUTTONS_OK,
"%s", primary);
1295 if(secondary && secondary[0] !=
'\0')
1296 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
"%s", secondary);
1297 gtk_dialog_run(GTK_DIALOG(dialog));
1298 gtk_widget_destroy(dialog);
1302 char *
name,
const size_t name_size)
1306 GtkWidget *dialog = gtk_dialog_new_with_buttons(
1308 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, _(
"Cancel"), GTK_RESPONSE_CANCEL,
1309 _(
"Confirm"), GTK_RESPONSE_ACCEPT, NULL);
1310 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1315 GtkWidget *label = gtk_label_new(message);
1316 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1317 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
1318 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
FALSE, 0);
1320 gtk_entry_set_activates_default(GTK_ENTRY(entry),
TRUE);
1321 if(initial_name && initial_name[0] !=
'\0') gtk_entry_set_text(GTK_ENTRY(entry), initial_name);
1322 gtk_box_pack_start(GTK_BOX(box), entry,
FALSE,
FALSE, 0);
1324 gtk_box_pack_start(GTK_BOX(content), box,
TRUE,
TRUE, 0);
1325 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1326 gtk_widget_show_all(dialog);
1328 gboolean accepted =
FALSE;
1329 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1335 gtk_widget_destroy(dialog);
1344 float display_rgb[3] = { 0.0f };
1373 float display_rgb[3] = { 0.0f };
1387 gtk_widget_queue_draw(
g->controls.brush_shape);
1412 gtk_widget_queue_draw(widget);
1417 const float working_rgb[3],
float display_rgb[3])
1422 const float inv_gain = (gain > 0.0f) ? 1.0f / gain : 1.0f;
1423 const float preview_rgb[3] = {
1424 working_rgb[0] * inv_gain,
1425 working_rgb[1] * inv_gain,
1426 working_rgb[2] * inv_gain,
1429 display_rgb[0] =
_clamp01(preview_rgb[0]);
1430 display_rgb[1] =
_clamp01(preview_rgb[1]);
1431 display_rgb[2] =
_clamp01(preview_rgb[2]);
1440 float in[4] = { preview_rgb[0], preview_rgb[1], preview_rgb[2], 0.0f };
1441 float out[4] = { preview_rgb[0], preview_rgb[1], preview_rgb[2], 0.0f };
1457 const float *picked_min
1459 const float *picked_max
1461 if(picked_max[0] < picked_min[0])
return;
1463 float display_rgb[3] = { 0.0f };
1484 float display_rgb[3] = { 0.0f };
1504 if(memchr(params->layer_name,
'\0',
sizeof(params->layer_name)) == NULL)
1505 memset(params->layer_name, 0,
sizeof(params->layer_name));
1507 params->layer_name[
sizeof(params->layer_name) - 1] =
'\0';
1511 if(g_strcmp0(params->layer_name, sanitized_layer_name))
1512 g_strlcpy(params->layer_name, sanitized_layer_name,
sizeof(params->layer_name));
1514 if(memchr(params->work_profile,
'\0',
sizeof(params->work_profile)) == NULL)
1515 memset(params->work_profile, 0,
sizeof(params->work_profile));
1517 params->work_profile[
sizeof(params->work_profile) - 1] =
'\0';
1521 params->layer_name[0] =
'\0';
1522 params->layer_order = -1;
1523 params->sidecar_timestamp = 0;
1525 if(params->layer_order < -1) params->layer_order = -1;
1527 memset(params->work_profile, 0,
sizeof(params->work_profile));
1530 if(params->layer_order < 0 && params->stroke_commit_hash == 0u)
1531 memset(params->work_profile, 0,
sizeof(params->work_profile));
1533 if(params->work_profile[0] ==
'\0' && !
IS_NULL_PTR(self) && self->
dev)
1537 sizeof(current_profile)))
1538 g_strlcpy(params->work_profile, current_profile,
sizeof(params->work_profile));
1546 if(!(!
IS_NULL_PTR(requested) && requested[0]))
return;
1548 gboolean last_was_space =
FALSE;
1550 for(
size_t in = 0; requested[in] !=
'\0' &&
out + 1 < name_size; in++)
1552 const unsigned char ch = (
unsigned char)requested[in];
1553 if(g_ascii_isspace(
ch))
1555 if(
out > 0 && !last_was_space)
1558 last_was_space =
TRUE;
1564 last_was_space =
FALSE;
1597 .width =
process->base_patch.width,
1598 .height =
process->base_patch.height,
1628 const int preview_mode = (gui && self && self->
dev && self->
dev->
gui_module == self)
1640 const gboolean have_last_dab,
const float last_dab_x,
1641 const float last_dab_y,
const uint32_t publish_serial)
1645 uint32_t x_bits = 0u;
1646 uint32_t y_bits = 0u;
1649 memcpy(&x_bits, &last_dab_x,
sizeof(x_bits));
1650 memcpy(&y_bits, &last_dab_y,
sizeof(y_bits));
1653 const uint32_t seed[5] = { (uint32_t)dab_count, have_last_dab ? 1u : 0u, x_bits, y_bits, publish_serial };
1655 uint64_t hash = params->stroke_commit_hash ? params->stroke_commit_hash : 5381u;
1656 hash =
dt_hash(hash, (
const char *)seed,
sizeof(seed));
1660 params->stroke_commit_hash = (uint32_t)(hash ? hash : 1u);
1667 GMainContext *
const ui_ctx = g_main_context_default();
1670 g->manager.background_job_running =
g->session.background_job_running;
1683 const gboolean missing = (
g->session.missing_layer_error[0] !=
'\0');
1686 if(
g->controls.notebook)
1688 if(
g->controls.brush_tab) gtk_widget_set_visible(
g->controls.brush_tab, attached);
1689 if(
g->controls.input_tab) gtk_widget_set_visible(
g->controls.input_tab, attached);
1690 if(
g->controls.layer_tab) gtk_widget_set_visible(
g->controls.layer_tab,
TRUE);
1691 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(
g->controls.notebook), attached);
1692 gtk_notebook_set_show_border(GTK_NOTEBOOK(
g->controls.notebook), attached);
1693 if(!attached &&
g->controls.layer_tab)
1694 gtk_notebook_set_current_page(GTK_NOTEBOOK(
g->controls.notebook),
1695 gtk_notebook_page_num(GTK_NOTEBOOK(
g->controls.notebook),
g->controls.layer_tab));
1698 if(
g->controls.preview_title) gtk_widget_set_visible(
g->controls.preview_title, attached);
1699 if(
g->controls.preview_box) gtk_widget_set_visible(
g->controls.preview_box, attached);
1700 if(
g->controls.layer_action_row) gtk_widget_set_visible(
g->controls.layer_action_row,
TRUE);
1701 if(
g->controls.layer_status)
1703 gtk_label_set_text(GTK_LABEL(
g->controls.layer_status), missing ?
g->session.missing_layer_error :
"");
1704 gtk_widget_set_visible(
g->controls.layer_status, missing);
1706 if(
g->controls.delete_layer) gtk_widget_set_visible(
g->controls.delete_layer, attached);
1707 if(
g->controls.rename_layer) gtk_widget_set_visible(
g->controls.rename_layer, attached);
1708 if(
g->controls.layer_fill_title) gtk_widget_set_visible(
g->controls.layer_fill_title, attached);
1709 if(
g->controls.layer_fill_row) gtk_widget_set_visible(
g->controls.layer_fill_row, attached);
1710 if(
g->controls.create_background) gtk_widget_set_visible(
g->controls.create_background, attached);
1711 if(
g->controls.save_layer) gtk_widget_set_visible(
g->controls.save_layer, attached);
1712 if(
g->controls.attach_layer) gtk_widget_set_visible(
g->controls.attach_layer, !attached && have_existing_layers);
1714 if(
g->controls.layer_select) gtk_widget_set_visible(
g->controls.layer_select, attached || have_existing_layers);
1715 if(
g->controls.create_layer) gtk_widget_set_sensitive(
g->controls.create_layer,
TRUE);
1716 if(
g->controls.rename_layer) gtk_widget_set_sensitive(
g->controls.rename_layer, attached);
1717 if(
g->controls.attach_layer) gtk_widget_set_sensitive(
g->controls.attach_layer, have_existing_layers);
1718 if(
g->controls.create_background)
1719 gtk_widget_set_sensitive(
g->controls.create_background, attached && !
g->session.background_job_running);
1720 if(
g->controls.save_layer) gtk_widget_set_sensitive(
g->controls.save_layer, attached);
1728 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_image))
1729 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_image),
1731 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_white))
1732 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_white),
1734 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_grey))
1735 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_grey),
1737 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_black))
1738 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_black),
1757 if(
g->manager.painting_active)
1760 dt_print(
DT_DEBUG_PERF,
"[drawlayer] commit_dabs deferred: stroke in progress (record_history=%d)\n",
1780 int sample_count = 0;
1781 gboolean had_stroke =
FALSE;
1782 gboolean had_last_dab =
FALSE;
1783 float last_dab_x = 0.0f;
1784 float last_dab_y = 0.0f;
1786 g->stroke.finish_commit_pending =
FALSE;
1787 sample_count = (int)
g->stroke.stroke_sample_count;
1788 had_stroke = (sample_count > 0);
1789 had_last_dab =
g->stroke.last_dab_valid;
1790 last_dab_x =
g->stroke.last_dab_x;
1791 last_dab_y =
g->stroke.last_dab_y;
1807 if(record_history && self->
dev)
1815 if(self->post_history_commit) self->post_history_commit(self);
1817 g->manager.realtime_active =
FALSE;
1831 if(!(had_stroke && record_history))
1833 g->manager.realtime_active =
FALSE;
1851 .manager = &
g->manager,
1852 .process_state = &
g->process,
1863 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_PIPE_FINISHED,
1864 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
1876 gtk_widget_set_visible(GTK_WIDGET(
g->controls.color), paint_mode);
1877 if(
g->controls.color_row) gtk_widget_set_visible(
g->controls.color_row, paint_mode);
1878 if(
g->controls.color_swatch) gtk_widget_set_visible(
g->controls.color_swatch, paint_mode);
1879 if(
g->controls.image_colorpicker) gtk_widget_set_visible(
g->controls.image_colorpicker, paint_mode);
1880 if(
g->controls.image_colorpicker_source) gtk_widget_set_visible(
g->controls.image_colorpicker_source, paint_mode);
1881 gtk_widget_set_visible(
g->controls.softness, show_hardness);
1892 GString *errors = g_string_new(NULL);
1893 gboolean deleted =
FALSE;
1894 int layer_width = 0;
1895 int layer_height = 0;
1896 if(!_resolve_layer_geometry(self, NULL, NULL, &layer_width, &layer_height, NULL, NULL))
1907 else if(!g_file_test(path, G_FILE_TEST_EXISTS))
1918 params->layer_name[0] =
'\0';
1919 params->layer_order = -1;
1920 params->sidecar_timestamp = 0;
1921 memset(params->work_profile, 0,
sizeof(params->work_profile));
1922 if(
g)
g->session.missing_layer_error[0] =
'\0';
1927 g->process.cache_valid =
FALSE;
1928 g->process.cache_dirty =
FALSE;
1930 g->process.cache_imgid = -1;
1931 g->process.cache_layer_name[0] =
'\0';
1932 g->process.cache_layer_order = -1;
1940 g_string_free(errors,
TRUE);
1951 GtkWidget *dialog = gtk_message_dialog_new(
1953 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
"%s",
1955 ? _(
"Delete the linked drawing layer from the sidecar TIFF before removing this module instance?")
1956 : _(
"Delete the linked drawing layer from the sidecar TIFF?"));
1959 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Keep layer"), GTK_RESPONSE_NO);
1960 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Delete layer"), GTK_RESPONSE_YES);
1964 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Cancel"), GTK_RESPONSE_CANCEL);
1965 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Delete"), GTK_RESPONSE_ACCEPT);
1968 const int response = gtk_dialog_run(GTK_DIALOG(dialog));
1969 gtk_widget_destroy(dialog);
1978 if(response != GTK_RESPONSE_ACCEPT)
return FALSE;
1991 if(!
IS_NULL_PTR(requested_name)) g_strlcpy(stripped_requested, requested_name,
sizeof(stripped_requested));
1992 g_strstrip(stripped_requested);
1993 if(stripped_requested[0] ==
'\0')
return FALSE;
1995 if(new_name[0] ==
'\0')
return FALSE;
1997 if(!g_strcmp0(new_name, params->layer_name))
return TRUE;
1999 GString *errors = g_string_new(NULL);
2000 gboolean renamed =
FALSE;
2001 int layer_width = 0;
2002 int layer_height = 0;
2003 if(!_resolve_layer_geometry(self, NULL, NULL, &layer_width, &layer_height, NULL, NULL))
2018 else if(!g_file_test(path, G_FILE_TEST_EXISTS))
2024 layer_width, layer_height, &info))
2028 g_strlcpy(params->layer_name, new_name,
sizeof(params->layer_name));
2029 params->layer_order = info.
index;
2031 g_strlcpy(
g->process.cache_layer_name, params->layer_name,
sizeof(
g->process.cache_layer_name));
2032 g->process.cache_layer_order = params->layer_order;
2040 g->session.missing_layer_error[0] =
'\0';
2050 g_string_free(errors,
TRUE);
2062 if(!
IS_NULL_PTR(requested_name)) g_strlcpy(stripped_requested, requested_name,
sizeof(stripped_requested));
2063 g_strstrip(stripped_requested);
2064 if(stripped_requested[0] ==
'\0')
return FALSE;
2066 if(new_name[0] ==
'\0')
return FALSE;
2073 _(
"A drawing layer with that name already exists."),
2074 _(
"Choose a different layer name."));
2083 g_strlcpy(params->layer_name, new_name,
sizeof(params->layer_name));
2084 params->layer_order = -1;
2085 params->sidecar_timestamp = 0;
2086 memset(params->work_profile, 0,
sizeof(params->work_profile));
2098 if(!
g->process.cache_valid ||
IS_NULL_PTR(
g->process.base_patch.pixels))
2104 g->process.cache_dirty =
TRUE;
2112 g->session.missing_layer_error[0] =
'\0';
2126 if(
IS_NULL_PTR(filter) || filter_size == 0)
return;
2131 const char *prev_op = NULL;
2132 if(self_piece && self->
dev->
pipe)
2134 for(GList *nodes = self->
dev->
pipe->
nodes; nodes; nodes = g_list_next(nodes))
2137 if(piece == self_piece)
break;
2138 if(piece->
enabled && piece->module && piece->module->op[0]) prev_op = piece->module->op;
2141 if(!
IS_NULL_PTR(prev_op) && prev_op[0]) g_snprintf(filter, filter_size,
"pre:%s", prev_op);
2151 gboolean cleared_initiator =
FALSE;
2157 if(!module || g_strcmp0(module->op,
"drawlayer"))
continue;
2164 g->session.background_job_running =
FALSE;
2165 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
TRUE);
2166 cleared_initiator =
TRUE;
2182 if(!module || g_strcmp0(module->op,
"drawlayer"))
continue;
2184 if(
IS_NULL_PTR(
g) || !
g->session.background_job_running)
continue;
2185 g->session.background_job_running =
FALSE;
2186 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
TRUE);
2191 return G_SOURCE_REMOVE;
2199 if(
g->session.background_job_running)
return FALSE;
2207 int layer_width = 0;
2208 int layer_height = 0;
2209 if(!_resolve_layer_geometry(self, self->
dev->
pipe, piece, &layer_width, &layer_height, NULL, NULL))
return FALSE;
2211 char sidecar_path[
PATH_MAX] = { 0 };
2222 g_strlcpy(current_info.
name, io_info.
name,
sizeof(current_info.
name));
2229 job_params->
dst_x = 0;
2230 job_params->
dst_y = 0;
2241 "drawlayer create background layer");
2250 g->session.background_job_running =
TRUE;
2251 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
FALSE);
2254 g->session.background_job_running =
FALSE;
2255 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
TRUE);
2271 if(widget ==
g->controls.size || widget ==
g->controls.softness || widget ==
g->controls.brush_shape)
2274 if(widget ==
g->controls.hdr_exposure)
2276 float display_rgb[3] = { 0.0f };
2281 if(widget ==
g->controls.brush_shape || widget ==
g->controls.opacity || widget ==
g->controls.softness || widget ==
g->controls.sprinkles
2282 || widget ==
g->controls.sprinkle_size || widget ==
g->controls.sprinkle_coarseness)
2289 const int layer_order)
2294 g_strlcpy(previous_name, params->layer_name,
sizeof(previous_name));
2295 const int previous_order = params->layer_order;
2297 g_strlcpy(params->layer_name, layer_name,
sizeof(params->layer_name));
2298 params->layer_order = layer_order;
2301 g_strlcpy(params->layer_name, previous_name,
sizeof(params->layer_name));
2302 params->layer_order = previous_order;
2307 g->session.missing_layer_error[0] =
'\0';
2326 if(active < 0)
return;
2349 if(active < 0)
return;
2367 _(
"Enter the new name for the current drawing layer."),
2368 params->layer_name, requested_name,
sizeof(requested_name)))
2400 const size_t count = (size_t)
g->process.base_patch.width *
g->process.base_patch.height;
2401 float *
const pixels =
g->process.base_patch.pixels;
2405 for(
size_t k = 0;
k < count;
k++)
2407 float *pixel = pixels + 4 *
k;
2415 g->process.cache_dirty =
TRUE;
2416 g->process.cache_dirty_rect.valid =
TRUE;
2417 g->process.cache_dirty_rect.nw[0] = 0;
2418 g->process.cache_dirty_rect.nw[1] = 0;
2419 g->process.cache_dirty_rect.se[0] =
g->process.base_patch.width;
2420 g->process.cache_dirty_rect.se[1] =
g->process.base_patch.height;
2440 (
size_t)
g->process.base_patch.width *
g->process.base_patch.height);
2443 g->process.cache_dirty =
TRUE;
2444 g->process.cache_dirty_rect.valid =
TRUE;
2445 g->process.cache_dirty_rect.nw[0] = 0;
2446 g->process.cache_dirty_rect.nw[1] = 0;
2447 g->process.cache_dirty_rect.se[0] =
g->process.base_patch.width;
2448 g->process.cache_dirty_rect.se[1] =
g->process.base_patch.height;
2484 if(!
g->process.cache_valid ||
IS_NULL_PTR(
g->process.base_patch.pixels))
2487 _(
"No drawing layer is loaded in memory."),
2488 _(
"The sidecar save was aborted."));
2494 _(
"Layer name is empty."),
2495 _(
"The sidecar save was aborted."));
2500 GtkWidget *dialog = gtk_message_dialog_new(
2502 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
"%s", _(
"Save the drawing sidecar now?"));
2503 gtk_message_dialog_format_secondary_text(
2504 GTK_MESSAGE_DIALOG(dialog),
"%s",
2505 _(
"This writes the current in-memory drawing layer to the sidecar TIFF immediately."));
2506 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Cancel"), GTK_RESPONSE_CANCEL);
2507 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Save"), GTK_RESPONSE_ACCEPT);
2509 const int response = gtk_dialog_run(GTK_DIALOG(dialog));
2510 gtk_widget_destroy(dialog);
2511 if(response != GTK_RESPONSE_ACCEPT)
2517 _(
"Waiting for the layer rasterization to finish..."));
2525 _(
"Failed to finalize the drawing stroke."),
2526 _(
"The sidecar was not saved."));
2536 _(
"Failed to write the drawing layer sidecar."),
2537 _(
"The sidecar TIFF could not be updated."));
2545 _(
"Drawing sidecar saved."),
2546 _(
"The current in-memory layer has been written to the sidecar TIFF."));
2557 _(
"Enter the name of the new drawing layer."),
2558 "", requested_name,
sizeof(requested_name)))
2580 if(GTK_WIDGET(button) ==
g->controls.preview_bg_white)
2582 else if(GTK_WIDGET(button) ==
g->controls.preview_bg_grey)
2584 else if(GTK_WIDGET(button) ==
g->controls.preview_bg_black)
2604 const float input_wx = isfinite(pointer_input.
x) ? (float)pointer_input.
x : (float)wx;
2605 const float input_wy = isfinite(pointer_input.
y) ? (float)pointer_input.
y : (float)wy;
2610 .pressure = pressure_norm,
2613 .event_ts = g_get_monotonic_time(),
2614 .stroke_batch =
g->stroke.current_stroke_batch,
2615 .event_index = ++
g->stroke.stroke_event_index,
2616 .stroke_pos = stroke_pos,
2628 uint32_t stroke_batch =
g->stroke.current_stroke_batch + 1u;
2629 if(stroke_batch == 0u) stroke_batch++;
2630 const uint32_t event_index = first_input ? first_input->
event_index : 0u;
2634 g->session.pointer_valid =
TRUE;
2635 g->stroke.current_stroke_batch = stroke_batch;
2638 g->stroke.finish_commit_pending =
FALSE;
2639 g->stroke.stroke_sample_count = 0;
2640 g->stroke.stroke_event_index = event_index;
2641 g->stroke.last_dab_valid =
FALSE;
2655 const gboolean flush_pending)
2659 .raw_input_ok =
TRUE,
2668 .manager = &
g->manager,
2669 .process_state = &
g->process,
2681 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
2682 .flush_pending = flush_pending,
2696 _(
"Waiting for the drawing rasterization to finish..."));
2701 _(
"Waiting for the layer rasterization to finish..."));
2713 return C_(
"modulename",
"drawing");
2719 return dt_iop_set_description(self, _(
"paint premultiplied RGB layers in a TIFF sidecar"), _(
"creative"),
2720 _(
"linear, RGB, scene-referred"), _(
"geometric, RGB"),
2721 _(
"linear, RGB, scene-referred"));
2728 const int program = 3;
2747 module->data = NULL;
2772 module->params = calloc(1, sizeof(dt_iop_drawlayer_params_t));
2773 module->default_params = calloc(1, sizeof(dt_iop_drawlayer_params_t));
2774 module->params_size = sizeof(dt_iop_drawlayer_params_t);
2775 module->gui_data = NULL;
2813 const gboolean display_pipe = self && self->
dev && self->
gui_data && pipe
2826 _refresh_piece_base_cache(self, data, &data->
params, pipe, piece);
2837 params->layer_name[0] =
'\0';
2838 params->layer_order = -1;
2839 params->sidecar_timestamp = 0;
2840 memset(params->work_profile, 0,
sizeof(params->work_profile));
2845 g->session.missing_layer_error[0] =
'\0';
2851 .manager = &
g->manager,
2852 .process_state = &
g->process,
2863 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_RESYNC,
2864 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
2896 &
g->stroke.finish_commit_pending, &
g->stroke.stroke_sample_count,
2897 &
g->stroke.current_stroke_batch);
2898 g->session.background_job_running =
FALSE;
2899 g->session.last_view_x = 0.0f;
2900 g->session.last_view_y = 0.0f;
2901 g->session.last_view_scale = 1.0f;
2904 g->session.last_view_x = self->
dev->
roi.
x;
2905 g->session.last_view_y = self->
dev->
roi.
y;
2913 g->controls.save_layer = gtk_button_new_with_label(_(
"save sidecar"));
2914 gtk_box_pack_start(GTK_BOX(history_box),
g->controls.save_layer,
TRUE,
TRUE, 0);
2917 GtkWidget *notebook = gtk_notebook_new();
2918 g->controls.notebook = notebook;
2919 gtk_widget_set_hexpand(notebook,
TRUE);
2925 g->controls.brush_tab = brush_tab;
2926 g->controls.layer_tab = layer_tab;
2927 g->controls.input_tab = input_tab;
2929 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), brush_tab, gtk_label_new(_(
"Brush")));
2930 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), layer_tab, gtk_label_new(_(
"Layer")));
2931 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), input_tab, gtk_label_new(_(
"Input")));
2932 gtk_container_child_set(GTK_CONTAINER(notebook), brush_tab,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2933 gtk_container_child_set(GTK_CONTAINER(notebook), layer_tab,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2934 gtk_container_child_set(GTK_CONTAINER(notebook), input_tab,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
2936 GtkWidget *preview_title = gtk_label_new(_(
"Background"));
2937 g->controls.preview_title = preview_title;
2938 gtk_widget_set_halign(preview_title, GTK_ALIGN_START);
2940 g->controls.preview_box = preview_box;
2941 GSList *preview_group = NULL;
2942 g->controls.preview_bg_image = gtk_radio_button_new_with_label(preview_group, _(
"image"));
2943 preview_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
g->controls.preview_bg_image));
2944 g->controls.preview_bg_white = gtk_radio_button_new_with_label(preview_group, _(
"white"));
2945 preview_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
g->controls.preview_bg_white));
2946 g->controls.preview_bg_grey = gtk_radio_button_new_with_label(preview_group, _(
"grey"));
2947 preview_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
g->controls.preview_bg_grey));
2948 g->controls.preview_bg_black = gtk_radio_button_new_with_label(preview_group, _(
"black"));
2949 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_image,
TRUE,
TRUE, 0);
2950 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_white,
TRUE,
TRUE, 0);
2951 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_grey,
TRUE,
TRUE, 0);
2952 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_black,
TRUE,
TRUE, 0);
2953 gtk_box_pack_start(GTK_BOX(layer_tab), preview_title,
FALSE,
FALSE, 0);
2954 gtk_box_pack_start(GTK_BOX(layer_tab), preview_box,
FALSE,
FALSE, 0);
2962 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.brush_mode,
TRUE,
TRUE, 0);
2964 GtkWidget *color_title = gtk_label_new(_(
"Color"));
2965 gtk_label_set_xalign(GTK_LABEL(color_title), 0.0f);
2967 gtk_box_pack_start(GTK_BOX(brush_tab), color_title,
TRUE,
TRUE, 0);
2968 g->controls.color = gtk_drawing_area_new();
2970 gtk_widget_add_events(
g->controls.color, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
2971 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.color,
TRUE,
TRUE, 0);
2973 g->controls.color_swatch = gtk_drawing_area_new();
2975 gtk_widget_add_events(
g->controls.color_swatch, GDK_BUTTON_PRESS_MASK);
2976 gtk_box_pack_start(GTK_BOX(
g->controls.color_row),
g->controls.color_swatch,
TRUE,
TRUE, 0);
2977 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.color_row,
TRUE,
TRUE, 0);
2984 gtk_box_pack_start(GTK_BOX(picker_controls),
g->controls.image_colorpicker,
TRUE,
TRUE, 0);
2985 gtk_box_pack_start(GTK_BOX(picker_controls),
g->controls.image_colorpicker_source,
TRUE,
TRUE, 0);
2986 gtk_box_pack_start(GTK_BOX(brush_tab), picker_controls,
TRUE,
TRUE, 0);
2988 g->controls.hdr_exposure
2992 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.hdr_exposure,
TRUE,
TRUE, 0);
2994 GtkWidget *geometry_title = gtk_label_new(_(
"Geometry"));
2995 gtk_label_set_xalign(GTK_LABEL(geometry_title), 0.0f);
2997 gtk_box_pack_start(GTK_BOX(brush_tab), geometry_title,
TRUE,
TRUE, 0);
2998 GtkWidget *brush_shape_title = gtk_label_new(_(
"Fall-off"));
2999 gtk_label_set_xalign(GTK_LABEL(brush_shape_title), 0.0f);
3000 gtk_box_pack_start(GTK_BOX(brush_tab), brush_shape_title,
TRUE,
TRUE, 0);
3001 g->controls.brush_shape = gtk_drawing_area_new();
3003 gtk_widget_add_events(
g->controls.brush_shape, GDK_BUTTON_PRESS_MASK);
3004 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.brush_shape,
TRUE,
TRUE, 0);
3010 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.size,
TRUE,
TRUE, 0);
3011 g->controls.distance
3015 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.distance,
TRUE,
TRUE, 0);
3016 g->controls.smoothing
3020 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.smoothing,
TRUE,
TRUE, 0);
3021 g->controls.softness
3026 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.softness,
TRUE,
TRUE, 0);
3028 GtkWidget *thickness_title = gtk_label_new(_(
"Thickness"));
3029 gtk_label_set_xalign(GTK_LABEL(thickness_title), 0.0f);
3031 gtk_box_pack_start(GTK_BOX(brush_tab), thickness_title,
TRUE,
TRUE, 0);
3036 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.opacity,
TRUE,
TRUE, 0);
3041 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.flow,
TRUE,
TRUE, 0);
3043 GtkWidget *texture_title = gtk_label_new(_(
"Texture"));
3044 gtk_label_set_xalign(GTK_LABEL(texture_title), 0.0f);
3046 gtk_box_pack_start(GTK_BOX(brush_tab), texture_title,
TRUE,
TRUE, 0);
3047 g->controls.sprinkles
3051 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.sprinkles,
TRUE,
TRUE, 0);
3052 g->controls.sprinkle_size
3056 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.sprinkle_size,
TRUE,
TRUE, 0);
3057 g->controls.sprinkle_coarseness
3061 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.sprinkle_coarseness,
TRUE,
TRUE, 0);
3064 GtkWidget *layer_status = gtk_label_new(
"");
3065 g->controls.layer_status = layer_status;
3066 gtk_widget_set_halign(layer_status, GTK_ALIGN_START);
3067 gtk_label_set_xalign(GTK_LABEL(layer_status), 0.0f);
3068 gtk_label_set_line_wrap(GTK_LABEL(layer_status),
TRUE);
3069 GtkWidget *layer_fill_title = gtk_label_new(_(
"Fill"));
3070 g->controls.layer_fill_title = layer_fill_title;
3071 gtk_widget_set_halign(layer_fill_title, GTK_ALIGN_START);
3073 g->controls.layer_action_row = layer_action_row;
3075 g->controls.layer_fill_row = layer_fill_row;
3078 g->controls.delete_layer = gtk_button_new_with_label(_(
"delete layer"));
3079 g->controls.create_layer = gtk_button_new_with_label(_(
"create new layer"));
3080 g->controls.rename_layer = gtk_button_new_with_label(_(
"rename layer"));
3081 g->controls.attach_layer = gtk_button_new_with_label(_(
"reuse selected layer"));
3082 g->controls.create_background = gtk_button_new_with_label(_(
"create background from input"));
3083 g->controls.fill_white = gtk_button_new_with_label(_(
"white"));
3084 g->controls.fill_black = gtk_button_new_with_label(_(
"black"));
3085 g->controls.fill_transparent = gtk_button_new_with_label(_(
"transparency"));
3086 gtk_box_pack_start(GTK_BOX(layer_box), layer_status,
FALSE,
FALSE, 0);
3087 gtk_box_pack_start(GTK_BOX(layer_box),
g->controls.layer_select,
FALSE,
FALSE, 0);
3088 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.create_layer,
TRUE,
TRUE, 0);
3089 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.rename_layer,
TRUE,
TRUE, 0);
3090 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.attach_layer,
TRUE,
TRUE, 0);
3091 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.delete_layer,
TRUE,
TRUE, 0);
3092 gtk_box_pack_start(GTK_BOX(layer_box), layer_action_row,
FALSE,
FALSE, 0);
3093 gtk_box_pack_start(GTK_BOX(layer_box), layer_fill_title,
FALSE,
FALSE, 0);
3094 gtk_box_pack_start(GTK_BOX(layer_fill_row),
g->controls.fill_white,
TRUE,
TRUE, 0);
3095 gtk_box_pack_start(GTK_BOX(layer_fill_row),
g->controls.fill_black,
TRUE,
TRUE, 0);
3096 gtk_box_pack_start(GTK_BOX(layer_fill_row),
g->controls.fill_transparent,
TRUE,
TRUE, 0);
3097 gtk_box_pack_start(GTK_BOX(layer_box), layer_fill_row,
FALSE,
FALSE, 0);
3098 gtk_box_pack_start(GTK_BOX(layer_box),
g->controls.create_background,
FALSE,
FALSE, 0);
3099 gtk_box_pack_start(GTK_BOX(layer_tab), layer_box,
FALSE,
FALSE, 0);
3101 GtkWidget *mapping_title = gtk_label_new(_(
"tablet mapping"));
3102 gtk_widget_set_halign(mapping_title, GTK_ALIGN_START);
3107 const char *labels[4] = { _(
"size"), _(
"opacity"), _(
"flow"), _(
"hardness") };
3108 const char *rows[3] = { _(
"pressure"), _(
"tilt"), _(
"acceleration") };
3110 { &
g->controls.map_pressure_size, &
g->controls.map_pressure_opacity, &
g->controls.map_pressure_flow, &
g->controls.map_pressure_softness },
3111 { &
g->controls.map_tilt_size, &
g->controls.map_tilt_opacity, &
g->controls.map_tilt_flow, &
g->controls.map_tilt_softness },
3112 { &
g->controls.map_accel_size, &
g->controls.map_accel_opacity, &
g->controls.map_accel_flow, &
g->controls.map_accel_softness },
3114 GtkWidget **profiles[3] = { &
g->controls.pressure_profile, &
g->controls.tilt_profile, &
g->controls.accel_profile };
3116 for(
int c = 0; c < 4; c++)
3118 GtkWidget *label = gtk_label_new(labels[c]);
3119 gtk_label_set_angle(GTK_LABEL(label), 90.0);
3120 gtk_grid_attach(GTK_GRID(grid), label, c + 1, 0, 1, 1);
3122 gtk_grid_attach(GTK_GRID(grid), gtk_label_new(_(
"profile")), 5, 0, 1, 1);
3124 for(
int r = 0;
r < 3;
r++)
3126 gtk_grid_attach(GTK_GRID(grid), gtk_label_new(rows[
r]), 0,
r + 1, 1, 1);
3127 for(
int c = 0; c < 4; c++)
3129 *targets[
r][c] = gtk_check_button_new();
3130 gtk_grid_attach(GTK_GRID(grid), *targets[
r][c], c + 1,
r + 1, 1, 1);
3139 gtk_grid_attach(GTK_GRID(grid), *profiles[
r], 5,
r + 1, 1, 1);
3142 gtk_box_pack_start(GTK_BOX(input_tab), mapping_title,
FALSE,
FALSE, 0);
3143 gtk_box_pack_start(GTK_BOX(input_tab), grid,
FALSE,
FALSE, 0);
3147 g_signal_connect(G_OBJECT(
g->controls.brush_mode),
"value-changed", G_CALLBACK(
_widget_changed), self);
3154 g_signal_connect(G_OBJECT(
g->controls.image_colorpicker_source),
"value-changed", G_CALLBACK(
_widget_changed), self);
3155 g_signal_connect(G_OBJECT(
g->controls.size),
"value-changed", G_CALLBACK(
_widget_changed), self);
3156 g_signal_connect(G_OBJECT(
g->controls.distance),
"value-changed", G_CALLBACK(
_widget_changed), self);
3157 g_signal_connect(G_OBJECT(
g->controls.smoothing),
"value-changed", G_CALLBACK(
_widget_changed), self);
3158 g_signal_connect(G_OBJECT(
g->controls.opacity),
"value-changed", G_CALLBACK(
_widget_changed), self);
3159 g_signal_connect(G_OBJECT(
g->controls.flow),
"value-changed", G_CALLBACK(
_widget_changed), self);
3160 g_signal_connect(G_OBJECT(
g->controls.sprinkles),
"value-changed", G_CALLBACK(
_widget_changed), self);
3161 g_signal_connect(G_OBJECT(
g->controls.sprinkle_size),
"value-changed", G_CALLBACK(
_widget_changed), self);
3162 g_signal_connect(G_OBJECT(
g->controls.sprinkle_coarseness),
"value-changed", G_CALLBACK(
_widget_changed), self);
3163 g_signal_connect(G_OBJECT(
g->controls.softness),
"value-changed", G_CALLBACK(
_widget_changed), self);
3164 g_signal_connect(G_OBJECT(
g->controls.hdr_exposure),
"value-changed", G_CALLBACK(
_widget_changed), self);
3165 g_signal_connect(G_OBJECT(
g->controls.layer_select),
"value-changed", G_CALLBACK(
_layer_selected), self);
3166 g_signal_connect(
g->controls.preview_bg_image,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3167 g_signal_connect(
g->controls.preview_bg_white,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3168 g_signal_connect(
g->controls.preview_bg_grey,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3169 g_signal_connect(
g->controls.preview_bg_black,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3180 for(
int r = 0;
r < 3;
r++)
3182 for(
int c = 0; c < 4; c++) g_signal_connect(*targets[
r][c],
"toggled", G_CALLBACK(
_widget_changed), self);
3183 g_signal_connect(G_OBJECT(*profiles[
r]),
"value-changed", G_CALLBACK(
_widget_changed), self);
3196 .manager = &
g->manager,
3197 .process_state = &
g->process,
3208 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_RESYNC,
3209 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3239 if(
g->controls.color) gtk_widget_queue_draw(
g->controls.color);
3241 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_pressure_size))
3242 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_pressure_size),
3244 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_pressure_opacity))
3245 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_pressure_opacity),
3247 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_pressure_flow))
3248 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_pressure_flow),
3250 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_pressure_softness))
3251 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_pressure_softness),
3254 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_tilt_size))
3255 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_tilt_size),
3257 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_tilt_opacity))
3258 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_tilt_opacity),
3260 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_tilt_flow))
3261 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_tilt_flow),
3263 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_tilt_softness))
3264 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_tilt_softness),
3267 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_accel_size))
3268 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_accel_size),
3270 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_accel_opacity))
3271 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_accel_opacity),
3273 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_accel_flow))
3274 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_accel_flow),
3276 if(GTK_IS_TOGGLE_BUTTON(
g->controls.map_accel_softness))
3277 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.map_accel_softness),
3280 if(
g->controls.pressure_profile)
3283 if(
g->controls.accel_profile)
3298 .manager = &
g->manager,
3299 .process_state = &
g->process,
3310 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_RESYNC,
3311 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3323 g->session.missing_layer_error[0] =
'\0';
3329 .manager = &
g->manager,
3330 .process_state = &
g->process,
3353 const int pending_samples =
g ? (int)
g->stroke.stroke_sample_count : 0;
3354 const gboolean had_pending_edits
3355 = (
g && (
g->process.cache_dirty ||
g->stroke.stroke_sample_count > 0));
3361 .manager = &
g->manager,
3362 .process_state = &
g->process,
3376 if(had_pending_edits && params)
3378 g->stroke.last_dab_y, 0u);
3387 if(self->post_history_commit) self->post_history_commit(self);
3400 .manager = &
g->manager,
3401 .process_state = &
g->process,
3444 memset(&
g->session.live_patch, 0,
sizeof(
g->session.live_patch));
3468 const float pressure_norm
3470 const float tilt_norm =
_clamp01((pointer_input && pointer_input->
has_tilt) ? pointer_input->
tilt : 0.0f);
3499 state->pressure = pressure_norm;
3500 state->tilt = tilt_norm;
3501 state->acceleration = accel_norm;
3502 state->radius = fmaxf(0.5f, radius);
3512 char lines[3][128] = { { 0 } };
3513 g_snprintf(lines[0],
sizeof(lines[0]), _(
"size %.1f px hardness %.2f%%"),
state->radius * 2.0f,
3514 state->hardness * 100.0f);
3515 g_snprintf(lines[1],
sizeof(lines[1]), _(
"opacity %.2f%% flow %.2f%%"),
state->opacity * 100.0f,
3516 state->flow * 100.0f);
3517 g_snprintf(lines[2],
sizeof(lines[2]), _(
"pressure %.2f%% tilt %.2f%% acceleration %.2f%%"),
3518 state->pressure * 100.0f,
state->tilt * 100.0f,
state->acceleration * 100.0f);
3525 cairo_select_font_face(cr,
"Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
3526 cairo_set_font_size(cr, fs);
3527 for(
int i = 0;
i < 3;
i++)
3529 cairo_text_extents_t ext = { 0 };
3530 cairo_text_extents(cr, lines[
i], &ext);
3531 max_w = fmax(max_w, ext.x_advance);
3534 const double box_w = max_w + 2.0 * pad;
3535 const double box_h = 3.0 * line_h + 2.0 * pad;
3540 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.55);
3541 cairo_rectangle(cr,
x, y, box_w, box_h);
3544 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.92);
3545 for(
int i = 0;
i < 3;
i++)
3548 cairo_show_text(cr, lines[
i]);
3561 cairo_set_line_width(cr, 1.0);
3562 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.8);
3564 if(
g->session.pointer_valid)
3568 const float widget_x = isfinite(pointer_input.
x)
3569 ? (float)pointer_input.
x
3570 : ((pointerx >= 0 && pointery >= 0) ? (
float)pointerx : -1.0f);
3571 const float widget_y = isfinite(pointer_input.
y)
3572 ? (float)pointer_input.
y
3573 : ((pointerx >= 0 && pointery >= 0) ? (
float)pointery : -1.0f);
3574 if(widget_x < 0.0f || widget_y < 0.0f)
3582 float radius = hud.
radius;
3586 float draw_x = widget_x;
3587 float draw_y = widget_y;
3607 const float draw_radius = fmaxf(0.5f, widget_radius);
3611 if(
g->ui.cursor_surface)
3613 const float surface_half_extent = 0.5f * (float)
g->ui.cursor_surface_size / (
float)
g->ui.cursor_surface_ppd;
3614 cairo_set_source_surface(cr,
g->ui.cursor_surface, draw_x - surface_half_extent, draw_y - surface_half_extent);
3620 cairo_set_source_rgba(cr, 0., 0., 0., 0.5);
3621 cairo_set_line_width(cr, 2.5);
3622 cairo_arc(cr, draw_x, draw_y, draw_radius + 1.0f, 0.0, 2.0 *
M_PI);
3625 cairo_set_source_rgba(cr, 1., 1., 1., 0.5);
3626 cairo_set_line_width(cr, 1.0);
3627 cairo_arc(cr, draw_x, draw_y, draw_radius, 0.0, 2.0 *
M_PI);
3649 .manager = &
g->manager,
3650 .process_state = &
g->process,
3682 .manager = &
g->manager,
3683 .process_state = &
g->process,
3704 if(!
g->session.pointer_valid)
3711 .manager = &
g->manager,
3712 .process_state = &
g->process,
3723 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_ENTER,
3724 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3729 if(
g->manager.painting_active)
3737 .manager = &
g->manager,
3738 .process_state = &
g->process,
3740 .raw_input = &input,
3759 dt_print(
DT_DEBUG_PERF,
"[drawlayer] stroke abort from mouse_moved: dispatch.ok=%d raw_input_ok=%d\n",
3764 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_STROKE_ABORT,
3765 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3777 .manager = &
g->manager,
3778 .process_state = &
g->process,
3794 return g->manager.painting_active ? 1 : 0;
3813 const float input_wx = isfinite(pointer_input.
x) ? (float)pointer_input.
x : (float)
x;
3814 const float input_wy = isfinite(pointer_input.
y) ? (float)pointer_input.
y : (float)y;
3816 uint32_t stroke_batch =
g->stroke.current_stroke_batch + 1u;
3817 if(stroke_batch == 0u) stroke_batch++;
3821 .pressure = pressure_norm,
3824 .event_ts = g_get_monotonic_time(),
3825 .stroke_batch = stroke_batch,
3836 .manager = &
g->manager,
3837 .process_state = &
g->process,
3839 .raw_input = &first,
3866 if(
g->manager.painting_active)
3870 const float input_wx = isfinite(pointer_input.
x) ? (float)pointer_input.
x : (float)
x;
3871 const float input_wy = isfinite(pointer_input.
y) ? (float)pointer_input.
y : (float)y;
3878 .event_ts = g_get_monotonic_time(),
3879 .stroke_batch =
g->stroke.current_stroke_batch,
3880 .event_index = ++
g->stroke.stroke_event_index,
3890 .manager = &
g->manager,
3891 .process_state = &
g->process,
3921 const float factor = increase ? 1.1f : 0.9f;
3934 .manager = &
g->manager,
3935 .process_state = &
g->process,
3958 const gint64 process_t0 = g_get_monotonic_time();
3966 gui ? &gui->
process : NULL, display_pipe, &data->runtime_manager,
3967 &data->runtime_process, &data->runtime_display_pipe);
3973 _refresh_piece_base_cache(self, runtime_data, runtime_params, (
dt_dev_pixelpipe_t *)pipe,
3979 .runtime_params = runtime_params,
4011 gboolean fallback = (runtime_params->
layer_name[0] ==
'\0');
4022 if(!fallback) fallback = !_update_runtime_state(&runtime_request, &source);
4026 const gboolean reuse_device_buffers = realtime;
4029 int source_width = source.
width;
4030 int source_height = source.
height;
4032 const float *source_pixels = source.
pixels;
4036 goto process_cl_fallback;
4051 const gboolean allow_partial = realtime && g_valid && g_devout && g_hash && g_roi;
4054 "[drawlayer] partial gate declined: valid=%d devout=%d hash=%d roi=%d\n",
4055 g_valid, g_devout, g_hash, g_roi);
4059 source_width, source_height, runtime_request.
process_state, &target_roi, &source_roi, direct_copy,
4061 reuse_device_buffers,
FALSE, allow_partial);
4065 if(ok && realtime && !preview_bg.
enabled && layer_hash != 0)
4087 (g_get_monotonic_time() - process_t0) / 1000.0, ok ? 1 : 0);
4095 (g_get_monotonic_time() - process_t0) / 1000.0);
4106 const void *
const ivoid,
void *
const ovoid)
4116 gui ? &gui->
process : NULL, display_pipe, &data->runtime_manager,
4117 &data->runtime_process, &data->runtime_display_pipe);
4123 _refresh_piece_base_cache(self, runtime_data, runtime_params, (
dt_dev_pixelpipe_t *)pipe,
4129 .runtime_params = runtime_params,
4136 .use_opencl =
FALSE,
4154 const float *input = (
const float *)ivoid;
4155 float *output = (
float *)
ovoid;
4156 const size_t pixels = (size_t)roi_out->
width * roi_out->
height;
4157 const gint64 process_t0 = g_get_monotonic_time();
4164 gboolean fallback = (runtime_params->
layer_name[0] ==
'\0');
4168 if(!fallback) fallback = !_update_runtime_state(&runtime_request, &source);
4171 const float *layer_pixels = source.
pixels;
4177 float *layerbuf = NULL;
4180 "drawlayer process scratch");
4188 goto fallback_pass_through;
4197 layer_pixels = layerbuf;
4203 (g_get_monotonic_time() - process_t0) / 1000.0);
4218fallback_pass_through:
4221 (g_get_monotonic_time() - process_t0) / 1000.0);
void cleanup(dt_imageio_module_format_t *self)
int dt_bauhaus_combobox_get(GtkWidget *widget)
int dt_bauhaus_combobox_length(GtkWidget *widget)
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
void dt_bauhaus_slider_set_factor(GtkWidget *widget, float factor)
Dab-level brush rasterization API for drawlayer.
@ DT_DRAWLAYER_BRUSH_MODE_PAINT
@ DT_DRAWLAYER_BRUSH_SHAPE_GAUSSIAN
@ DT_DRAWLAYER_BRUSH_SHAPE_LINEAR
GtkWidget * dt_color_picker_new_with_cst(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w, const dt_iop_colorspace_type_t cst)
@ DT_COLOR_PICKER_POINT_AREA
const dt_colormatrix_t dt_aligned_pixel_t out
dt_store_simd_aligned(out, dt_mat3x4_mul_vec4(vin, dt_colormatrix_row_to_simd(matrix, 0), dt_colormatrix_row_to_simd(matrix, 1), dt_colormatrix_row_to_simd(matrix, 2)))
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
int dt_conf_get_bool(const char *name)
void dt_conf_set_float(const char *name, float val)
void dt_control_get_pointer_input(dt_control_pointer_input_t *input)
void dt_control_log(const char *msg,...)
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
#define dt_control_set_cursor_visible(visible)
float dt_drawlayer_widget_brush_radius(dt_iop_module_t *self, const dt_drawlayer_brush_dab_t *dab, const float fallback)
gboolean dt_drawlayer_widget_to_layer_coords(dt_iop_module_t *self, const double wx, const double wy, float *lx, float *ly)
Shared coordinate transforms and geometry computations for drawlayer.
void dt_print(dt_debug_thread_t thread, const char *msg,...)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
static const dt_aligned_pixel_simd_t value
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
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_write_history(dt_develop_t *dev, gboolean async)
Thread-safe wrapper around dt_dev_write_history_ext() for dev->image_storage.id.
void dt_dev_history_notify_change(dt_develop_t *dev, const int32_t imgid)
Notify the rest of the app that history changes were written.
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.
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_update_history_all(dev)
dt_dev_pixelpipe_iop_t * dt_dev_distort_get_iop_pipe(struct dt_dev_pixelpipe_t *pipe, struct dt_iop_module_t *module)
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
void dt_dev_undo_start_record(dt_develop_t *dev)
void dt_dev_undo_end_record(dt_develop_t *dev)
static void dt_dev_set_history_hash(dt_develop_t *dev, const uint64_t history_hash)
static gboolean _rekey_shared_base_patch(drawlayer_patch_t *patch, const int32_t imgid, const dt_iop_drawlayer_params_t *params)
static void _retain_base_patch_loaded_ref(dt_iop_drawlayer_gui_data_t *g)
void init(dt_iop_module_t *module)
Allocate and initialize module parameter blocks.
static void _sanitize_requested_layer_name(const char *requested, char *name, size_t name_size)
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)
const char ** description(struct dt_iop_module_t *self)
Module description strings used by UI/help.
#define _set_drawlayer_pipeline_realtime_mode
int default_group()
Return default iop group for drawlayer module.
gboolean dt_drawlayer_flush_layer_cache(dt_iop_module_t *self)
static void _draw_brush_hud(cairo_t *cr, const drawlayer_hud_brush_state_t *state)
void gui_reset(dt_iop_module_t *self)
Reset GUI/session state for current drawlayer instance.
static gboolean _confirm_delete_layer(dt_iop_module_t *self, const gboolean removing_module)
static gboolean _background_layer_job_done_idle(gpointer user_data)
#define _drawlayer_wait_for_rasterization_modal
static drawlayer_process_scratch_t * _get_process_scratch(void)
void dt_drawlayer_show_runtime_feedback(const dt_iop_drawlayer_gui_data_t *g, const dt_drawlayer_runtime_feedback_t feedback)
static void _preview_bg_toggled(GtkToggleButton *button, gpointer user_data)
#define _flush_layer_cache
int mouse_leave(dt_iop_module_t *self)
Mouse leave handler.
static gboolean _apply_selected_layer_attachment(dt_iop_module_t *self, dt_iop_drawlayer_gui_data_t *g, dt_iop_drawlayer_params_t *params, const char *layer_name, const int layer_order)
Apply one selected on-disk layer from the combobox to module params/history.
static gboolean _fill_current_layer(dt_iop_module_t *self, const float value)
gboolean dt_drawlayer_sync_widget_cache(dt_iop_module_t *self)
void gui_focus(dt_iop_module_t *self, gboolean in)
Focus transition hook (enter/leave) for drawlayer GUI mode.
static int _drawlayer_run_premult_over_kernel(const int devid, const int kernel_premult_over, cl_mem dev_background, cl_mem dev_layer_rgba, cl_mem dev_out, const int width, const int height, const int background_offset_x, const int background_offset_y)
static gboolean _color_picker_set_from_position(dt_iop_module_t *self, const float x, const float y)
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
static void _attach_selected_layer_clicked(GtkButton *button, gpointer user_data)
__DT_CLONE_TARGETS__ int process(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
CPU processing path for layer-over-input compositing.
static dt_drawlayer_runtime_result_t _update_gui_runtime_manager(dt_iop_module_t *self, dt_iop_drawlayer_gui_data_t *g, dt_drawlayer_runtime_event_t event, gboolean flush_pending)
int button_pressed(dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
Button press handler (starts stroke capture on left button).
static gboolean _color_picker_motion(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
static gboolean _prompt_layer_name_dialog(const char *title, const char *message, const char *initial_name, char *name, size_t name_size)
static void _fill_transparent_clicked(GtkButton *button, gpointer user_data)
#define _release_all_base_patch_extra_refs
void dt_drawlayer_begin_gui_stroke_capture(dt_iop_module_t *self, const dt_drawlayer_paint_raw_input_t *first_input)
static void _show_drawlayer_modal_message(const GtkMessageType type, const char *primary, const char *secondary)
static void _destroy_process_scratch(gpointer data)
static void _create_layer_clicked(GtkButton *button, gpointer user_data)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
void dt_drawlayer_release_all_base_patch_extra_refs(dt_iop_drawlayer_gui_data_t *g)
static int64_t _sidecar_timestamp_from_path(const char *path)
static void _save_layer_clicked(GtkButton *button, gpointer user_data)
static gboolean _get_current_work_profile_key(dt_iop_module_t *self, GList *iop_list, dt_dev_pixelpipe_t *pipe, char *key, const size_t key_size)
static void _layer_selected(GtkWidget *widget, gpointer user_data)
static gboolean _drawlayer_sync_host_image_to_device(const int devid, cl_mem device_image, void *host_pixels, const int width, const int height, const int bpp, const dt_drawlayer_damaged_rect_t *dirty_rect)
static gboolean _brush_profile_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
static void _build_pre_module_filter_string(dt_iop_module_t *self, char *filter, const size_t filter_size)
const char * name()
Module display name.
static void _sync_brush_profile_preview_widget(dt_iop_module_t *self)
static void _widget_changed(GtkWidget *widget, gpointer user_data)
static void _brush_pipeline_color_from_display(dt_iop_module_t *self, const float display_rgb[3], float pipeline_rgb[3])
Convert one display-space brush color snapshot to pipeline space.
static gboolean _clear_current_layer(dt_iop_module_t *self)
static void _sync_cached_brush_colors(dt_iop_module_t *self, const float display_rgb[3])
Cache brush colors in GUI state so stroke input snapshots don't re-transform per event.
int scrolled(dt_iop_module_t *self, double x, double y, int up, uint32_t state)
Scroll handler used for interactive brush-size changes.
gboolean dt_drawlayer_commit_dabs(dt_iop_module_t *self, gboolean record_history)
void quiesce(dt_iop_module_t *self)
Destroy GUI resources and stop background worker.
void gui_init(dt_iop_module_t *self)
Build GUI widgets and initialize worker/caches.
static int _drawlayer_copy_or_resample_layer_roi(const int devid, cl_mem dev_source_rgba, cl_mem dev_layer_rgba, const int source_w, const int source_h, const dt_iop_roi_t *const target_roi, const dt_iop_roi_t *const source_roi)
static gboolean _create_background_layer_from_input(dt_iop_module_t *self)
void dt_drawlayer_set_pipeline_realtime_mode(dt_iop_module_t *self, gboolean state)
static drawlayer_wait_dialog_t _show_drawlayer_wait_dialog(const char *title, const char *message)
static void _rename_layer_clicked(GtkButton *button, gpointer user_data)
static gboolean _color_picker_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static gboolean _color_swatch_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
#define _touch_stroke_commit_hash
static gboolean _drawlayer_acquire_layer_image(const int devid, dt_pixel_cache_entry_t *resolved_entry, const gboolean realtime_reuse, const gboolean direct_copy, cl_mem dev_source_rgba, const int source_w, const int source_h, const dt_iop_roi_t *const target_roi, const dt_iop_roi_t *const source_roi, drawlayer_cl_image_handle_t *layer, int *err)
static gboolean _color_picker_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
void gui_cleanup(dt_iop_module_t *self)
static int _blend_layer_over_input_cl(const int devid, const int kernel_premult_over, cl_mem dev_out, cl_mem dev_in, drawlayer_process_scratch_t *scratch, const float *layer_pixels, dt_pixel_cache_entry_t *source_entry, cl_mem source_mem_override, const int source_w, const int source_h, dt_drawlayer_process_state_t *process, const dt_iop_roi_t *const target_roi, const dt_iop_roi_t *const source_roi, const gboolean direct_copy, const gboolean use_preview_bg, const float preview_bg, const gboolean realtime_reuse, const gboolean force_device_copy, const gboolean allow_partial)
#define _drawlayer_runtime_perform_action
static gboolean _drawlayer_modal_wait_tick(gpointer user_data)
static void _sync_preview_bg_buttons(dt_iop_module_t *self)
static gboolean _delete_current_layer(dt_iop_module_t *self)
void cleanup_global(dt_iop_module_so_t *module)
Release global OpenCL resources for drawlayer.
gboolean module_will_remove(dt_iop_module_t *self)
Hook called before module removal from history stack.
static gboolean _drawlayer_map_source_damage_to_target(const dt_drawlayer_damaged_rect_t *src_damage, const dt_iop_roi_t *const target_roi, const dt_iop_roi_t *const source_roi, dt_drawlayer_damaged_rect_t *out)
static gboolean _drawlayer_acquire_source_image(const int devid, const float *layer_pixels, dt_pixel_cache_entry_t *resolved_entry, const gboolean force_device_copy, const gboolean realtime_reuse, const int source_w, const int source_h, dt_drawlayer_process_state_t *process, drawlayer_cl_image_handle_t *source)
int mouse_moved(dt_iop_module_t *self, double x, double y, double pressure, int which)
Mouse motion handler.
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Return default colorspace expected by drawlayer process paths.
static gboolean _color_swatch_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
int flags()
Return module capability flags.
static gboolean _working_rgb_to_display_rgb(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const float working_rgb[3], float display_rgb[3])
static gboolean _profile_key_is_sane(const char *value)
static gboolean _color_picker_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
int button_released(dt_iop_module_t *self, double x, double y, int which, uint32_t state)
Button release handler (ends current stroke).
#define _layer_to_widget_coords
static gboolean _create_new_layer(dt_iop_module_t *self, const char *requested_name)
void commit_params(dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Commit params to runtime piece and refresh base cache state.
void change_image(dt_iop_module_t *self)
Invalidate module state when active image changes.
static void _develop_ui_pipe_finished_callback(gpointer instance, gpointer user_data)
#define _drawlayer_runtime_collect_inputs
static void _create_background_clicked(GtkButton *button, gpointer user_data)
void dt_drawlayer_wait_for_rasterization_modal(const dt_iop_drawlayer_gui_data_t *g, const char *title, const char *message)
dt_drawlayer_runtime_context_t drawlayer_runtime_host_context_t
static gboolean _brush_profile_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static GPrivate _drawlayer_process_scratch_key
static __DT_CLONE_TARGETS__ void _blend_layer_over_input(float *output, const float *input, const float *layerbuf, const size_t pixels, const gboolean use_preview_bg, const float preview_bg)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Cleanup per-pipe runtime data.
void gui_post_expose(dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
Draw post-expose overlay (cursor, HUD, temp preview).
static void _fill_black_clicked(GtkButton *button, gpointer user_data)
dt_drawlayer_runtime_request_t drawlayer_runtime_request_t
void dt_drawlayer_end_gui_stroke_capture(dt_iop_module_t *self)
static void _sync_layer_controls(dt_iop_module_t *self)
static void _fill_input_layer_coords(dt_iop_module_t *self, dt_drawlayer_paint_raw_input_t *input)
static gboolean _layer_name_non_empty(const char *name)
static void _fill_input_brush_settings(dt_iop_module_t *self, dt_drawlayer_paint_raw_input_t *input)
void init_global(dt_iop_module_so_t *module)
Initialize global OpenCL resources for drawlayer kernels.
static gboolean _rename_current_layer_from_gui(dt_iop_module_t *self, const char *requested_name)
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
OpenCL processing path for layer-over-input compositing.
#define DRAWLAYER_RESAMPLE_DAMAGE_MARGIN
static void _compute_hud_brush_state(const dt_control_pointer_input_t *pointer_input, drawlayer_hud_brush_state_t *state)
#define _ensure_layer_cache
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Apply selected picker color to drawlayer brush color.
static void _sync_mode_sensitive_widgets(dt_iop_module_t *self)
static void _fill_white_clicked(GtkButton *button, gpointer user_data)
static void _sanitize_params(dt_iop_module_t *self, dt_iop_drawlayer_params_t *params)
static void _ensure_cursor_stamp_surface(dt_iop_module_t *self, const float widget_radius, const float opacity, const float hardness)
static gboolean _build_raw_input_event(dt_iop_module_t *self, const double wx, const double wy, const double pressure, const dt_drawlayer_paint_stroke_pos_t stroke_pos, dt_drawlayer_paint_raw_input_t *input)
static void _refresh_layer_widgets(dt_iop_module_t *self)
static void _retain_base_patch_stroke_ref(dt_iop_drawlayer_gui_data_t *g)
static void _delete_layer_clicked(GtkButton *button, gpointer user_data)
#define dt_pthread_rwlock_wrlock
#define dt_pthread_rwlock_unlock
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
GtkWidget * dt_ui_center(dt_ui_t *ui)
get the center drawable widget
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
static void dt_iop_image_copy_by_size(float *const __restrict__ out, const float *const __restrict__ in, const size_t width, const size_t height, const size_t ch)
void dt_iop_request_focus(dt_iop_module_t *module)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
@ DT_REQUEST_COLORPICK_OFF
static void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module) ACQUIRE(&module -> gui_lock)
@ IOP_FLAGS_SUPPORTS_BLENDING
static void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module) RELEASE(&module -> gui_lock)
#define IOP_GUI_ALLOC(module)
gboolean dt_mask_scroll_increases(int up)
int dt_iop_clip_and_zoom_roi_cl(int devid, cl_mem dev_out, cl_mem dev_in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in)
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)
int dt_interpolation_resample_cl(const struct dt_interpolation *itor, const int devid, cl_mem dev_out, const dt_iop_roi_t *const roi_out, cl_mem dev_in, const dt_iop_roi_t *const roi_in)
@ DT_INTERPOLATION_BILINEAR
int32_t dt_drawlayer_io_background_layer_job_run(dt_job_t *job)
Worker entrypoint for async "create background from input" sidecar jobs.
gboolean dt_drawlayer_io_layer_name_exists(const char *path, const char *candidate, const int ignore_index)
Test if a layer name already exists in sidecar TIFF.
gboolean dt_drawlayer_io_find_layer(const char *path, const char *target_name, const int target_order, dt_drawlayer_io_layer_info_t *info)
Find target layer metadata in sidecar TIFF.
gboolean dt_drawlayer_io_sidecar_path(const int32_t imgid, char *path, const size_t path_size)
Build absolute sidecar path from image id.
gboolean dt_drawlayer_io_rename_layer(const char *path, const char *current_name, const char *new_name, const char *work_profile, const int layer_width, const int layer_height, dt_drawlayer_io_layer_info_t *info)
Rename one existing layer page while preserving its directory payload.
gboolean dt_drawlayer_io_load_layer(const char *path, const char *target_name, const int target_order, const int layer_width, const int layer_height, dt_drawlayer_io_patch_t *patch)
Load one sidecar layer patch into float RGBA destination patch.
gboolean dt_drawlayer_io_delete_layer(const char *path, const char *target_name, const int layer_width, const int layer_height)
Delete one existing layer page from the sidecar TIFF.
TIFF sidecar I/O API for drawlayer layers.
static float _clamp01(const float v)
Clamp scalar to [0,1].
gboolean dt_drawlayer_brush_rasterize_dab_argb8(const dt_drawlayer_brush_dab_t *dab, uint8_t *argb, const int width, const int height, const int stride, const float center_x, const float center_y, const float opacity_multiplier)
Render one dab to 8-bit ARGB surface for GUI cursor preview.
Patch/cache helpers for drawlayer process and preview buffers.
Drawlayer configuration read/write helpers (private include unit).
static float _conf_smoothing(void)
Read and clamp configured smoothing parameter (%).
#define DRAWLAYER_CONF_MAP_TILT_SIZE
static void _ensure_gui_conf_defaults(void)
Ensure all drawlayer GUI config keys exist with sane defaults.
static float _conf_sprinkle_coarseness(void)
Read and clamp configured sprinkle octave mix (%).
static drawlayer_mapping_profile_t _conf_mapping_profile(const char *key)
Read and clamp one mapping-profile enum key.
static float _conf_hardness(void)
Derive hardness as complementary value of softness.
static float _conf_flow(void)
Read and clamp configured flow (%).
static float _conf_size(void)
Read and clamp configured brush size (px).
static void _conf_display_color(float rgb[3])
Read configured display RGB brush color.
#define DRAWLAYER_CONF_MAP_PRESSURE_SIZE
static float _conf_sprinkles(void)
Read and clamp configured sprinkles amount (%).
#define DRAWLAYER_CONF_ACCEL_PROFILE
static void _remember_display_color(dt_iop_module_t *self, const float display_rgb[3])
Push current display color to history and trigger swatch redraw.
static float _conf_opacity(void)
Read and clamp configured stroke opacity (%).
#define DRAWLAYER_CONF_MAP_PRESSURE_SOFTNESS
#define DRAWLAYER_CONF_PRESSURE_PROFILE
#define DRAWLAYER_CONF_MAP_TILT_FLOW
static float _conf_distance(void)
Read and clamp configured distance/sampling parameter (%).
#define DRAWLAYER_CONF_MAP_ACCEL_FLOW
static drawlayer_pick_source_t _conf_pick_source(void)
Read and clamp color picker source selector.
#define DRAWLAYER_CONF_MAP_ACCEL_SIZE
#define DRAWLAYER_CONF_MAP_PRESSURE_OPACITY
#define DRAWLAYER_CONF_SIZE
static void _sync_color_picker_from_conf(dt_iop_module_t *self)
Refresh picker widgets from persisted config color.
#define DRAWLAYER_CONF_MAP_TILT_SOFTNESS
#define DRAWLAYER_CONF_TILT_PROFILE
#define DRAWLAYER_CONF_MAP_ACCEL_OPACITY
static void _load_color_history(dt_iop_drawlayer_gui_data_t *g)
Load persisted color-history stack from config into widgets state.
static dt_iop_drawlayer_brush_shape_t _conf_brush_shape(void)
Read and clamp configured brush shape.
static void _sync_params_from_gui(dt_iop_module_t *self, const gboolean record_history)
Sync active GUI widget values back into persistent config keys.
#define DRAWLAYER_CONF_MAP_PRESSURE_FLOW
static float _conf_hdr_exposure(void)
Read and clamp HDR picker exposure compensation (EV).
#define DRAWLAYER_CONF_MAP_TILT_OPACITY
#define DRAWLAYER_CONF_MAP_ACCEL_SOFTNESS
static float _conf_sprinkle_size(void)
Read and clamp configured sprinkle feature size (px).
static dt_iop_drawlayer_brush_mode_t _conf_brush_mode(void)
Read and clamp configured brush blend mode.
static void _apply_display_brush_color(dt_iop_module_t *self, const float display_rgb[3], const gboolean remember)
Apply display-space brush color to conf, widgets and redraw.
Private drawlayer module types and lightweight shared helpers.
static float _mapping_profile_value(const drawlayer_mapping_profile_t profile, const float x)
@ DRAWLAYER_INPUT_MAP_ACCEL_SIZE
@ DRAWLAYER_INPUT_MAP_ACCEL_FLOW
@ DRAWLAYER_INPUT_MAP_PRESSURE_SOFTNESS
@ DRAWLAYER_INPUT_MAP_TILT_SOFTNESS
@ DRAWLAYER_INPUT_MAP_TILT_OPACITY
@ DRAWLAYER_INPUT_MAP_PRESSURE_OPACITY
@ DRAWLAYER_INPUT_MAP_TILT_FLOW
@ DRAWLAYER_INPUT_MAP_ACCEL_OPACITY
@ DRAWLAYER_INPUT_MAP_TILT_SIZE
@ DRAWLAYER_INPUT_MAP_PRESSURE_FLOW
@ DRAWLAYER_INPUT_MAP_ACCEL_SOFTNESS
@ DRAWLAYER_INPUT_MAP_PRESSURE_SIZE
drawlayer_mapping_profile_t
@ DRAWLAYER_PREVIEW_BG_WHITE
@ DRAWLAYER_PREVIEW_BG_IMAGE
@ DRAWLAYER_PREVIEW_BG_BLACK
@ DRAWLAYER_PREVIEW_BG_GREY
@ DRAWLAYER_PICK_SOURCE_OUTPUT
void dt_drawlayer_paint_runtime_state_reset(dt_drawlayer_damaged_rect_t *state)
Reset stroke-damage accumulator to empty/invalid.
Stroke-level path sampling and runtime-state API for drawlayer.
dt_drawlayer_paint_stroke_pos_t
Position of a raw input event inside a stroke lifecycle.
@ DT_DRAWLAYER_PAINT_STROKE_MIDDLE
@ DT_DRAWLAYER_PAINT_STROKE_FIRST
@ DT_DRAWLAYER_PAINT_STROKE_END
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_output_profile_info(const struct dt_dev_pixelpipe_t *pipe)
void dt_ioppr_transform_image_colorspace_rgb(const float *const restrict image_in, float *const restrict image_out, const int width, const int height, const dt_iop_order_iccprofile_info_t *const profile_info_from, const dt_iop_order_iccprofile_info_t *const profile_info_to, const char *message)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_iop_work_profile_info(struct dt_iop_module_t *module, GList *iop_list)
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
void dt_control_job_add_progress(dt_job_t *job, const char *message, gboolean cancellable)
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
Private drawlayer layer cache, sidecar sync and widget cache state.
static void _layerio_log_errors(GString *errors)
static void _reset_stroke_session(dt_iop_drawlayer_gui_data_t *g)
static void _populate_layer_list(dt_iop_module_t *self)
static void _layerio_append_error(GString *errors, const char *message)
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
void * dt_opencl_alloc_device_use_host_pointer(const int devid, const int width, const int height, const int bpp, void *host, const int flags)
gboolean dt_opencl_is_pinned_memory(cl_mem mem)
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
int dt_opencl_create_kernel(const int prog, const char *name)
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
int dt_opencl_unmap_mem_object(const int devid, cl_mem mem_object, void *mapped_ptr)
void dt_opencl_free_kernel(const int kernel)
void * dt_opencl_map_image(const int devid, cl_mem buffer, const int blocking, const int flags, size_t width, size_t height, int bpp)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
gboolean dt_opencl_finish(const int devid)
void * dt_opencl_copy_host_to_device(const int devid, void *host, const int width, const int height, const int bpp)
int dt_opencl_write_host_to_device_raw(const int devid, const void *host, void *device, const size_t *origin, const size_t *region, const int rowpitch, const int blocking)
void dt_opencl_release_mem_object(cl_mem mem)
int dt_opencl_write_host_to_device(const int devid, void *host, void *device, const int width, const int height, const int bpp)
@ DT_DEV_PIXELPIPE_THUMBNAIL
@ DT_DEV_PIXELPIPE_EXPORT
void * dt_dev_pixelpipe_cache_get_pinned_image(dt_dev_pixelpipe_cache_t *cache, void *host_ptr, dt_pixel_cache_entry_t *entry_hint, int devid, int width, int height, int bpp, int flags, gboolean *out_reused)
Acquire a pinned OpenCL image for a host buffer tracked by the pixelpipe cache.
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....
void dt_dev_pixelpipe_cache_put_pinned_image(dt_dev_pixelpipe_cache_t *cache, void *host_ptr, dt_pixel_cache_entry_t *entry_hint, void **mem)
Release or cache a pinned OpenCL image acquired with dt_dev_pixelpipe_cache_get_pinned_image().
void dt_dev_pixelpipe_cache_release_cl_buffer(void **cl_mem_buffer, dt_pixel_cache_entry_t *cache_entry, void *host_ptr, const gboolean cache_device)
Release or cache an OpenCL image associated with a host cache line.
void * dt_dev_pixelpipe_cache_get_cl_buffer(int devid, void *const host_ptr, const dt_iop_roi_t *roi, const size_t bpp, dt_iop_module_t *module, const char *message, dt_pixel_cache_entry_t *cache_entry, gboolean *out_reused, void *keep)
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.
int dt_dev_pixelpipe_cache_rekey(dt_dev_pixelpipe_cache_t *cache, const uint64_t old_hash, const uint64_t new_hash, dt_pixel_cache_entry_t *entry)
Change the hash/key of an existing cache line in place, without freeing, reallocating or invalidating...
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_ref_entry_for_host_ptr(dt_dev_pixelpipe_cache_t *cache, void *host_ptr)
Resolve and retain the cache entry owning a host pointer.
Pixelpipe cache for storing intermediate results in the pixelpipe.
gboolean dt_dev_pixelpipe_get_realtime(const dt_dev_pixelpipe_t *pipe)
void dt_drawlayer_runtime_manager_bind_piece(dt_drawlayer_runtime_manager_t *headless_manager, dt_drawlayer_process_state_t *headless_process, dt_drawlayer_runtime_manager_t *gui_manager, dt_drawlayer_process_state_t *gui_process, const gboolean display_pipe, dt_drawlayer_runtime_manager_t **runtime_manager, dt_drawlayer_process_state_t **runtime_process, gboolean *runtime_display_pipe)
void dt_drawlayer_runtime_manager_cleanup(dt_drawlayer_runtime_manager_t *state)
void dt_drawlayer_runtime_manager_init(dt_drawlayer_runtime_manager_t *state)
dt_drawlayer_runtime_result_t dt_drawlayer_runtime_manager_update(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_update_request_t *request, const dt_drawlayer_runtime_host_t *host)
void dt_drawlayer_process_state_init(dt_drawlayer_process_state_t *state)
void dt_drawlayer_ui_cursor_clear(dt_drawlayer_ui_state_t *state)
void dt_drawlayer_process_state_cleanup(dt_drawlayer_process_state_t *state)
void dt_drawlayer_runtime_manager_note_buffer_lock(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_buffer_t buffer, const dt_drawlayer_runtime_actor_t actor, const gboolean write_lock, const gboolean acquire)
void dt_drawlayer_process_state_invalidate(dt_drawlayer_process_state_t *state)
Private runtime state/helpers shared by drawlayer module entrypoints.
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_BEGIN
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_END
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_SAMPLE
@ DT_DRAWLAYER_SOURCE_BASE_PATCH
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CPU
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CL
@ DT_DRAWLAYER_RUNTIME_BUFFER_BASE_PATCH
dt_drawlayer_runtime_event_t
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_GAIN
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_AFTER
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SCROLL
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_BEFORE
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_AFTER
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_CHANGE_IMAGE
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_RAW_INPUT
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_BEFORE
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_LEAVE
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_STROKE_ABORT
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_LOSS
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SYNC_TEMP_BUFFERS
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
@ DT_SIGNAL_DEVELOP_UI_PIPE_FINISHED
This signal is raised when pipe is finished and the gui is attached no param, no returned value.
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
float * dt_drawlayer_cache_ensure_scratch_buffer(float **buffer, size_t *capacity_pixels, const size_t needed_pixels, const char *name)
Ensure scratch RGBA float capacity in pixels.
void dt_drawlayer_cache_patch_wrunlock(const dt_drawlayer_cache_patch_t *patch)
Release write lock on shared patch cache entry.
void dt_drawlayer_cache_patch_wrlock(const dt_drawlayer_cache_patch_t *patch)
Acquire write lock on shared patch cache entry.
void dt_drawlayer_cache_patch_clear(dt_drawlayer_cache_patch_t *patch, const char *external_alloc_name)
Release patch storage and reset patch metadata.
gboolean dt_drawlayer_cache_patch_alloc_shared(dt_drawlayer_cache_patch_t *patch, const uint64_t hash, const size_t pixel_count, const int width, const int height, const char *name, int *created_out)
Allocate patch storage from shared pixel cache entry.
void dt_drawlayer_cache_free_temp_buffer(void **buffer, const char *name)
Free temporary aligned cache buffer.
void dt_drawlayer_cache_patch_rdlock(const dt_drawlayer_cache_patch_t *patch)
Acquire read lock on shared patch cache entry.
void dt_drawlayer_cache_patch_rdunlock(const dt_drawlayer_cache_patch_t *patch)
Release read lock on shared patch cache entry.
void dt_drawlayer_cache_clear_transparent_float(float *pixels, const size_t pixel_count)
Fill float RGBA buffer with transparent black.
Shared drawlayer runtime helpers used across module/runtime files.
#define DRAWLAYER_NAME_SIZE
dt_drawlayer_runtime_feedback_t
@ DT_DRAWLAYER_RUNTIME_FEEDBACK_NONE
@ DT_DRAWLAYER_RUNTIME_FEEDBACK_FOCUS_LOSS_WAIT
@ DT_DRAWLAYER_RUNTIME_FEEDBACK_SAVE_WAIT
#define DRAWLAYER_PROFILE_SIZE
unsigned __int64 uint64_t
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
struct dt_gui_gtk_t * gui
struct dt_control_signal_t * signals
struct dt_bauhaus_t * bauhaus
struct dt_develop_t * develop
struct dt_control_t * control
gboolean is_cached_device
char work_profile[DRAWLAYER_PROFILE_SIZE]
char name[DRAWLAYER_NAME_SIZE]
const dt_iop_drawlayer_gui_data_t * g
size_t cl_background_rgba_pixels
float * flush_update_rgba
float * cl_background_rgba
size_t flush_update_rgba_pixels
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
struct dt_develop_t * dev
struct dt_iop_module_t * gui_module
dt_pthread_rwlock_t history_mutex
struct dt_dev_pixelpipe_t * preview_pipe
struct dt_dev_pixelpipe_t * virtual_pipe
struct dt_develop_t::@17 roi
struct dt_dev_pixelpipe_t * pipe
Fully resolved input dab descriptor.
Generic float RGBA patch stored either in malloc memory or pixel cache.
dt_pixel_cache_entry_t * cache_entry
Integer axis-aligned rectangle in buffer coordinates.
Parameters owned by the async "create background from input" job.
char initiator_layer_name[64]
int initiator_layer_order
char sidecar_path[PATH_MAX]
char requested_bg_name[64]
Result posted back to the UI after background-layer creation.
int initiator_layer_order
char initiator_layer_name[64]
int64_t sidecar_timestamp
Metadata returned when probing one layer directory in sidecar TIFF.
Float RGBA patch used by drawlayer I/O routines.
uint64_t last_composite_layer_hash
void * last_composite_dev_out
dt_drawlayer_cache_patch_t base_patch
char cache_layer_name[DRAWLAYER_NAME_SIZE]
gboolean last_composite_valid
dt_iop_roi_t last_composite_target_roi
dt_drawlayer_damaged_rect_t cache_dirty_rect
dt_drawlayer_runtime_request_t runtime
dt_drawlayer_process_state_t * process
const dt_iop_drawlayer_params_t * runtime_params
const dt_iop_roi_t * roi_in
const dt_dev_pixelpipe_t * pipe
dt_drawlayer_process_state_t * process_state
const dt_iop_roi_t * roi_out
dt_dev_pixelpipe_iop_t * piece
dt_drawlayer_runtime_manager_t * manager
dt_drawlayer_runtime_buffer_t tracked_buffer
gboolean tracked_read_lock
dt_drawlayer_runtime_source_kind_t kind
dt_pixel_cache_entry_t * cache_entry
dt_drawlayer_runtime_actor_t tracked_actor
dt_drawlayer_runtime_event_t event
dt_drawlayer_runtime_release_t release
dt_drawlayer_process_state_t * runtime_process
dt_drawlayer_process_state_t process
dt_drawlayer_runtime_manager_t headless_manager
dt_iop_drawlayer_params_t params
dt_drawlayer_runtime_manager_t * runtime_manager
gboolean runtime_display_pipe
dt_drawlayer_process_state_t process
dt_drawlayer_session_state_t session
dt_drawlayer_runtime_manager_t manager
dt_iop_global_data_t * data
dt_dev_request_colorpick_flags_t request_color_pick
dt_iop_params_t * default_params
dt_aligned_pixel_t picked_output_color_min
struct dt_develop_t * dev
dt_iop_gui_data_t * gui_data
dt_aligned_pixel_t picked_output_color_max
dt_iop_global_data_t * global_data
dt_aligned_pixel_t picked_output_color
dt_aligned_pixel_t picked_color_min
dt_aligned_pixel_t picked_color_max
dt_aligned_pixel_t picked_color
dt_iop_color_intent_t intent
dt_colorspaces_color_profile_type_t type
char filename[DT_IOP_COLOR_ICC_LEN]
Region of interest passed through the pixelpipe.
typedef double((*spd)(unsigned long int wavelength, double TempK))
Drawlayer realtime worker thread and FIFO event queue.
void dt_drawlayer_worker_stop(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Stop realtime and full-resolution worker threads.
void dt_drawlayer_worker_cleanup(dt_drawlayer_worker_t **worker)
Public worker cleanup entry point.
void dt_drawlayer_worker_reset_backend_path(dt_drawlayer_worker_t *worker)
Reset worker-owned backend damage accumulator.
static void _cancel_async_commit(dt_drawlayer_worker_t *rt)
Cancel deferred commit request state if any.
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.
gboolean dt_drawlayer_worker_active(const dt_drawlayer_worker_t *worker)
Public status query: TRUE when worker has pending activity.
void dt_drawlayer_worker_publish_backend_stroke_damage(dt_iop_module_t *self)
Publish accumulated backend stroke damage into drawlayer process/runtime state.
void dt_drawlayer_worker_request_commit(dt_drawlayer_worker_t *worker)
Public commit request helper.
gboolean dt_drawlayer_worker_any_active(const dt_drawlayer_worker_t *worker)
Public status query: TRUE when any worker still has pending activity.
void dt_drawlayer_worker_reset_live_publish(dt_drawlayer_worker_t *worker)
Reset worker-owned transient live-publish state.
void dt_drawlayer_worker_seal_for_commit(dt_drawlayer_worker_t *worker)
Seal current stroke for synchronous commit.
void dt_drawlayer_worker_reset_stroke(dt_drawlayer_worker_t *worker)
Clear preserved stroke runtime/history after commit completed.
static gboolean _wait_worker_idle(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Wait until worker queue is drained and not busy.
Background stroke worker API for drawlayer realtime painting.