app: in gimppaintcore-loops, add [Temp]CompBuffer algorithm helper-classes

In gimppaintcore-loops, add a CompBuffer algorithm helper-class,
which provides access to the output buffer used for compositing,
to be used by the DO_LAYER_BLEND algorithm instead of the
destination buffer.

CompVuffer itself doesn't provide the storage for the buffer; this
is rather the responsibility of the algorithms that use it.  The
TempCompBuffer algorithm helper-class provides temporary storage
for the compositing buffer, and can be used by algorithms that need
a temporary buffer.
This commit is contained in:
Ell 2019-02-16 08:56:11 -05:00
parent b717ead1ab
commit 858f30a609
1 changed files with 156 additions and 12 deletions

View File

@ -102,7 +102,9 @@ enum
ALGORITHM_STIPPLE = 1u << 29,
ALGORITHM_COMP_MASK = 1u << 28,
ALGORITHM_TEMP_COMP_MASK = 1u << 27,
ALGORITHM_MASK_BUFFER_ITERATOR = 1u << 26
ALGORITHM_COMP_BUFFER = 1u << 26,
ALGORITHM_TEMP_COMP_BUFFER = 1u << 25,
ALGORITHM_MASK_BUFFER_ITERATOR = 1u << 24
};
@ -813,6 +815,130 @@ static BasicDispatch<
> dispatch_temp_comp_mask;
/* CompBuffer, dispatch_comp_buffer(), has_comp_buffer(), comp_buffer_data():
*
* An algorithm helper class, providing access to the output buffer used for
* compositing. When this class is part of the hierarchy, 'DoLayerBlend' uses
* this buffer as the output buffer, instead of the input parameters'
* 'dest_buffer'. Algorithms that use the compositing buffer should specify
* 'dispatch_comp_buffer()' as a dependency, and access 'CompBuffer' members
* through their base type/subobject.
*
* Note that 'CompBuffer' only provides *access* to the compositing buffer, but
* doesn't provide its actual *storage*. This is the responsibility of the
* algorithms that use 'CompBuffer'. Algorithms that need temporary storage
* for the compositing buffer can use 'TempCompBuffer'.
*
* The 'has_comp_buffer()' constexpr function determines if a given algorithm
* hierarchy uses the compositing buffer.
*
* The 'comp_buffer_data()' function returns a pointer to the compositing
* buffer data for the current row if the hierarchy uses the compositing
* buffer, or NULL otherwise.
*/
template <class Base>
struct CompBuffer : Base
{
/* Component type of the compositing buffer. */
using comp_buffer_type = gfloat;
static constexpr guint filter = Base::filter | ALGORITHM_COMP_BUFFER;
using Base::Base;
template <class Derived>
struct State : Base::template State<Derived>
{
/* Pointer to the compositing buffer data for the current row. */
comp_buffer_type *comp_buffer_data;
};
};
static BasicDispatch<CompBuffer, ALGORITHM_COMP_BUFFER> dispatch_comp_buffer;
template <class Base>
static constexpr gboolean
has_comp_buffer (const CompBuffer<Base> *algorithm)
{
return TRUE;
}
static constexpr gboolean
has_comp_buffer (const AlgorithmBase *algorithm)
{
return FALSE;
}
template <class Base,
class State>
static gfloat *
comp_buffer_data (const CompBuffer<Base> *algorithm,
State *state)
{
return state->comp_buffer_data;
}
template <class State>
static gfloat *
comp_buffer_data (const AlgorithmBase *algorithm,
State *state)
{
return NULL;
}
/* TempCompBuffer, dispatch_temp_comp_buffer():
*
* An algorithm helper class, providing temporary storage for the compositing
* buffer. Algorithms that need a temporary compositing buffer should specify
* 'dispatch_temp_comp_buffer()' as a dependency, which itself includes
* 'dispatch_comp_buffer()' as a dependency.
*/
template <class Base>
struct TempCompBuffer : Base
{
static constexpr guint filter = Base::filter | ALGORITHM_TEMP_COMP_BUFFER;
using Base::Base;
template <class Derived>
using State = typename Base::template State<Derived>;
template <class Derived>
void
init_step (const GimpPaintCoreLoopsParams *params,
State<Derived> *state,
GeglBufferIterator *iter,
const GeglRectangle *roi,
const GeglRectangle *area,
const GeglRectangle *rect) const
{
Base::init_step (params, state, iter, roi, area, rect);
state->comp_buffer_data = gegl_scratch_new (gfloat, 4 * rect->width);
}
template <class Derived>
void
finalize_step (const GimpPaintCoreLoopsParams *params,
State<Derived> *state) const
{
gegl_scratch_free (state->comp_buffer_data);
Base::finalize_step (params, state);
}
};
static BasicDispatch<
TempCompBuffer,
ALGORITHM_TEMP_COMP_BUFFER,
decltype (dispatch_comp_buffer)
> dispatch_temp_comp_buffer;
/* MaskBufferIterator, mask_buffer_iterator_dispatch(),
* has_mask_buffer_iterator():
*
@ -1783,17 +1909,20 @@ struct DoLayerBlend : Base
const GeglRectangle *roi,
const GeglRectangle *area) const
{
state->iterator_base = gegl_buffer_iterator_add (iter, params->dest_buffer,
state->iterator_base = gegl_buffer_iterator_add (iter, params->src_buffer,
area, 0, iterator_format,
GEGL_ACCESS_WRITE,
GEGL_ACCESS_READ,
GEGL_ABYSS_NONE);
gegl_buffer_iterator_add (iter, params->src_buffer, area, 0,
iterator_format,
GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
if (! has_comp_buffer ((const Derived *) this))
{
gegl_buffer_iterator_add (iter, params->dest_buffer, area, 0,
iterator_format,
GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
}
/* initialize the base class *after* initializing the iterator, to make
* sure that dest_buffer is the primary buffer of the iterator, if no
* sure that src_buffer is the primary buffer of the iterator, if no
* subclass added an iterator first.
*/
Base::init (params, state, iter, roi, area);
@ -1810,8 +1939,7 @@ struct DoLayerBlend : Base
{
Base::init_step (params, state, iter, roi, area, rect);
state->out_pixel = (gfloat *) iter->items[state->iterator_base + 0].data;
state->in_pixel = (gfloat *) iter->items[state->iterator_base + 1].data;
state->in_pixel = (gfloat *) iter->items[state->iterator_base + 0].data;
state->paint_pixel = this->paint_data +
(rect->y - roi->y) * this->paint_stride +
@ -1823,6 +1951,9 @@ struct DoLayerBlend : Base
(gfloat *) iter->items[mask_buffer_iterator (this, state)].data;
}
if (! has_comp_buffer ((const Derived *) this))
state->out_pixel = (gfloat *) iter->items[state->iterator_base + 1].data;
state->process_roi.x = rect->x;
state->process_roi.width = rect->width;
state->process_roi.height = 1;
@ -1841,6 +1972,7 @@ struct DoLayerBlend : Base
Base::process_row (params, state, iter, roi, area, rect, y);
gfloat *mask_pixel;
gfloat *out_pixel;
if (has_comp_mask (this))
mask_pixel = comp_mask_data (this, state);
@ -1849,22 +1981,34 @@ struct DoLayerBlend : Base
else
mask_pixel = NULL;
if (! has_comp_buffer ((const Derived *) this))
{
out_pixel = state->out_pixel;
}
else
{
out_pixel = comp_buffer_data (
(const Derived *) this,
(typename Derived::template State<Derived> *) state);
}
state->process_roi.y = y;
layer_mode.function ((GeglOperation*) &layer_mode,
state->in_pixel,
state->paint_pixel,
mask_pixel,
state->out_pixel,
out_pixel,
rect->width,
&state->process_roi,
0);
state->in_pixel += rect->width * 4;
state->out_pixel += rect->width * 4;
state->paint_pixel += this->paint_stride;
if (! has_comp_mask (this) && has_mask_buffer_iterator (this))
state->mask_pixel += rect->width;
state->paint_pixel += this->paint_stride;
if (! has_comp_buffer ((const Derived *) this))
state->out_pixel += rect->width * 4;
}
};