Commit 911133c8 authored by johannes hanika's avatar johannes hanika

local laplacian: make roi aware in darkroom mode

this only affects zooming in darkroom mode.
the upper level of the laplacian pyramid are stolen
from the preview pipeline. because they are at a different
resolution, trilinear filtering is done to braid the data
into the new output pyramids.

this can result in some artifacts on very fine geometry
for unlucky ratios between full and preview resolution.
i think it's already a lot better than without though.

the opencl code path is not fixed yet.

i did not benchmark it, but since the full pipeline
actually computes /less/ it should be faster modulo
synchronisation with the preview pipe.
parent da1efc9b
This diff is collapsed.
......@@ -17,6 +17,34 @@
along with darktable. If not, see <http://www.gnu.org/licenses/>.
*/
#include "develop/imageop.h"
// struct bundling all the auxiliary buffers
// required to fill the boundary of a full res pipeline
// with the coarse but complete roi preview pipeline
typedef struct local_laplacian_boundary_t
{
int mode; // 0-regular, 1-preview/collect, 2-full/read
float *pad0; // padded preview buffer, grey levels (allocated via dt_alloc_align)
int wd; // preview width
int ht; // preview height
int pwd; // padded preview width
int pht; // padded preview height
const dt_iop_roi_t *roi; // roi of current view (pointing to pixelpipe roi)
const dt_iop_roi_t *buf; // dimensions of full buffer
float *output[30]; // output pyramid of preview pass (allocated via dt_alloc_align)
int num_levels; // number of levels in preview output pyramid
}
local_laplacian_boundary_t;
void local_laplacian_boundary_free(
local_laplacian_boundary_t *b)
{
dt_free_align(b->pad0);
for(int l=0;l<b->num_levels;l++) dt_free_align(b->output[l]);
memset(b, 0, sizeof(*b));
}
void local_laplacian_internal(
const float *const input, // input buffer in some Labx or yuvx format
float *const out, // output buffer with colour
......@@ -26,7 +54,9 @@ void local_laplacian_internal(
const float shadows, // user param: lift shadows
const float highlights, // user param: compress highlights
const float clarity, // user param: increase clarity/local contrast
const int use_sse2); // switch on sse optimised version, if available
const int use_sse2, // switch on sse optimised version, if available
// the following is just needed for clipped roi with boundary conditions from coarse buffer (can be 0)
local_laplacian_boundary_t *b);
void local_laplacian(
const float *const input, // input buffer in some Labx or yuvx format
......@@ -36,9 +66,10 @@ void local_laplacian(
const float sigma, // user param: separate shadows/midtones/highlights
const float shadows, // user param: lift shadows
const float highlights, // user param: compress highlights
const float clarity) // user param: increase clarity/local contrast
const float clarity, // user param: increase clarity/local contrast
local_laplacian_boundary_t *b) // can be 0
{
local_laplacian_internal(input, out, wd, ht, sigma, shadows, highlights, clarity, 0);
local_laplacian_internal(input, out, wd, ht, sigma, shadows, highlights, clarity, 0, b);
}
size_t local_laplacian_memory_use(const int width, // width of input image
......@@ -58,8 +89,9 @@ void local_laplacian_sse2(
const float sigma, // user param: separate shadows/midtones/highlights
const float shadows, // user param: lift shadows
const float highlights, // user param: compress highlights
const float clarity) // user param: increase clarity/local contrast
const float clarity, // user param: increase clarity/local contrast
local_laplacian_boundary_t *b) // can be 0
{
local_laplacian_internal(input, out, wd, ht, sigma, shadows, highlights, clarity, 1);
local_laplacian_internal(input, out, wd, ht, sigma, shadows, highlights, clarity, 1, b);
}
#endif
Subproject commit afffdab5c7577af933fe30aafa8357177df08df5
Subproject commit 6878b3d5fd2ed321d425a7ad73f8c82be3cd9044
......@@ -82,6 +82,10 @@ typedef struct dt_iop_bilat_gui_data_t
GtkWidget *range;
GtkWidget *detail;
GtkWidget *mode;
local_laplacian_boundary_t ll_boundary;
uint64_t hash;
dt_pthread_mutex_t lock;
}
dt_iop_bilat_gui_data_t;
......@@ -263,6 +267,7 @@ void process_sse2(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, c
// this is called for preview and full pipe separately, each with its own pixelpipe piece.
// get our data struct:
dt_iop_bilat_data_t *d = (dt_iop_bilat_data_t *)piece->data;
dt_iop_bilat_gui_data_t *g = self->gui_data;
// the total scale is composed of scale before input to the pipeline (iscale),
// and the scale of the roi.
const float scale = piece->iscale / roi_in->scale;
......@@ -279,7 +284,47 @@ void process_sse2(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, c
}
else // s_mode_local_laplacian
{
local_laplacian_sse2(i, o, roi_in->width, roi_in->height, d->midtone, d->sigma_s, d->sigma_r, d->detail);
local_laplacian_boundary_t b = {0};
if(self->dev->gui_attached && g && piece->pipe->type == DT_DEV_PIXELPIPE_PREVIEW)
{
b.mode = 1;
}
else if(self->dev->gui_attached && g && piece->pipe->type == DT_DEV_PIXELPIPE_FULL)
{
// full pipeline working on ROI needs boundary conditions from preview pipe
// only do this if roi covers less than 90% of full width
if(MIN(roi_in->width/roi_in->scale / piece->buf_in.width,
roi_in->height/roi_in->scale / piece->buf_in.height) < 0.9)
{
dt_pthread_mutex_lock(&g->lock);
const uint64_t hash = g->hash;
dt_pthread_mutex_unlock(&g->lock);
if(hash != 0 && !dt_dev_sync_pixelpipe_hash(self->dev, piece->pipe, 0, self->priority, &g->lock, &g->hash))
// TODO: remove this debug output at some point:
dt_control_log(_("local laplacian: inconsistent output"));
dt_pthread_mutex_lock(&g->lock);
// grab preview pipe buffers here:
b = g->ll_boundary;
dt_pthread_mutex_unlock(&g->lock);
if(b.wd > 0 && b.ht > 0) b.mode = 2;
}
}
b.roi = roi_in;
b.buf = &piece->buf_in;
local_laplacian_sse2(i, o, roi_in->width, roi_in->height, d->midtone, d->sigma_s, d->sigma_r, d->detail, &b);
// preview pixelpipe stores values.
if(self->dev->gui_attached && g && piece->pipe->type == DT_DEV_PIXELPIPE_PREVIEW)
{
uint64_t hash = dt_dev_hash_plus(self->dev, piece->pipe, 0, self->priority);
dt_pthread_mutex_lock(&g->lock);
// store buffer pointers on gui struct. maybe need to swap/free old ones
local_laplacian_boundary_free(&g->ll_boundary);
g->ll_boundary = b;
g->hash = hash;
dt_pthread_mutex_unlock(&g->lock);
}
}
if(piece->pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(i, o, roi_in->width, roi_in->height);
......@@ -308,7 +353,7 @@ void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const
}
else // s_mode_local_laplacian
{
local_laplacian(i, o, roi_in->width, roi_in->height, d->midtone, d->sigma_s, d->sigma_r, d->detail);
local_laplacian(i, o, roi_in->width, roi_in->height, d->midtone, d->sigma_s, d->sigma_r, d->detail, 0);
}
if(piece->pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(i, o, roi_in->width, roi_in->height);
......@@ -427,6 +472,9 @@ void gui_update(dt_iop_module_t *self)
gtk_widget_set_visible(g->highlights, TRUE);
gtk_widget_set_visible(g->shadows, TRUE);
gtk_widget_set_visible(g->midtone, TRUE);
dt_pthread_mutex_lock(&g->lock);
g->hash = 0;
dt_pthread_mutex_unlock(&g->lock);
}
else
{
......@@ -445,6 +493,9 @@ void gui_init(dt_iop_module_t *self)
// init the slider (more sophisticated layouts are possible with gtk tables and boxes):
self->gui_data = malloc(sizeof(dt_iop_bilat_gui_data_t));
dt_iop_bilat_gui_data_t *g = (dt_iop_bilat_gui_data_t *)self->gui_data;
memset(&g->ll_boundary, 0, sizeof(local_laplacian_boundary_t));
dt_pthread_mutex_init(&g->lock, NULL);
g->hash = 0;
self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_BAUHAUS_SPACE);
g->mode = dt_bauhaus_combobox_new(self);
......@@ -508,6 +559,9 @@ void gui_init(dt_iop_module_t *self)
void gui_cleanup(dt_iop_module_t *self)
{
// nothing else necessary, gtk will clean up the slider.
dt_iop_bilat_gui_data_t *g = (dt_iop_bilat_gui_data_t *)self->gui_data;
local_laplacian_boundary_free(&g->ll_boundary);
dt_pthread_mutex_destroy(&g->lock);
free(self->gui_data);
self->gui_data = NULL;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment