63 .pixels =
calloc((
size_t)
W *
H * 4,
sizeof(
float)),
64 .external_alloc =
TRUE };
66 .pixels =
calloc((
size_t)
W *
H,
sizeof(
float)),
67 .external_alloc =
TRUE };
74 free(
p->patch.pixels);
80 const float opacity,
const float radius,
const float step,
81 const float sprinkles)
83 for(
int i = 0;
i < count;
i++)
86 .
x = 24.0f + step * (float)
i,
91 .sample_spacing = step,
92 .sample_opacity_scale = 1.0f,
95 .sprinkles = sprinkles,
96 .sprinkle_size = 3.0f,
97 .sprinkle_coarseness = 0.5f,
99 .
color = { 0.8f, 0.4f, 0.2f, 1.0f },
110 const float opacity,
const float radius,
const float step)
120 for(
int i = 0;
i < count;
i++)
142 for(
size_t i = 0;
i <
n;
i++)
144 const double d =
fabs((
double)a[
i] - (
double)b[
i]);
150static void _compare_tex(
const int mode,
const float opacity,
const float radius,
const float step,
151 const int count,
const float sprinkles)
179 print_message(
"mode=%d opacity=%.2f r=%.1f step=%.2f n=%d sprinkles=%.2f -> "
180 "max |dpixel|=%.3e max |dmask|=%.3e\n",
195static void _compare(
const int mode,
const float opacity,
const float radius,
const float step,
264 dabs[3].
color[1] = 0.9f;
300 const int count = 32;
345 for(
size_t i = 0;
i < px;
i++) mask[
i] = 0.0f;
350 const int count = 32;
351 const float radius = 64.0f;
352 const int plane = 512;
356 for(
int i = 0;
i < count;
i++)
359 .
x = 160.0f + (float)
i, .y = 256.0f, .radius = radius, .dir_x = 1.0f, .dir_y = 0.0f,
360 .sample_spacing = 1.0f, .sample_opacity_scale = 1.0f, .opacity = 1.0f, .flow = 1.0f,
361 .sprinkles = sprinkles, .sprinkle_size = 3.0f, .sprinkle_coarseness = 0.5f, .hardness = 0.5f,
369 const size_t px = (size_t)plane * plane;
371 float *mask =
calloc(px,
sizeof(
float));
380 .external_alloc =
TRUE };
382 .external_alloc =
TRUE };
393 for(
int i = 0;
i < count;
i++)
413 print_message(
"one heartbeat batch, r=%.0f spacing=1 dabs=%d sprinkles=%.2f: "
414 "per-dab %.3f ms, batch %.3f ms (%.1fx)\n",
Dab-level brush rasterization API for drawlayer.
@ DT_DRAWLAYER_BRUSH_MODE_ERASE
@ DT_DRAWLAYER_BRUSH_MODE_PAINT
@ DT_DRAWLAYER_BRUSH_MODE_BLUR
@ DT_DRAWLAYER_BRUSH_MODE_SMUDGE
@ DT_DRAWLAYER_BRUSH_SHAPE_LINEAR
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
gboolean dt_drawlayer_brush_batch_is_uniform(const dt_drawlayer_brush_dab_t *dabs, const guint count, dt_drawlayer_brush_batch_t *out)
Decide whether a run of dabs can take the batch path, and describe it if so.
gboolean dt_drawlayer_brush_rasterize(const dt_drawlayer_cache_patch_t *sample_patch, dt_drawlayer_cache_patch_t *patch, const float scale, const dt_drawlayer_brush_dab_t *dab, const float sample_opacity_scale, dt_drawlayer_cache_patch_t *stroke_mask, dt_drawlayer_paint_stroke_t *runtime_private)
Public dab rasterization entry point.
gboolean dt_drawlayer_brush_rasterize_batch(const dt_drawlayer_brush_batch_t *batch, dt_drawlayer_cache_patch_t *patch, const float scale, dt_drawlayer_cache_patch_t *stroke_mask, float *const transmittance, float *const noise_scratch, dt_drawlayer_damaged_rect_t *batch_damage)
Rasterize a whole batch in two passes: accumulate transmittance, then composite once.
Patch/cache helpers for drawlayer process and preview buffers.
void dt_drawlayer_paint_runtime_private_destroy(dt_drawlayer_paint_stroke_t **state)
Destroy stroke runtime payload and null pointer.
dt_drawlayer_paint_stroke_t * dt_drawlayer_paint_runtime_private_create(void)
Allocate stroke runtime payload object used by paint+brush internals.
Stroke-level path sampling and runtime-state API for drawlayer.
@ DT_DRAWLAYER_PAINT_STROKE_MIDDLE
@ DT_DRAWLAYER_PAINT_STROKE_FIRST
#define omp_get_max_threads()
const float uint32_t state[4]
A run of dabs that share everything the batch composite needs to be a single step.
Fully resolved input dab descriptor.
Generic float RGBA patch stored either in malloc memory or pixel cache.
Mutable stroke runtime state owned by worker/backend code.
dt_drawlayer_cache_patch_t mask
dt_drawlayer_cache_patch_t patch
typedef double((*spd)(unsigned long int wavelength, double TempK))
static void _plane_free(plane_t *p)
static void test_batch_matches_serial_paint_capped(void **state)
The cap binds mid-batch: opacity well below 1 with many overlapping dabs.
static void _run_serial(plane_t *p, const dt_drawlayer_brush_dab_t *dabs, const int count)
Run the reference path: one dt_drawlayer_brush_rasterize per dab, in order.
static void _compare_tex(const int mode, const float opacity, const float radius, const float step, const int count, const float sprinkles)
static void test_batch_is_thread_count_independent(void **state)
The batch result must not depend on the thread count.
static void _build_dabs(dt_drawlayer_brush_dab_t *dabs, const int count, const int mode, const float opacity, const float radius, const float step)
static void test_report_batch_speedup(void **state)
static void test_batch_matches_serial_erase(void **state)
static void _clear_mask(float *const mask, const size_t px)
Time both paths on the shipped regime, so the speedup is measured and not derived.
static void _build_dabs_tex(dt_drawlayer_brush_dab_t *dabs, const int count, const int mode, const float opacity, const float radius, const float step, const float sprinkles)
A short stroke of overlapping dabs, uniform in everything the gate tests.
static void _compare(const int mode, const float opacity, const float radius, const float step, const int count)
static double _max_abs_diff(const float *a, const float *b, const size_t n)
static void test_batch_matches_serial_sprinkles(void **state)
Texture on: the batch shares ONE sprinkle field across every dab.
static void _plane_init(plane_t *p)
static void test_batch_matches_serial_paint_dense(void **state)
Heavy overlap, the shipped regime: spacing far below the diameter.
static void _run_batch(plane_t *p, const dt_drawlayer_brush_dab_t *dabs, const int count)
static void test_batch_matches_serial_paint_sparse(void **state)
Sparse dabs, barely overlapping.
static void _report_speedup(const float sprinkles)
static void test_gate_refuses_non_uniform(void **state)
The gate must refuse everything the closed form is not derived for.