67#include <glib/gstdio.h>
135 char *
name,
size_t name_size);
142 gboolean flush_pending);
154 if(!display_rgb ||
IS_NULL_PTR(pipeline_rgb))
return;
156 pipeline_rgb[0] =
_clamp01(display_rgb[0]);
157 pipeline_rgb[1] =
_clamp01(display_rgb[1]);
158 pipeline_rgb[2] =
_clamp01(display_rgb[2]);
168 float in[4] = { pipeline_rgb[0], pipeline_rgb[1], pipeline_rgb[2], 0.0f };
169 float out[4] = { pipeline_rgb[0], pipeline_rgb[1], pipeline_rgb[2], 0.0f };
171 "drawlayer brush color");
172 pipeline_rgb[0] =
out[0];
173 pipeline_rgb[1] =
out[1];
174 pipeline_rgb[2] =
out[2];
179 pipeline_rgb[0] *= gain;
180 pipeline_rgb[1] *= gain;
181 pipeline_rgb[2] *= gain;
190 g->ui.brush_display_color[0] =
_clamp01(display_rgb[0]);
191 g->ui.brush_display_color[1] =
_clamp01(display_rgb[1]);
192 g->ui.brush_display_color[2] =
_clamp01(display_rgb[2]);
194 g->ui.brush_color_valid =
TRUE;
211 uint32_t map_flags = 0u;
225 c->map_flags = map_flags;
240 g->ui.brush_settings_valid =
TRUE;
255 uint32_t map_flags = 0u;
272 float display_rgb[3] = { 0.0f };
273 float pipeline_rgb[3] = { 0.0f };
276 memcpy(display_rgb,
g->ui.brush_display_color,
sizeof(display_rgb));
277 memcpy(pipeline_rgb,
g->ui.brush_pipeline_color,
sizeof(pipeline_rgb));
285 memcpy(display_rgb,
g->ui.brush_display_color,
sizeof(display_rgb));
286 memcpy(pipeline_rgb,
g->ui.brush_pipeline_color,
sizeof(pipeline_rgb));
291 display_rgb[0] =
_clamp01(display_rgb[0]);
292 display_rgb[1] =
_clamp01(display_rgb[1]);
293 display_rgb[2] =
_clamp01(display_rgb[2]);
298 input->
map_flags = c ? c->map_flags : map_flags;
313 input->
color[0] = pipeline_rgb[0];
314 input->
color[1] = pipeline_rgb[1];
315 input->
color[2] = pipeline_rgb[2];
340 "[drawlayer] raw-input batch=%u event=%u pos=%u widget=(%.3f,%.3f) raster=(%.3f,%.3f) ok=%d\n",
349 g_strlcpy(tmp,
name,
sizeof(tmp));
351 return tmp[0] !=
'\0';
355 char *
key,
const size_t key_size)
364 g_snprintf(
key, key_size,
"%d|%d|%s", (
int)work_profile->
type, (
int)work_profile->
intent,
366 return key[0] !=
'\0';
394 scratch = g_malloc0(
sizeof(*scratch));
434 patch->
width, patch->
height,
"drawlayer sidecar cache", &created))
447 "[drawlayer] cache rekey conflict old=%" PRIu64
" new=%" PRIu64
" -> published snapshot instead\n",
456 g->process.base_patch_loaded_ref =
TRUE;
463 g->process.base_patch_stroke_refs++;
474 g->process.base_patch_loaded_ref =
FALSE;
475 g->process.base_patch_stroke_refs = 0;
479 if(
g->process.base_patch_loaded_ref)
482 g->process.base_patch_loaded_ref =
FALSE;
485 while(
g->process.base_patch_stroke_refs > 0)
488 g->process.base_patch_stroke_refs--;
529 const gboolean have_sidecar = have_sidecar_path && g_file_test(path, G_FILE_TEST_EXISTS);
548 if(!have_pipe_geometry)
581 "drawlayer sidecar cache", &created))
593 gboolean warm_loaded =
FALSE;
594 const gboolean load_attempted = have_sidecar && info.
found;
649 const gboolean use_preview_bg,
const float preview_bg)
653 const dt_aligned_pixel_simd_t preview_base = { preview_bg, preview_bg, preview_bg, 1.0f };
655 for(
size_t kk = 0; kk < pixels; kk++)
657 const float *base = input + 4 * kk;
658 const float *layer = layerbuf + 4 * kk;
659 float *pixel = output + 4 * kk;
660 const float src_alpha =
_clamp01(layer[3]);
661 if(src_alpha > 1e-8f)
663 const dt_aligned_pixel_simd_t base_v = use_preview_bg ? preview_base : dt_load_simd_aligned(base);
664 dt_aligned_pixel_simd_t src_v = dt_load_simd_aligned(layer);
665 const float inv_alpha = 1.0f - src_alpha;
666 const dt_aligned_pixel_simd_t inv_alpha_v = { inv_alpha, inv_alpha, inv_alpha, inv_alpha };
667 src_v[3] = src_alpha;
672 const dt_aligned_pixel_simd_t base_v = use_preview_bg ? preview_base : dt_load_simd_aligned(base);
692 if(dirty_rect && dirty_rect->
valid)
694 const int dirty_x0 = CLAMP(dirty_rect->
nw[0], 0,
width);
695 const int dirty_y0 = CLAMP(dirty_rect->
nw[1], 0,
height);
696 const int dirty_x1 = CLAMP(dirty_rect->
se[0], 0,
width);
697 const int dirty_y1 = CLAMP(dirty_rect->
se[1], 0,
height);
698 const int dirty_w = dirty_x1 - dirty_x0;
699 const int dirty_h = dirty_y1 - dirty_y0;
700 if(dirty_w > 0 && dirty_h > 0 && (dirty_w <
width || dirty_h <
height))
702 const size_t origin[] = { (size_t)dirty_x0, (
size_t)dirty_y0, 0 };
703 const size_t region[] = { (size_t)dirty_w, (
size_t)dirty_h, 1 };
704 char *host_origin = (
char *)host_pixels + ((
size_t)dirty_y0 *
width + dirty_x0) * (
size_t)
bpp;
706 CL_TRUE) == CL_SUCCESS)
723 const gboolean realtime_reuse,
724 const int source_w,
const int source_h,
734 if(realtime_reuse && resolved_entry)
737 gboolean reused_from_cache =
FALSE;
739 "drawlayer source", resolved_entry,
740 &reused_from_cache, NULL);
744 = (reused_from_cache &&
process) ? &
process->cache_dirty_rect : NULL;
746 4 *
sizeof(
float), dirty_rect))
758 (
void *)layer_pixels, resolved_entry, devid, source_w, source_h,
759 4 *
sizeof(
float), CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, NULL);
767 devid, source_w, source_h, 4 *
sizeof(
float), (
void *)layer_pixels, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR);
771 4 *
sizeof(
float), NULL))
786 const int source_w,
const int source_h,
790 const gboolean can_copy_crop
791 = (fabs(target_roi->
scale - 1.0) <= 1e-6 && target_roi->
x >= 0
792 && target_roi->
y >= 0 && target_roi->
x + target_roi->
width <= source_w
793 && target_roi->
y + target_roi->
height <= source_h);
796 size_t src_origin[3] = { (size_t)target_roi->
x, (
size_t)target_roi->
y, 0 };
797 size_t dst_origin[3] = { 0, 0, 0 };
798 size_t region[3] = { (size_t)target_roi->
width, (
size_t)target_roi->
height, 1 };
801 if(copy_err == CL_SUCCESS)
return CL_SUCCESS;
817 const gboolean realtime_reuse,
818 cl_mem dev_source_rgba,
const int source_w,
const int source_h,
826 if(realtime_reuse && resolved_entry)
829 "drawlayer layer", resolved_entry, NULL,
841 *err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
847 return *err == CL_SUCCESS;
851 cl_mem dev_background, cl_mem dev_layer_rgba, cl_mem dev_out,
852 const int width,
const int height,
const int background_offset_x,
853 const int background_offset_y)
855 const int offs[2] = { background_offset_x, background_offset_y };
864 if(err != CL_SUCCESS)
return err;
874#define DRAWLAYER_RESAMPLE_DAMAGE_MARGIN 8
891 const double scale = target_roi->
scale;
895 const double sx0 = (
double)src_damage->
nw[0] + source_roi->
x;
896 const double sy0 = (
double)src_damage->
nw[1] + source_roi->
y;
897 const double sx1 = (
double)src_damage->
se[0] + source_roi->
x;
898 const double sy1 = (
double)src_damage->
se[1] + source_roi->
y;
900 int tx0 = (int)floor(sx0 * scale - target_roi->
x) - margin;
901 int ty0 = (int)floor(sy0 * scale - target_roi->
y) - margin;
902 int tx1 = (int)ceil(sx1 * scale - target_roi->
x) + margin;
903 int ty1 = (int)ceil(sy1 * scale - target_roi->
y) + margin;
905 tx0 = CLAMP(tx0, 0, target_roi->
width);
906 ty0 = CLAMP(ty0, 0, target_roi->
height);
907 tx1 = CLAMP(tx1, 0, target_roi->
width);
908 ty1 = CLAMP(ty1, 0, target_roi->
height);
910 if(tx1 <= tx0 || ty1 <= ty0)
return FALSE;
912 if(tx0 == 0 && ty0 == 0 && tx1 == target_roi->
width && ty1 == target_roi->
height)
return FALSE;
954 gboolean resolved_entry_ref =
FALSE;
959 resolved_entry_ref = (!
IS_NULL_PTR(resolved_entry));
978 const gint64 stage_t0 = trace_stages ? g_get_monotonic_time() : 0;
979 gint64 stage_source = stage_t0;
980 gint64 stage_layer = stage_t0;
984 cl_mem dev_layer_partial = NULL;
985 cl_mem dev_bg_partial = NULL;
986 cl_mem dev_out_partial = NULL;
987 cl_mem dev_background = NULL;
988 int err = CL_SUCCESS;
993 if(trace_stages) stage_source = g_get_monotonic_time();
997 const int dw = target_damage.
se[0] - target_damage.
nw[0];
998 const int dh = target_damage.
se[1] - target_damage.
nw[1];
999 size_t win_origin[3] = { (size_t)target_damage.
nw[0], (
size_t)target_damage.
nw[1], 0 };
1000 size_t zero_origin[3] = { 0, 0, 0 };
1001 size_t win_region[3] = { (size_t)dw, (
size_t)dh, 1 };
1016 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
1031 if(err != CL_SUCCESS)
goto cleanup;
1034 if(err != CL_SUCCESS)
goto cleanup;
1037 dev_out_partial, dw, dh, 0, 0);
1038 if(err != CL_SUCCESS)
goto cleanup;
1041 if(err != CL_SUCCESS)
goto cleanup;
1058 "[drawlayer] composite partial win=%dx%d src=%.2f ms kernel=%.2f ms total=%.2f ms\n",
1059 dw, dh, (stage_source - stage_t0) / 1000.0,
1060 (g_get_monotonic_time() - stage_source) / 1000.0,
1061 (g_get_monotonic_time() - stage_t0) / 1000.0);
1068 if(trace_stages) stage_layer = g_get_monotonic_time();
1075 "drawlayer req->process req->scratch");
1078 for(
size_t kk = 0; kk < out_pixels; kk++)
1080 float *pixel = background + 4 * kk;
1088 4 *
sizeof(
float), CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, NULL);
1092 dev_background = req->
dev_in;
1096 if(err != CL_SUCCESS)
goto cleanup;
1097 const gint64 stage_kernel = trace_stages ? g_get_monotonic_time() : 0;
1115 "[drawlayer] composite FULL out=%dx%d src=%dx%d src_up=%.2f ms resample=%.2f ms "
1116 "kernel=%.2f ms finish=%.2f ms total=%.2f ms pinned=%d\n",
1118 (stage_source - stage_t0) / 1000.0, (stage_layer - stage_source) / 1000.0,
1119 (stage_kernel - stage_layer) / 1000.0,
1120 (g_get_monotonic_time() - stage_kernel) / 1000.0,
1121 (g_get_monotonic_time() - stage_t0) / 1000.0, source.
is_pinned ? 1 : 0);
1129 (
void **)&dev_background);
1130 if(layer.
mem && layer.
mem != source.
mem)
1139 (
void **)&source.
mem);
1144 if(resolved_entry_ref)
1158 for(
const unsigned char *c = (
const unsigned char *)
value; *c; c++)
1162 else if(!g_ascii_isprint(*c))
1166 return separators >= 2;
1171 if(
IS_NULL_PTR(path) || path[0] ==
'\0' || !g_file_test(path, G_FILE_TEST_EXISTS))
return 0;
1173 GStatBuf st = { 0 };
1174 if(g_stat(path, &st) != 0)
return 0;
1175 return (int64_t)st.st_mtime;
1179 const float hardness)
1185 float display_rgb[3] = { 0.0f };
1188 const int size_px =
MAX(2, (
int)ceil((2.0f * widget_radius + 2.0f) * ppd));
1190 const gboolean needs_rebuild
1191 = !
g->ui.cursor_surface ||
g->ui.cursor_surface_size != size_px || fabs(
g->ui.cursor_surface_ppd - ppd) > 1e-9
1192 || fabsf(
g->ui.cursor_radius - widget_radius) > 1e-3f || fabsf(
g->ui.cursor_opacity - opacity) > 1e-6f
1193 || fabsf(
g->ui.cursor_hardness - hardness) > 1e-6f ||
g->ui.cursor_shape != shape
1194 || fabsf(
g->ui.cursor_color[0] - display_rgb[0]) > 1e-6f || fabsf(
g->ui.cursor_color[1] - display_rgb[1]) > 1e-6f
1195 || fabsf(
g->ui.cursor_color[2] - display_rgb[2]) > 1e-6f;
1196 if(!needs_rebuild)
return;
1199 g->ui.cursor_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size_px, size_px);
1200 if(cairo_surface_status(
g->ui.cursor_surface) != CAIRO_STATUS_SUCCESS)
1205 cairo_surface_set_device_scale(
g->ui.cursor_surface, ppd, ppd);
1207 unsigned char *data = cairo_image_surface_get_data(
g->ui.cursor_surface);
1208 const int stride = cairo_image_surface_get_stride(
g->ui.cursor_surface);
1209 memset(data, 0, (
size_t)stride * size_px);
1212 .
radius = fmaxf(widget_radius * (
float)ppd, 0.5f),
1214 .hardness = hardness,
1216 .display_color = { display_rgb[0], display_rgb[1], display_rgb[2] },
1219 const float half = 0.5f * (float)size_px;
1221 cairo_surface_mark_dirty(
g->ui.cursor_surface);
1223 g->ui.cursor_surface_size = size_px;
1224 g->ui.cursor_surface_ppd = ppd;
1225 g->ui.cursor_radius = widget_radius;
1226 g->ui.cursor_opacity = opacity;
1227 g->ui.cursor_hardness = hardness;
1228 g->ui.cursor_shape = shape;
1229 g->ui.cursor_color[0] = display_rgb[0];
1230 g->ui.cursor_color[1] = display_rgb[1];
1231 g->ui.cursor_color[2] = display_rgb[2];
1241 if(
main) gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(
main));
1242 gtk_window_set_modal(GTK_WINDOW(dialog),
TRUE);
1243 gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog),
TRUE);
1244 gtk_window_set_deletable(GTK_WINDOW(dialog),
FALSE);
1245 gtk_window_set_resizable(GTK_WINDOW(dialog),
FALSE);
1246 gtk_window_set_title(GTK_WINDOW(dialog), title);
1247 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
1249 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1252 GtkWidget *label = gtk_label_new(message);
1253 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1254 gtk_box_pack_start(GTK_BOX(box), spinner,
FALSE,
FALSE, 0);
1255 gtk_box_pack_start(GTK_BOX(box), label,
TRUE,
TRUE, 0);
1257 gtk_box_pack_start(GTK_BOX(content), box,
TRUE,
TRUE, 0);
1258 gtk_spinner_start(GTK_SPINNER(spinner));
1259 gtk_widget_show_all(dialog);
1260 gtk_widget_show_now(dialog);
1261 gtk_window_present(GTK_WINDOW(dialog));
1262 GdkDisplay *display = gtk_widget_get_display(dialog);
1263 if(display) gdk_display_flush(display);
1268 for(
int k = 0;
k < 2;
k++)
1269 gtk_main_iteration_do(
FALSE);
1286 g_main_loop_quit(
state->loop);
1287 return G_SOURCE_REMOVE;
1290 return G_SOURCE_CONTINUE;
1294 const char *title,
const char *message)
1299 GMainLoop *loop = g_main_loop_new(NULL,
FALSE);
1307 g_main_loop_run(loop);
1309 if(source_id) g_source_remove(source_id);
1312 gtk_widget_destroy(wait.
dialog);
1315 g_main_loop_unref(loop);
1323 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1324 type, GTK_BUTTONS_OK,
"%s", primary);
1325 if(secondary && secondary[0] !=
'\0')
1326 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
"%s", secondary);
1327 gtk_dialog_run(GTK_DIALOG(dialog));
1328 gtk_widget_destroy(dialog);
1332 char *
name,
const size_t name_size)
1336 GtkWidget *dialog = gtk_dialog_new_with_buttons(
1338 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, _(
"Cancel"), GTK_RESPONSE_CANCEL,
1339 _(
"Confirm"), GTK_RESPONSE_ACCEPT, NULL);
1340 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1345 GtkWidget *label = gtk_label_new(message);
1346 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1347 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
1348 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
FALSE, 0);
1350 gtk_entry_set_activates_default(GTK_ENTRY(entry),
TRUE);
1351 if(initial_name && initial_name[0] !=
'\0') gtk_entry_set_text(GTK_ENTRY(entry), initial_name);
1352 gtk_box_pack_start(GTK_BOX(box), entry,
FALSE,
FALSE, 0);
1354 gtk_box_pack_start(GTK_BOX(content), box,
TRUE,
TRUE, 0);
1355 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1356 gtk_widget_show_all(dialog);
1358 gboolean accepted =
FALSE;
1359 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1365 gtk_widget_destroy(dialog);
1374 float display_rgb[3] = { 0.0f };
1403 float display_rgb[3] = { 0.0f };
1417 gtk_widget_queue_draw(
g->controls.brush_shape);
1442 gtk_widget_queue_draw(widget);
1447 const float working_rgb[3],
float display_rgb[3])
1452 const float inv_gain = (gain > 0.0f) ? 1.0f / gain : 1.0f;
1453 const float preview_rgb[3] = {
1454 working_rgb[0] * inv_gain,
1455 working_rgb[1] * inv_gain,
1456 working_rgb[2] * inv_gain,
1459 display_rgb[0] =
_clamp01(preview_rgb[0]);
1460 display_rgb[1] =
_clamp01(preview_rgb[1]);
1461 display_rgb[2] =
_clamp01(preview_rgb[2]);
1470 float in[4] = { preview_rgb[0], preview_rgb[1], preview_rgb[2], 0.0f };
1471 float out[4] = { preview_rgb[0], preview_rgb[1], preview_rgb[2], 0.0f };
1503 const float *picked_min
1505 const float *picked_max
1507 if(picked_max[0] < picked_min[0])
return;
1509 float display_rgb[3] = { 0.0f };
1530 float display_rgb[3] = { 0.0f };
1583 sizeof(current_profile)))
1592 if(!(!
IS_NULL_PTR(requested) && requested[0]))
return;
1594 gboolean last_was_space =
FALSE;
1596 for(
size_t in = 0; requested[in] !=
'\0' &&
out + 1 < name_size; in++)
1598 const unsigned char ch = (
unsigned char)requested[in];
1599 if(g_ascii_isspace(
ch))
1601 if(
out > 0 && !last_was_space)
1604 last_was_space =
TRUE;
1610 last_was_space =
FALSE;
1637 .width =
process->base_patch.width,
1638 .height =
process->base_patch.height,
1663 process_roi.
x += (int)lroundf((
float)placement.
offset_x * process_roi.
scale);
1664 process_roi.
y += (int)lroundf((
float)placement.
offset_y * process_roi.
scale);
1692 const int preview_mode = (gui && self && self->
dev && self->
dev->
gui_module == self)
1704 const gboolean have_last_dab,
const float last_dab_x,
1705 const float last_dab_y,
const uint32_t publish_serial)
1709 uint32_t x_bits = 0u;
1710 uint32_t y_bits = 0u;
1713 memcpy(&x_bits, &last_dab_x,
sizeof(x_bits));
1714 memcpy(&y_bits, &last_dab_y,
sizeof(y_bits));
1717 const uint32_t seed[5] = { (uint32_t)dab_count, have_last_dab ? 1u : 0u, x_bits, y_bits, publish_serial };
1731 GMainContext *
const ui_ctx = g_main_context_default();
1745 const gboolean missing = (
g->session.missing_layer_error[0] !=
'\0');
1748 if(
g->controls.notebook)
1750 if(
g->controls.brush_tab) gtk_widget_set_visible(
g->controls.brush_tab, attached);
1751 if(
g->controls.input_tab) gtk_widget_set_visible(
g->controls.input_tab, attached);
1752 if(
g->controls.layer_tab) gtk_widget_set_visible(
g->controls.layer_tab,
TRUE);
1753 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(
g->controls.notebook), attached);
1754 gtk_notebook_set_show_border(GTK_NOTEBOOK(
g->controls.notebook), attached);
1755 if(!attached &&
g->controls.layer_tab)
1756 gtk_notebook_set_current_page(GTK_NOTEBOOK(
g->controls.notebook),
1757 gtk_notebook_page_num(GTK_NOTEBOOK(
g->controls.notebook),
g->controls.layer_tab));
1760 if(
g->controls.preview_title) gtk_widget_set_visible(
g->controls.preview_title, attached);
1761 if(
g->controls.preview_box) gtk_widget_set_visible(
g->controls.preview_box, attached);
1762 if(
g->controls.layer_action_row) gtk_widget_set_visible(
g->controls.layer_action_row,
TRUE);
1763 if(
g->controls.layer_status)
1765 gtk_label_set_text(GTK_LABEL(
g->controls.layer_status), missing ?
g->session.missing_layer_error :
"");
1766 gtk_widget_set_visible(
g->controls.layer_status, missing);
1768 if(
g->controls.delete_layer) gtk_widget_set_visible(
g->controls.delete_layer, attached);
1769 if(
g->controls.rename_layer) gtk_widget_set_visible(
g->controls.rename_layer, attached);
1770 if(
g->controls.layer_fill_title) gtk_widget_set_visible(
g->controls.layer_fill_title, attached);
1771 if(
g->controls.layer_fill_row) gtk_widget_set_visible(
g->controls.layer_fill_row, attached);
1772 if(
g->controls.create_background) gtk_widget_set_visible(
g->controls.create_background, attached);
1773 if(
g->controls.save_layer) gtk_widget_set_visible(
g->controls.save_layer, attached);
1774 if(
g->controls.attach_layer) gtk_widget_set_visible(
g->controls.attach_layer, !attached && have_existing_layers);
1776 if(
g->controls.layer_select) gtk_widget_set_visible(
g->controls.layer_select, attached || have_existing_layers);
1777 if(
g->controls.create_layer) gtk_widget_set_sensitive(
g->controls.create_layer,
TRUE);
1778 if(
g->controls.rename_layer) gtk_widget_set_sensitive(
g->controls.rename_layer, attached);
1779 if(
g->controls.attach_layer) gtk_widget_set_sensitive(
g->controls.attach_layer, have_existing_layers);
1780 if(
g->controls.create_background)
1781 gtk_widget_set_sensitive(
g->controls.create_background, attached && !
g->session.background_job_running);
1782 if(
g->controls.save_layer) gtk_widget_set_sensitive(
g->controls.save_layer, attached);
1790 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_image))
1791 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_image),
1793 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_white))
1794 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_white),
1796 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_grey))
1797 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_grey),
1799 if(GTK_IS_TOGGLE_BUTTON(
g->controls.preview_bg_black))
1800 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->controls.preview_bg_black),
1819 if(
g->manager.painting_active)
1822 dt_print(
DT_DEBUG_PERF,
"[drawlayer] commit_dabs deferred: stroke in progress (record_history=%d)\n",
1842 int sample_count = 0;
1843 gboolean had_stroke =
FALSE;
1844 gboolean had_last_dab =
FALSE;
1845 float last_dab_x = 0.0f;
1846 float last_dab_y = 0.0f;
1848 g->stroke.finish_commit_pending =
FALSE;
1849 sample_count = (int)
g->stroke.stroke_sample_count;
1850 had_stroke = (sample_count > 0);
1851 had_last_dab =
g->stroke.last_dab_valid;
1852 last_dab_x =
g->stroke.last_dab_x;
1853 last_dab_y =
g->stroke.last_dab_y;
1869 if(record_history && self->
dev)
1877 if(self->post_history_commit) self->post_history_commit(self);
1879 g->manager.realtime_active =
FALSE;
1893 if(!(had_stroke && record_history))
1895 g->manager.realtime_active =
FALSE;
1918 gtk_widget_set_visible(GTK_WIDGET(
g->controls.color), paint_mode);
1919 if(
g->controls.color_row) gtk_widget_set_visible(
g->controls.color_row, paint_mode);
1920 if(
g->controls.color_swatch) gtk_widget_set_visible(
g->controls.color_swatch, paint_mode);
1921 if(
g->controls.image_colorpicker) gtk_widget_set_visible(
g->controls.image_colorpicker, paint_mode);
1922 if(
g->controls.image_colorpicker_source) gtk_widget_set_visible(
g->controls.image_colorpicker_source, paint_mode);
1923 gtk_widget_set_visible(
g->controls.softness, show_hardness);
1934 GString *errors = g_string_new(NULL);
1935 gboolean deleted =
FALSE;
1950 else if(!g_file_test(path, G_FILE_TEST_EXISTS))
1965 if(
g)
g->session.missing_layer_error[0] =
'\0';
1970 g->process.cache_valid =
FALSE;
1971 g->process.cache_dirty =
FALSE;
1973 g->process.cache_imgid = -1;
1974 g->process.cache_layer_name[0] =
'\0';
1975 g->process.cache_layer_order = -1;
1983 g_string_free(errors,
TRUE);
1994 GtkWidget *dialog = gtk_message_dialog_new(
1996 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
"%s",
1998 ? _(
"Delete the linked drawing layer from the sidecar TIFF before removing this module instance?")
1999 : _(
"Delete the linked drawing layer from the sidecar TIFF?"));
2002 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Keep layer"), GTK_RESPONSE_NO);
2003 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Delete layer"), GTK_RESPONSE_YES);
2007 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Cancel"), GTK_RESPONSE_CANCEL);
2008 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Delete"), GTK_RESPONSE_ACCEPT);
2011 const int response = gtk_dialog_run(GTK_DIALOG(dialog));
2012 gtk_widget_destroy(dialog);
2021 if(response != GTK_RESPONSE_ACCEPT)
return FALSE;
2034 if(!
IS_NULL_PTR(requested_name)) g_strlcpy(stripped_requested, requested_name,
sizeof(stripped_requested));
2035 g_strstrip(stripped_requested);
2036 if(stripped_requested[0] ==
'\0')
return FALSE;
2038 if(new_name[0] ==
'\0')
return FALSE;
2042 GString *errors = g_string_new(NULL);
2043 gboolean renamed =
FALSE;
2062 else if(!g_file_test(path, G_FILE_TEST_EXISTS))
2075 g_strlcpy(
g->process.cache_layer_name,
params->
layer_name,
sizeof(
g->process.cache_layer_name));
2084 g->session.missing_layer_error[0] =
'\0';
2094 g_string_free(errors,
TRUE);
2106 if(!
IS_NULL_PTR(requested_name)) g_strlcpy(stripped_requested, requested_name,
sizeof(stripped_requested));
2107 g_strstrip(stripped_requested);
2108 if(stripped_requested[0] ==
'\0')
return FALSE;
2110 if(new_name[0] ==
'\0')
return FALSE;
2117 _(
"A drawing layer with that name already exists."),
2118 _(
"Choose a different layer name."));
2142 if(!
g->process.cache_valid ||
IS_NULL_PTR(
g->process.base_patch.pixels))
2148 g->process.cache_dirty =
TRUE;
2156 g->session.missing_layer_error[0] =
'\0';
2170 if(
IS_NULL_PTR(filter) || filter_size == 0)
return;
2175 const char *prev_op = NULL;
2176 if(self_piece && self->
dev->
pipe)
2178 for(GList *nodes = self->
dev->
pipe->
nodes; nodes; nodes = g_list_next(nodes))
2181 if(
piece == self_piece)
break;
2185 if(!
IS_NULL_PTR(prev_op) && prev_op[0]) g_snprintf(filter, filter_size,
"pre:%s", prev_op);
2197 gboolean cleared_initiator =
FALSE;
2198 if(dev && dev->image_storage.id == result->
imgid)
2200 for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
2203 if(!module || g_strcmp0(module->op,
"drawlayer"))
continue;
2210 g->session.background_job_running =
FALSE;
2211 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
TRUE);
2212 cleared_initiator =
TRUE;
2223 if(!cleared_initiator && dev)
2225 for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
2228 if(!module || g_strcmp0(module->op,
"drawlayer"))
continue;
2230 if(
IS_NULL_PTR(
g) || !
g->session.background_job_running)
continue;
2231 g->session.background_job_running =
FALSE;
2232 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
TRUE);
2237 return G_SOURCE_REMOVE;
2245 if(
g->session.background_job_running)
return FALSE;
2268 g_strlcpy(current_info.
name, io_info.
name,
sizeof(current_info.
name));
2275 job_params->
dst_x = 0;
2276 job_params->
dst_y = 0;
2287 "drawlayer create background layer");
2296 g->session.background_job_running =
TRUE;
2297 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
FALSE);
2300 g->session.background_job_running =
FALSE;
2301 if(
g->controls.create_background) gtk_widget_set_sensitive(
g->controls.create_background,
TRUE);
2317 if(widget ==
g->controls.size || widget ==
g->controls.softness || widget ==
g->controls.brush_shape)
2320 if(widget ==
g->controls.hdr_exposure)
2322 float display_rgb[3] = { 0.0f };
2327 if(widget ==
g->controls.brush_shape || widget ==
g->controls.opacity || widget ==
g->controls.softness || widget ==
g->controls.sprinkles
2328 || widget ==
g->controls.sprinkle_size || widget ==
g->controls.sprinkle_coarseness)
2335 const int layer_order)
2353 g->session.missing_layer_error[0] =
'\0';
2372 if(active < 0)
return;
2395 if(active < 0)
return;
2413 _(
"Enter the new name for the current drawing layer."),
2446 const size_t count = (size_t)
g->process.base_patch.width *
g->process.base_patch.height;
2447 float *
const pixels =
g->process.base_patch.pixels;
2451 for(
size_t k = 0;
k < count;
k++)
2453 float *pixel = pixels + 4 *
k;
2461 g->process.cache_dirty =
TRUE;
2462 g->process.cache_dirty_rect.valid =
TRUE;
2463 g->process.cache_dirty_rect.nw[0] = 0;
2464 g->process.cache_dirty_rect.nw[1] = 0;
2465 g->process.cache_dirty_rect.se[0] =
g->process.base_patch.width;
2466 g->process.cache_dirty_rect.se[1] =
g->process.base_patch.height;
2486 (
size_t)
g->process.base_patch.width *
g->process.base_patch.height);
2489 g->process.cache_dirty =
TRUE;
2490 g->process.cache_dirty_rect.valid =
TRUE;
2491 g->process.cache_dirty_rect.nw[0] = 0;
2492 g->process.cache_dirty_rect.nw[1] = 0;
2493 g->process.cache_dirty_rect.se[0] =
g->process.base_patch.width;
2494 g->process.cache_dirty_rect.se[1] =
g->process.base_patch.height;
2530 if(!
g->process.cache_valid ||
IS_NULL_PTR(
g->process.base_patch.pixels))
2533 _(
"No drawing layer is loaded in memory."),
2534 _(
"The sidecar save was aborted."));
2540 _(
"Layer name is empty."),
2541 _(
"The sidecar save was aborted."));
2546 GtkWidget *dialog = gtk_message_dialog_new(
2548 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
"%s", _(
"Save the drawing sidecar now?"));
2549 gtk_message_dialog_format_secondary_text(
2550 GTK_MESSAGE_DIALOG(dialog),
"%s",
2551 _(
"This writes the current in-memory drawing layer to the sidecar TIFF immediately."));
2552 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Cancel"), GTK_RESPONSE_CANCEL);
2553 gtk_dialog_add_button(GTK_DIALOG(dialog), _(
"Save"), GTK_RESPONSE_ACCEPT);
2555 const int response = gtk_dialog_run(GTK_DIALOG(dialog));
2556 gtk_widget_destroy(dialog);
2557 if(response != GTK_RESPONSE_ACCEPT)
2563 _(
"Waiting for the layer rasterization to finish..."));
2571 _(
"Failed to finalize the drawing stroke."),
2572 _(
"The sidecar was not saved."));
2582 _(
"Failed to write the drawing layer sidecar."),
2583 _(
"The sidecar TIFF could not be updated."));
2591 _(
"Drawing sidecar saved."),
2592 _(
"The current in-memory layer has been written to the sidecar TIFF."));
2603 _(
"Enter the name of the new drawing layer."),
2604 "", requested_name,
sizeof(requested_name)))
2626 if(GTK_WIDGET(button) ==
g->controls.preview_bg_white)
2628 else if(GTK_WIDGET(button) ==
g->controls.preview_bg_grey)
2630 else if(GTK_WIDGET(button) ==
g->controls.preview_bg_black)
2650 const float input_wx = isfinite(pointer_input.
x) ? (float)pointer_input.
x : (float)wx;
2651 const float input_wy = isfinite(pointer_input.
y) ? (float)pointer_input.
y : (float)wy;
2656 .pressure = pressure_norm,
2659 .event_ts = g_get_monotonic_time(),
2660 .stroke_batch =
g->stroke.current_stroke_batch,
2661 .event_index = ++
g->stroke.stroke_event_index,
2662 .stroke_pos = stroke_pos,
2674 uint32_t stroke_batch =
g->stroke.current_stroke_batch + 1u;
2675 if(stroke_batch == 0u) stroke_batch++;
2676 const uint32_t event_index = first_input ? first_input->
event_index : 0u;
2680 g->session.pointer_valid =
TRUE;
2681 g->stroke.current_stroke_batch = stroke_batch;
2684 g->stroke.finish_commit_pending =
FALSE;
2685 g->stroke.stroke_sample_count = 0;
2686 g->stroke.stroke_event_index = event_index;
2687 g->stroke.last_dab_valid =
FALSE;
2706 const gboolean flush_pending)
2710 .raw_input_ok =
TRUE,
2719 .manager = &
g->manager,
2720 .process_state = &
g->process,
2730 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
2731 .flush_pending = flush_pending,
2745 _(
"Waiting for the drawing rasterization to finish..."));
2750 _(
"Waiting for the layer rasterization to finish..."));
2762 return C_(
"modulename",
"drawing");
2768 return dt_iop_set_description(self, _(
"paint premultiplied RGB layers in a TIFF sidecar"), _(
"creative"),
2769 _(
"linear, RGB, scene-referred"), _(
"geometric, RGB"),
2770 _(
"linear, RGB, scene-referred"));
2777 const int program = 3;
2796 module->data = NULL;
2821 module->params = calloc(1, sizeof(dt_iop_drawlayer_params_t));
2822 module->default_params = calloc(1, sizeof(dt_iop_drawlayer_params_t));
2823 module->params_size = sizeof(dt_iop_drawlayer_params_t);
2858 piece->data_size = 0;
2898 g->session.missing_layer_error[0] =
'\0';
2933 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.brush_mode,
TRUE,
TRUE, 0);
2935 GtkWidget *color_title = gtk_label_new(_(
"Color"));
2936 gtk_label_set_xalign(GTK_LABEL(color_title), 0.0f);
2938 gtk_box_pack_start(GTK_BOX(brush_tab), color_title,
TRUE,
TRUE, 0);
2939 g->controls.color = gtk_drawing_area_new();
2941 gtk_widget_add_events(
g->controls.color, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
2942 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.color,
TRUE,
TRUE, 0);
2944 g->controls.color_swatch = gtk_drawing_area_new();
2946 gtk_widget_add_events(
g->controls.color_swatch, GDK_BUTTON_PRESS_MASK);
2947 gtk_box_pack_start(GTK_BOX(
g->controls.color_row),
g->controls.color_swatch,
TRUE,
TRUE, 0);
2948 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.color_row,
TRUE,
TRUE, 0);
2955 gtk_box_pack_start(GTK_BOX(picker_controls),
g->controls.image_colorpicker,
TRUE,
TRUE, 0);
2956 gtk_box_pack_start(GTK_BOX(picker_controls),
g->controls.image_colorpicker_source,
TRUE,
TRUE, 0);
2957 gtk_box_pack_start(GTK_BOX(brush_tab), picker_controls,
TRUE,
TRUE, 0);
2959 g->controls.hdr_exposure
2963 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.hdr_exposure,
TRUE,
TRUE, 0);
2965 GtkWidget *geometry_title = gtk_label_new(_(
"Geometry"));
2966 gtk_label_set_xalign(GTK_LABEL(geometry_title), 0.0f);
2968 gtk_box_pack_start(GTK_BOX(brush_tab), geometry_title,
TRUE,
TRUE, 0);
2969 GtkWidget *brush_shape_title = gtk_label_new(_(
"Fall-off"));
2970 gtk_label_set_xalign(GTK_LABEL(brush_shape_title), 0.0f);
2971 gtk_box_pack_start(GTK_BOX(brush_tab), brush_shape_title,
TRUE,
TRUE, 0);
2972 g->controls.brush_shape = gtk_drawing_area_new();
2974 gtk_widget_add_events(
g->controls.brush_shape, GDK_BUTTON_PRESS_MASK);
2975 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.brush_shape,
TRUE,
TRUE, 0);
2981 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.size,
TRUE,
TRUE, 0);
2982 g->controls.distance
2986 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.distance,
TRUE,
TRUE, 0);
2987 g->controls.smoothing
2991 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.smoothing,
TRUE,
TRUE, 0);
2992 g->controls.softness
2997 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.softness,
TRUE,
TRUE, 0);
2999 GtkWidget *thickness_title = gtk_label_new(_(
"Thickness"));
3000 gtk_label_set_xalign(GTK_LABEL(thickness_title), 0.0f);
3002 gtk_box_pack_start(GTK_BOX(brush_tab), thickness_title,
TRUE,
TRUE, 0);
3007 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.opacity,
TRUE,
TRUE, 0);
3012 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.flow,
TRUE,
TRUE, 0);
3014 GtkWidget *texture_title = gtk_label_new(_(
"Texture"));
3015 gtk_label_set_xalign(GTK_LABEL(texture_title), 0.0f);
3017 gtk_box_pack_start(GTK_BOX(brush_tab), texture_title,
TRUE,
TRUE, 0);
3018 g->controls.sprinkles
3022 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.sprinkles,
TRUE,
TRUE, 0);
3023 g->controls.sprinkle_size
3027 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.sprinkle_size,
TRUE,
TRUE, 0);
3028 g->controls.sprinkle_coarseness
3032 gtk_box_pack_start(GTK_BOX(brush_tab),
g->controls.sprinkle_coarseness,
TRUE,
TRUE, 0);
3036 g_signal_connect(G_OBJECT(
g->controls.brush_mode),
"value-changed", G_CALLBACK(
_widget_changed), self);
3043 g_signal_connect(G_OBJECT(
g->controls.image_colorpicker_source),
"value-changed", G_CALLBACK(
_widget_changed), self);
3044 g_signal_connect(G_OBJECT(
g->controls.size),
"value-changed", G_CALLBACK(
_widget_changed), self);
3045 g_signal_connect(G_OBJECT(
g->controls.distance),
"value-changed", G_CALLBACK(
_widget_changed), self);
3046 g_signal_connect(G_OBJECT(
g->controls.smoothing),
"value-changed", G_CALLBACK(
_widget_changed), self);
3047 g_signal_connect(G_OBJECT(
g->controls.opacity),
"value-changed", G_CALLBACK(
_widget_changed), self);
3048 g_signal_connect(G_OBJECT(
g->controls.flow),
"value-changed", G_CALLBACK(
_widget_changed), self);
3049 g_signal_connect(G_OBJECT(
g->controls.sprinkles),
"value-changed", G_CALLBACK(
_widget_changed), self);
3050 g_signal_connect(G_OBJECT(
g->controls.sprinkle_size),
"value-changed", G_CALLBACK(
_widget_changed), self);
3051 g_signal_connect(G_OBJECT(
g->controls.sprinkle_coarseness),
"value-changed", G_CALLBACK(
_widget_changed), self);
3052 g_signal_connect(G_OBJECT(
g->controls.softness),
"value-changed", G_CALLBACK(
_widget_changed), self);
3053 g_signal_connect(G_OBJECT(
g->controls.hdr_exposure),
"value-changed", G_CALLBACK(
_widget_changed), self);
3065 GtkWidget *preview_title = gtk_label_new(_(
"Background"));
3066 g->controls.preview_title = preview_title;
3067 gtk_widget_set_halign(preview_title, GTK_ALIGN_START);
3069 g->controls.preview_box = preview_box;
3070 GSList *preview_group = NULL;
3071 g->controls.preview_bg_image = gtk_radio_button_new_with_label(preview_group, _(
"image"));
3072 preview_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
g->controls.preview_bg_image));
3073 g->controls.preview_bg_white = gtk_radio_button_new_with_label(preview_group, _(
"white"));
3074 preview_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
g->controls.preview_bg_white));
3075 g->controls.preview_bg_grey = gtk_radio_button_new_with_label(preview_group, _(
"grey"));
3076 preview_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
g->controls.preview_bg_grey));
3077 g->controls.preview_bg_black = gtk_radio_button_new_with_label(preview_group, _(
"black"));
3078 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_image,
TRUE,
TRUE, 0);
3079 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_white,
TRUE,
TRUE, 0);
3080 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_grey,
TRUE,
TRUE, 0);
3081 gtk_box_pack_start(GTK_BOX(preview_box),
g->controls.preview_bg_black,
TRUE,
TRUE, 0);
3082 gtk_box_pack_start(GTK_BOX(layer_tab), preview_title,
FALSE,
FALSE, 0);
3083 gtk_box_pack_start(GTK_BOX(layer_tab), preview_box,
FALSE,
FALSE, 0);
3086 GtkWidget *layer_status = gtk_label_new(
"");
3087 g->controls.layer_status = layer_status;
3088 gtk_widget_set_halign(layer_status, GTK_ALIGN_START);
3089 gtk_label_set_xalign(GTK_LABEL(layer_status), 0.0f);
3090 gtk_label_set_line_wrap(GTK_LABEL(layer_status),
TRUE);
3091 GtkWidget *layer_fill_title = gtk_label_new(_(
"Fill"));
3092 g->controls.layer_fill_title = layer_fill_title;
3093 gtk_widget_set_halign(layer_fill_title, GTK_ALIGN_START);
3095 g->controls.layer_action_row = layer_action_row;
3097 g->controls.layer_fill_row = layer_fill_row;
3100 g->controls.delete_layer = gtk_button_new_with_label(_(
"delete layer"));
3101 g->controls.create_layer = gtk_button_new_with_label(_(
"create new layer"));
3102 g->controls.rename_layer = gtk_button_new_with_label(_(
"rename layer"));
3103 g->controls.attach_layer = gtk_button_new_with_label(_(
"reuse selected layer"));
3104 g->controls.create_background = gtk_button_new_with_label(_(
"create background from input"));
3105 GtkWidget *fill_white = gtk_button_new_with_label(_(
"white"));
3106 GtkWidget *fill_black = gtk_button_new_with_label(_(
"black"));
3107 GtkWidget *fill_transparent = gtk_button_new_with_label(_(
"transparency"));
3108 gtk_box_pack_start(GTK_BOX(layer_box), layer_status,
FALSE,
FALSE, 0);
3109 gtk_box_pack_start(GTK_BOX(layer_box),
g->controls.layer_select,
FALSE,
FALSE, 0);
3110 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.create_layer,
TRUE,
TRUE, 0);
3111 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.rename_layer,
TRUE,
TRUE, 0);
3112 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.attach_layer,
TRUE,
TRUE, 0);
3113 gtk_box_pack_start(GTK_BOX(layer_action_row),
g->controls.delete_layer,
TRUE,
TRUE, 0);
3114 gtk_box_pack_start(GTK_BOX(layer_box), layer_action_row,
FALSE,
FALSE, 0);
3115 gtk_box_pack_start(GTK_BOX(layer_box), layer_fill_title,
FALSE,
FALSE, 0);
3116 gtk_box_pack_start(GTK_BOX(layer_fill_row), fill_white,
TRUE,
TRUE, 0);
3117 gtk_box_pack_start(GTK_BOX(layer_fill_row), fill_black,
TRUE,
TRUE, 0);
3118 gtk_box_pack_start(GTK_BOX(layer_fill_row), fill_transparent,
TRUE,
TRUE, 0);
3119 gtk_box_pack_start(GTK_BOX(layer_box), layer_fill_row,
FALSE,
FALSE, 0);
3120 gtk_box_pack_start(GTK_BOX(layer_box),
g->controls.create_background,
FALSE,
FALSE, 0);
3121 gtk_box_pack_start(GTK_BOX(layer_tab), layer_box,
FALSE,
FALSE, 0);
3123 g_signal_connect(G_OBJECT(
g->controls.layer_select),
"value-changed", G_CALLBACK(
_layer_selected), self);
3124 g_signal_connect(
g->controls.preview_bg_image,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3125 g_signal_connect(
g->controls.preview_bg_white,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3126 g_signal_connect(
g->controls.preview_bg_grey,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3127 g_signal_connect(
g->controls.preview_bg_black,
"toggled", G_CALLBACK(
_preview_bg_toggled), self);
3148 GtkWidget *mapping_title = gtk_label_new(_(
"tablet mapping"));
3149 gtk_widget_set_halign(mapping_title, GTK_ALIGN_START);
3154 const char *labels[4] = { _(
"size"), _(
"opacity"), _(
"flow"), _(
"hardness") };
3155 const char *rows[3] = { _(
"pressure"), _(
"tilt"), _(
"acceleration") };
3159 for(
int c = 0; c < 4; c++)
3161 GtkWidget *label = gtk_label_new(labels[c]);
3162 gtk_label_set_angle(GTK_LABEL(label), 90.0);
3163 gtk_grid_attach(GTK_GRID(grid), label, c + 1, 0, 1, 1);
3165 gtk_grid_attach(GTK_GRID(grid), gtk_label_new(_(
"profile")), 5, 0, 1, 1);
3167 for(
int r = 0;
r < 3;
r++)
3169 gtk_grid_attach(GTK_GRID(grid), gtk_label_new(rows[
r]), 0,
r + 1, 1, 1);
3170 for(
int c = 0; c < 4; c++)
3173 gtk_grid_attach(GTK_GRID(grid), *mapping[
r].targets[c].widget, c + 1,
r + 1, 1, 1);
3182 gtk_grid_attach(GTK_GRID(grid), *mapping[
r].profile.widget, 5,
r + 1, 1, 1);
3185 gtk_box_pack_start(GTK_BOX(input_tab), mapping_title,
FALSE,
FALSE, 0);
3186 gtk_box_pack_start(GTK_BOX(input_tab), grid,
FALSE,
FALSE, 0);
3188 for(
int r = 0;
r < 3;
r++)
3191 g_signal_connect(G_OBJECT(*mapping[
r].profile.widget),
"value-changed", G_CALLBACK(
_widget_changed), self);
3208 &
g->stroke.finish_commit_pending, &
g->stroke.stroke_sample_count,
3209 &
g->stroke.current_stroke_batch);
3210 g->session.background_job_running =
FALSE;
3211 g->session.last_view_x = 0.0f;
3212 g->session.last_view_y = 0.0f;
3213 g->session.last_view_scale = 1.0f;
3225 g->controls.save_layer = gtk_button_new_with_label(_(
"save sidecar"));
3226 gtk_box_pack_start(GTK_BOX(history_box),
g->controls.save_layer,
TRUE,
TRUE, 0);
3240 g->controls.brush_tab = brush_tab;
3241 g->controls.layer_tab = layer_tab;
3242 g->controls.input_tab = input_tab;
3244 gtk_notebook_append_page(GTK_NOTEBOOK(
notebook), brush_tab, gtk_label_new(_(
"Brush")));
3245 gtk_notebook_append_page(GTK_NOTEBOOK(
notebook), layer_tab, gtk_label_new(_(
"Layer")));
3246 gtk_notebook_append_page(GTK_NOTEBOOK(
notebook), input_tab, gtk_label_new(_(
"Input")));
3247 gtk_container_child_set(GTK_CONTAINER(
notebook), brush_tab,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
3248 gtk_container_child_set(GTK_CONTAINER(
notebook), layer_tab,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
3249 gtk_container_child_set(GTK_CONTAINER(
notebook), input_tab,
"tab-expand",
TRUE,
"tab-fill",
TRUE, NULL);
3307 if(
g->controls.color) gtk_widget_queue_draw(
g->controls.color);
3315 float display_rgb[3] = { 0.0f };
3327 if(GTK_IS_TOGGLE_BUTTON(target))
3328 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(target),
dt_conf_get_bool(mapping[
r].targets[c].conf_key));
3330 if(*mapping[
r].profile.widget)
3351 g->session.missing_layer_error[0] =
'\0';
3363 const int pending_samples =
g ? (int)
g->stroke.stroke_sample_count : 0;
3364 const gboolean had_pending_edits
3365 = (
g && (
g->process.cache_dirty ||
g->stroke.stroke_sample_count > 0));
3368 if(had_pending_edits &&
params)
3370 g->stroke.last_dab_y, 0u);
3379 if(self->post_history_commit) self->post_history_commit(self);
3418 memset(&
g->session.live_patch, 0,
sizeof(
g->session.live_patch));
3442 const float pressure_norm
3444 const float tilt_norm =
_clamp01((pointer_input && pointer_input->
has_tilt) ? pointer_input->
tilt : 0.0f);
3473 state->pressure = pressure_norm;
3474 state->tilt = tilt_norm;
3475 state->acceleration = accel_norm;
3476 state->radius = fmaxf(0.5f, radius);
3486 char lines[3][128] = { { 0 } };
3487 g_snprintf(lines[0],
sizeof(lines[0]), _(
"size %.1f px hardness %.2f%%"),
state->radius * 2.0f,
3488 state->hardness * 100.0f);
3489 g_snprintf(lines[1],
sizeof(lines[1]), _(
"opacity %.2f%% flow %.2f%%"),
state->opacity * 100.0f,
3490 state->flow * 100.0f);
3491 g_snprintf(lines[2],
sizeof(lines[2]), _(
"pressure %.2f%% tilt %.2f%% acceleration %.2f%%"),
3492 state->pressure * 100.0f,
state->tilt * 100.0f,
state->acceleration * 100.0f);
3499 cairo_select_font_face(cr,
"Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
3500 cairo_set_font_size(cr, fs);
3501 for(
int i = 0;
i < 3;
i++)
3503 cairo_text_extents_t ext = { 0 };
3504 cairo_text_extents(cr, lines[
i], &ext);
3505 max_w = fmax(max_w, ext.x_advance);
3508 const double box_w = max_w + 2.0 * pad;
3509 const double box_h = 3.0 * line_h + 2.0 * pad;
3514 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.55);
3515 cairo_rectangle(cr,
x, y, box_w, box_h);
3518 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.92);
3519 for(
int i = 0;
i < 3;
i++)
3522 cairo_show_text(cr, lines[
i]);
3535 cairo_set_line_width(cr, 1.0);
3536 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.8);
3538 if(
g->session.pointer_valid)
3542 const float widget_x = isfinite(pointer_input.
x)
3543 ? (float)pointer_input.
x
3544 : ((pointerx >= 0 && pointery >= 0) ? (
float)pointerx : -1.0f);
3545 const float widget_y = isfinite(pointer_input.
y)
3546 ? (float)pointer_input.
y
3547 : ((pointerx >= 0 && pointery >= 0) ? (
float)pointery : -1.0f);
3548 if(widget_x < 0.0f || widget_y < 0.0f)
3556 float radius = hud.
radius;
3559 float draw_x = widget_x;
3560 float draw_y = widget_y;
3580 const float draw_radius = fmaxf(0.5f, widget_radius);
3584 if(
g->ui.cursor_surface)
3586 const float surface_half_extent = 0.5f * (float)
g->ui.cursor_surface_size / (
float)
g->ui.cursor_surface_ppd;
3587 cairo_set_source_surface(cr,
g->ui.cursor_surface, draw_x - surface_half_extent, draw_y - surface_half_extent);
3593 cairo_set_source_rgba(cr, 0., 0., 0., 0.5);
3594 cairo_set_line_width(cr, 2.5);
3595 cairo_arc(cr, draw_x, draw_y, draw_radius + 1.0f, 0.0, 2.0 *
M_PI);
3598 cairo_set_source_rgba(cr, 1., 1., 1., 0.5);
3599 cairo_set_line_width(cr, 1.0);
3600 cairo_arc(cr, draw_x, draw_y, draw_radius, 0.0, 2.0 *
M_PI);
3632 if(
g->session.pointer_valid)
3638 if(!
g->session.pointer_valid)
3645 .manager = &
g->manager,
3646 .process_state = &
g->process,
3655 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_ENTER,
3656 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3661 if(
g->manager.painting_active)
3669 .manager = &
g->manager,
3670 .process_state = &
g->process,
3672 .raw_input = &input,
3689 dt_print(
DT_DEBUG_PERF,
"[drawlayer] stroke abort from mouse_moved: dispatch.ok=%d raw_input_ok=%d\n",
3694 .event = DT_DRAWLAYER_RUNTIME_EVENT_GUI_STROKE_ABORT,
3695 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
3707 .manager = &
g->manager,
3708 .process_state = &
g->process,
3722 return g->manager.painting_active ? 1 : 0;
3741 const float input_wx = isfinite(pointer_input.
x) ? (float)pointer_input.
x : (float)
x;
3742 const float input_wy = isfinite(pointer_input.
y) ? (float)pointer_input.
y : (float)y;
3744 uint32_t stroke_batch =
g->stroke.current_stroke_batch + 1u;
3745 if(stroke_batch == 0u) stroke_batch++;
3749 .pressure = pressure_norm,
3752 .event_ts = g_get_monotonic_time(),
3753 .stroke_batch = stroke_batch,
3764 .manager = &
g->manager,
3765 .process_state = &
g->process,
3767 .raw_input = &first,
3793 if(
g->manager.painting_active)
3797 const float input_wx = isfinite(pointer_input.
x) ? (float)pointer_input.
x : (float)
x;
3798 const float input_wy = isfinite(pointer_input.
y) ? (float)pointer_input.
y : (float)y;
3805 .event_ts = g_get_monotonic_time(),
3806 .stroke_batch =
g->stroke.current_stroke_batch,
3807 .event_index = ++
g->stroke.stroke_event_index,
3817 .manager = &
g->manager,
3818 .process_state = &
g->process,
3851 const float factor = increase ? 1.1f : 0.9f;
3888 const gboolean have_gui,
3891 const gboolean use_opencl)
3896 gui ? &gui->
process : NULL, display_pipe, &data->runtime_manager,
3897 &data->runtime_process, &data->runtime_display_pipe);
3900 if(runtime_params->layer_name[0] !=
'\0')
3908 .runtime_params = runtime_params,
3910 .manager = data->runtime_manager,
3911 .process_state = data->runtime_process,
3912 .display_pipe = data->runtime_display_pipe,
3915 .use_opencl = use_opencl,
3925 const gint64 process_t0 = g_get_monotonic_time();
3954 gboolean fallback = (runtime_params->
layer_name[0] ==
'\0');
3965 if(!fallback) fallback = !_update_runtime_state(&runtime_request, &source);
3971 const gint64 prologue_end = g_get_monotonic_time();
3975 const gboolean reuse_device_buffers = realtime;
3978 int source_width = source.
width;
3979 int source_height = source.
height;
3980 const float *source_pixels = source.
pixels;
3984 goto process_cl_fallback;
3999 const gboolean allow_partial = realtime && g_valid && g_devout && g_hash && g_roi;
4005 if(realtime && pstate && !allow_partial)
4007 "[drawlayer] partial gate declined: valid=%d devout=%d hash=%d roi=%d "
4008 "(cache_on_ram=%d bypass=%d)\n",
4009 g_valid, g_devout, g_hash, g_roi,
piece->cache_output_on_ram ? 1 : 0,
4018 .layer_pixels = source_pixels,
4019 .source_entry = source_entry,
4020 .source_w = source_width,
4021 .source_h = source_height,
4023 .target_roi = &target_roi,
4024 .source_roi = &source_roi,
4025 .use_preview_bg = preview_bg.
enabled,
4026 .preview_bg = preview_bg.
value,
4027 .realtime_reuse = reuse_device_buffers,
4028 .allow_partial = allow_partial,
4034 if(ok && realtime && !preview_bg.
enabled && layer_hash != 0)
4056 "[drawlayer] process_cl prologue=%.2f ms composite+epilogue=%.2f ms total=%.2f ms ok=%d\n",
4057 (prologue_end - process_t0) / 1000.0,
4058 (g_get_monotonic_time() - prologue_end) / 1000.0,
4059 (g_get_monotonic_time() - process_t0) / 1000.0, ok ? 1 : 0);
4067 (g_get_monotonic_time() - process_t0) / 1000.0);
4078 const void *
const ivoid,
void *
const ovoid)
4102 const float *input = (
const float *)ivoid;
4103 float *output = (
float *)
ovoid;
4104 const size_t pixels = (size_t)roi_out->
width * roi_out->
height;
4105 const gint64 process_t0 = g_get_monotonic_time();
4112 gboolean fallback = (runtime_params->
layer_name[0] ==
'\0');
4116 if(!fallback) fallback = !_update_runtime_state(&runtime_request, &source);
4119 const float *layer_pixels = source.
pixels;
4123 float *layerbuf = NULL;
4126 "drawlayer process scratch");
4134 goto fallback_pass_through;
4143 layer_pixels = layerbuf;
4148 (g_get_monotonic_time() - process_t0) / 1000.0);
4163fallback_pass_through:
4166 (g_get_monotonic_time() - process_t0) / 1000.0);
GtkWidget * dt_gui_main_window(void)
struct dt_ui_t * dt_gui_get_ui(void)
GtkWidget * dt_gui_center_widget(void)
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
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
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
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)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
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)))
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 a redraw of the centre view.
void dt_control_mouse_is_painting(gboolean state)
#define dt_control_set_cursor_visible(visible)
struct dt_control_t * dt_control_get_global(void)
gboolean dt_drawlayer_raw_placement_for_frame(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *const frame, dt_drawlayer_raw_placement_t *placement)
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)
gboolean dt_drawlayer_layer_to_widget_coords(dt_iop_module_t *self, const float x, const float y, float *wx, float *wy)
Shared coordinate transforms and geometry computations for drawlayer.
struct dt_develop_t * dt_dev_get_global(void)
struct dt_gui_gtk_t * dt_gui_get_global(void)
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
dt_dev_image_geometry_t dt_dev_geometry_snapshot(const dt_develop_t *dev)
gboolean dt_dev_add_history_item_ext(dt_develop_t *dev, struct dt_iop_module_t *module, gboolean enable, gboolean force_new_item) REQUIRES(dev -> history_mutex)
Append or update a history item for a module.
uint64_t dt_dev_history_compute_hash(dt_develop_t *dev) REQUIRES_SHARED(dev -> history_mutex)
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.
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_update_history_all(dev)
float dt_dev_viewport_center_y(const dt_develop_t *dev)
float dt_dev_viewport_center_x(const dt_develop_t *dev)
float dt_dev_viewport_scaling(const dt_develop_t *dev)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_output_profile_info(const struct dt_dev_pixelpipe_t *pipe)
__DT_CLONE_TARGETS__ dt_iop_order_iccprofile_info_t * dt_ioppr_get_iop_work_profile_info(struct dt_iop_module_t *module, GList *iop_list)
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)
GtkWidget * geometry
its size, under the preview
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)
static gboolean _brush_paints_color(void)
Does the brush currently lay down the chosen colour?
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.
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)
void dt_drawlayer_invalidate_brush_settings_cache(dt_iop_drawlayer_gui_data_t *g)
static gboolean _background_layer_job_done_idle(gpointer user_data)
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)
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.
void dt_drawlayer_sanitize_params(dt_iop_module_t *self, dt_iop_drawlayer_params_t *params)
void dt_drawlayer_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.
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)
static gboolean _drawlayer_acquire_layer_image(const int devid, dt_pixel_cache_entry_t *resolved_entry, const gboolean realtime_reuse, 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)
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 drawlayer_runtime_request_t _process_bind_runtime(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, dt_iop_drawlayer_gui_data_t *gui, const gboolean have_gui, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const gboolean use_opencl)
Everything process() and process_cl() must do identically before they diverge.
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)
void dt_drawlayer_begin_gui_stroke_capture(dt_iop_module_t *self, const dt_drawlayer_paint_raw_input_t *first_input)
static gboolean _drawlayer_acquire_source_image(const int devid, const float *layer_pixels, dt_pixel_cache_entry_t *resolved_entry, const gboolean realtime_reuse, const int source_w, const int source_h, dt_drawlayer_process_state_t *process, drawlayer_cl_image_handle_t *source)
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 void _save_layer_clicked(GtkButton *button, gpointer user_data)
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 int _blend_layer_over_input_cl(const drawlayer_blend_cl_request_t *const req)
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)
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)
int64_t dt_drawlayer_sidecar_timestamp_from_path(const char *path)
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)
gboolean dt_drawlayer_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 gboolean _color_picker_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
void gui_cleanup(dt_iop_module_t *self)
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)
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).
void dt_drawlayer_retain_base_patch_loaded_ref(dt_iop_drawlayer_gui_data_t *g)
static gboolean _create_new_layer(dt_iop_module_t *self, const char *requested_name)
void dt_drawlayer_refresh_layer_widgets(dt_iop_module_t *self)
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.
static void _build_brush_tab(dt_iop_module_t *self, dt_iop_drawlayer_gui_data_t *g, GtkWidget *brush_tab)
Build the Brush tab: mode, colour, geometry, thickness and texture.
void change_image(dt_iop_module_t *self)
Invalidate module state when active image changes.
static void _build_layer_tab(dt_iop_module_t *self, dt_iop_drawlayer_gui_data_t *g, GtkWidget *layer_tab)
Build the Layer tab: the Background choice, the layer list and its actions.
static void _develop_ui_pipe_finished_callback(gpointer instance, gpointer user_data)
static void _refresh_brush_settings_cache(dt_iop_drawlayer_gui_data_t *g)
Re-resolve the brush from conf into the GUI-side cache.
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)
gboolean dt_drawlayer_layer_name_non_empty(const char *name)
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 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.
gboolean dt_drawlayer_rekey_shared_base_patch(drawlayer_patch_t *patch, const int32_t imgid, const dt_iop_drawlayer_params_t *params)
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)
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 _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 _retain_base_patch_stroke_ref(dt_iop_drawlayer_gui_data_t *g)
static void _delete_layer_clicked(GtkButton *button, gpointer user_data)
static void _build_input_tab(dt_iop_module_t *self, dt_iop_drawlayer_gui_data_t *g, GtkWidget *input_tab)
Build the Input tab: the tablet-mapping grid and its profile combos.
static int dt_pthread_rwlock_wrlock(dt_pthread_rwlock_t *rwlock) ACQUIRE(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
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)
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
void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module)
Release what dt_iop_gui_enter_critical_section() took. Also a no-op headless.
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
@ IOP_FLAGS_SUPPORTS_BLENDING
void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module)
Take the module's GUI lock, serialising access to its dt_iop_gui_data_t.
gboolean dt_mask_scroll_increases(int up)
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
#define IOP_GUI_ALLOC(module)
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.
void dt_drawlayer_conf_remember_display_color(dt_iop_module_t *self, const float display_rgb[3])
Push current display color to history and trigger swatch redraw.
void dt_drawlayer_conf_sync_params_from_gui(dt_iop_module_t *self, const gboolean record_history)
Sync active GUI widget values back into persistent config keys.
float dt_drawlayer_conf_hardness(void)
Derive hardness as complementary value of softness.
drawlayer_pick_source_t dt_drawlayer_conf_pick_source(void)
Read and clamp color picker source selector.
float dt_drawlayer_conf_sprinkle_coarseness(void)
Read and clamp configured sprinkle octave mix (%).
float dt_drawlayer_conf_smoothing(void)
Read and clamp configured smoothing parameter (%).
drawlayer_mapping_profile_t dt_drawlayer_conf_mapping_profile(const char *key)
Read and clamp one mapping-profile enum key.
void dt_drawlayer_conf_ensure_defaults(void)
Ensure all drawlayer GUI config keys exist with sane defaults.
void dt_drawlayer_conf_display_color(float rgb[3])
Read configured display RGB brush color.
float dt_drawlayer_conf_hdr_exposure(void)
Read and clamp HDR picker exposure compensation (EV).
dt_iop_drawlayer_brush_shape_t dt_drawlayer_conf_brush_shape(void)
Read and clamp configured brush shape.
dt_iop_drawlayer_brush_mode_t dt_drawlayer_conf_brush_mode(void)
Read and clamp configured brush blend mode.
float dt_drawlayer_conf_sprinkles(void)
Read and clamp configured sprinkles amount (%).
void dt_drawlayer_conf_load_color_history(dt_iop_drawlayer_gui_data_t *g)
Load persisted color-history stack from config into widgets state.
void dt_drawlayer_conf_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.
float dt_drawlayer_conf_opacity(void)
Read and clamp configured stroke opacity (%).
float dt_drawlayer_conf_size(void)
Read and clamp configured brush size (px).
void dt_drawlayer_conf_sync_color_picker(dt_iop_module_t *self)
Refresh picker widgets from persisted config color.
float dt_drawlayer_conf_flow(void)
Read and clamp configured flow (%).
float dt_drawlayer_conf_distance(void)
Read and clamp configured distance/sampling parameter (%).
void dt_drawlayer_mapping_rows(dt_iop_drawlayer_gui_data_t *g, dt_drawlayer_mapping_row_t rows[DT_DRAWLAYER_MAPPING_ROWS])
float dt_drawlayer_conf_sprinkle_size(void)
Read and clamp configured sprinkle feature size (px).
The brush settings the drawlayer module keeps in the application configuration.
#define DRAWLAYER_CONF_MAP_TILT_SIZE
#define DRAWLAYER_CONF_MAP_PRESSURE_SIZE
#define DRAWLAYER_CONF_ACCEL_PROFILE
#define DRAWLAYER_CONF_MAP_PRESSURE_SOFTNESS
#define DRAWLAYER_CONF_PRESSURE_PROFILE
#define DRAWLAYER_CONF_MAP_TILT_FLOW
#define DRAWLAYER_CONF_MAP_ACCEL_FLOW
#define DRAWLAYER_CONF_MAP_ACCEL_SIZE
#define DRAWLAYER_CONF_MAP_PRESSURE_OPACITY
#define DRAWLAYER_CONF_SIZE
#define DRAWLAYER_CONF_MAP_TILT_SOFTNESS
#define DRAWLAYER_CONF_TILT_PROFILE
#define DRAWLAYER_CONF_MAP_ACCEL_OPACITY
#define DRAWLAYER_CONF_MAP_PRESSURE_FLOW
#define DRAWLAYER_CONF_MAP_TILT_OPACITY
#define DRAWLAYER_CONF_MAP_ACCEL_SOFTNESS
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_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)
void dt_drawlayer_layers_log_errors(GString *errors)
void dt_drawlayer_layers_populate_list(dt_iop_module_t *self)
void dt_drawlayer_layers_reset_stroke_session(dt_iop_drawlayer_gui_data_t *g)
void dt_drawlayer_layers_append_error(GString *errors, const char *message)
The drawlayer's layer store: the layer cache and its sidecar synchronisation.
static const dt_dev_pixelpipe_t * pipe
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t * piece
static const dt_iop_drawlayer_params_t * params
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t int int * layer_height
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t int * layer_width
_lib_location_type_t type
int32_t dt_get_debug_flags(void)
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
dt_masks_form_t * dt_masks_get_visible_form(const dt_develop_t *dev)
Return the currently visible form used by the masks GUI.
The interactive half of the masks subsystem: the editing state (dt_masks_form_gui_t),...
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
void dt_ui_notebook_set_picker_owner(GtkNotebook *notebook, gpointer owner)
Register an opaque owner for a GtkNotebook's page switches, and report every "switch_page" to the hos...
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)
#define __OMP_PARALLEL_FOR__(...)
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
void * dt_dev_pixelpipe_cache_get_pinned_image(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(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Take or release one reference on a cache line. A referenced line is never evicted,...
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_put_pinned_image(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_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(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(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(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
#define DT_DRAWLAYER_MAPPING_ROWS
How many input axes the tablet mapping offers (pressure, tilt, acceleration).
@ 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_GUI_RESYNC
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_AFTER
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SCROLL
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_BEFORE
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_PIPE_FINISHED
@ 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_DRAWLAYER_MAPPING_TARGETS
How many brush properties each axis can drive (size, opacity, flow, hardness).
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ 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)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
static const dt_aligned_pixel_simd_t value
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
gboolean dt_drawlayer_ensure_layer_cache(dt_iop_module_t *self)
const float uint32_t state[4]
unsigned __int64 uint64_t
Everything the GPU layer-over-input blend needs, in one place.
const dt_iop_roi_t * target_roi
drawlayer_process_scratch_t * scratch
const dt_iop_roi_t * source_roi
const float * layer_pixels
dt_drawlayer_process_state_t * process
dt_pixel_cache_entry_t * source_entry
gboolean is_cached_device
What one sidecar directory scan found about a layer.
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 * cl_background_rgba
Objective facts about the image a dev is working on.
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_masks_form_gui_t * form_gui
struct dt_dev_pixelpipe_t * pipe
Fully resolved input dab descriptor.
The brush as the input path needs it, resolved from conf once per change.
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[DT_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.
One input axis: the four properties it can drive, and its response curve.
dt_drawlayer_mapping_cell_t targets[4]
dt_drawlayer_mapping_cell_t profile
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
Where the raw-anchored layer canvas sits in this module's own frame.
dt_drawlayer_runtime_request_t runtime
What the runtime manager is given to reach its caller's state.
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
unsigned int stroke_commit_hash
int64_t sidecar_timestamp
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_iop_module_gui_t * gui
struct dt_develop_t * dev
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
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
dt_iop_color_intent_t intent
Rendering intent, passed to cmsCreateTransform on the lcms2 fallback only. The matrix path ignores it...
dt_colorspaces_color_profile_type_t type
Profile identity, half of the memo key. DT_COLORSPACE_NONE means "unset" and makes every apply functi...
char filename[DT_IOP_COLOR_ICC_LEN]
ICC file name, the other half of the memo key; "" for every built-in. Compared with strcmp,...
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__
typedef double((*spd)(unsigned long int wavelength, double TempK))
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.
gboolean dt_drawlayer_worker_wait_idle(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Wait until worker queue is drained and not busy.
void dt_drawlayer_worker_snapshot_params(dt_drawlayer_worker_t *worker, const dt_iop_drawlayer_params_t *params)
Seed the worker's private params blob for the stroke about to start. GUI thread only.
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_cancel_async_commit(dt_drawlayer_worker_t *rt)
Cancel deferred commit request state if any.
void dt_drawlayer_worker_reset_stroke(dt_drawlayer_worker_t *worker)
Clear preserved stroke runtime/history after commit completed.
Background stroke worker API for drawlayer realtime painting.