/* GIMP - The GNU Image Manipulation Program * Copyright (C) 2013 Daniel Sabo * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include extern "C" { #include "paint-types.h" #include "operations/layer-modes/gimp-layer-modes.h" #include "core/gimptempbuf.h" #include "operations/gimpoperationmaskcomponents.h" #include "operations/layer-modes/gimpoperationlayermode.h" #include "gimppaintcore-loops.h" } /* extern "C" */ #define PIXELS_PER_THREAD \ (/* each thread costs as much as */ 64.0 * 64.0 /* pixels */) /* In order to avoid iterating over the same region of the same buffers * multiple times, when calling more than one of the paint-core loop functions * (hereafter referred to as "algorithms") in succession, we provide a single * function, gimp_paint_core_loops_process(), which can be used to perform * multiple algorithms in a row. This function takes a pointer to a * GimpPaintCoreLoopsParams structure, providing the parameters for the * algorithms, and a GimpPaintCoreLoopsAlgorithm bitset, which specifies the * set of algorithms to run; currently, the algorithms are always run in a * fixed order. For convenience, we provide public functions for the * individual algorithms, but they're merely wrappers around * gimp_paint_core_loops_process(). * * We use some C++ magic to statically generate specialized versions of * gimp_paint_core_loops_process() for all possible combinations of algorithms, * and, where relevant, formats and input parameters, and to dispatch to the * correct version at runtime. * * To achieve this, each algorithm provides two components: * * - The algorithm class template, which implements the algorithm, following * a common interface. See the AlgorithmBase class for a description of * the interface. Each algorithm class takes its base class as a template * parameter, which allows us to construct a class hierarchy corresponding * to a specific set of algorithms. Some classes in the hierarchy are not * algorithms themselves, but are rather helpers, which provide some * functionality to the algorithms further down the hierarchy, such as * access to specific buffers. * * - A dispatch function, which takes the input parameters, the requested set * of algorithms, the (type of) the current algorithm hierarchy, and a * visitor object. The function calls the visitor with a (potentially) * modified hierarchy, depending on the input. Ihe dispatch function for * an algorithm checks if the requested set of algorithms contains a * certain algorithm, adds the said algorithm to the hierarchy accordingly, * and calls the visitor with the new hierarchy. See the AlgorithmDispatch * class, which provides a dispatch-function implementation which * algorithms can use instead of providing their own dispatch function. * * Helper classes in the hierarchy may also provide dispatch functions, * which likewise modify the hierarchy based on the input parameters. For * example, the dispatch_paint_mask() function adds a certain PaintMask * specialization to the hierarchy, depending on the format of the paint * mask buffer; this can be used to specialize algorithms based on the mask * format; an algorithm that depends on the paint mask may dispatch through * this function, before modifying the hierarchy itself. * * The dispatch() function is used to construct an algorithm hierarchy by * dispatching through a list of functions. gimp_paint_core_loops_process() * calls dispatch() with the full list of algorithm dispatch functions, * receiving in return the algorithm hierarchy matching the input. It then * uses the algorithm interface to perform the actual processing. */ enum { ALGORITHM_PAINT_BUF = 1u << 31, ALGORITHM_PAINT_MASK = 1u << 30, ALGORITHM_STIPPLE = 1u << 29, ALGORITHM_COMP_MASK = 1u << 28, ALGORITHM_TEMP_COMP_MASK = 1u << 27, ALGORITHM_COMP_BUFFER = 1u << 26, ALGORITHM_TEMP_COMP_BUFFER = 1u << 25, ALGORITHM_CANVAS_BUFFER_ITERATOR = 1u << 24, ALGORITHM_MASK_BUFFER_ITERATOR = 1u << 23 }; template struct identity { using type = T; }; /* dispatch(): * * Takes a list of dispatch function objects, and calls each of them, in order, * with the same 'params' and 'algorithms' parameters, passing 'algorithm' as * the input hierarchy to the first dispatch function, and passing the output * hierarchy of the previous dispatch function as the input hierarchy for the * next dispatch function. Calls 'visitor' with the output hierarchy of the * last dispatch function. * * Each algorithm hierarchy should provide a 'filter' static data member, and * each dispatch function object should provide a 'mask' static data member. * If the bitwise-AND of the current hierarchy's 'filter' member and the * current dispatch function's 'mask' member is equal to 'mask', the dispatch * function is skipped. This can be used to make sure that a class appears * only once in the hierarchy, even if its dispatch function is used multiple * times, or to prevent an algorithm from being dispatched, if it cannot be * used together with another algorithm. */ template static inline void dispatch (Visitor visitor, const GimpPaintCoreLoopsParams *params, GimpPaintCoreLoopsAlgorithm algorithms, identity algorithm) { visitor (algorithm); } template struct dispatch_impl { template static void apply (Visitor visitor, const GimpPaintCoreLoopsParams *params, GimpPaintCoreLoopsAlgorithm algorithms, identity algorithm, Dispatch disp, DispatchRest... disp_rest) { disp ( [&] (auto algorithm) { dispatch (visitor, params, algorithms, algorithm, disp_rest...); }, params, algorithms, algorithm); } }; template struct dispatch_impl { template static void apply (Visitor visitor, const GimpPaintCoreLoopsParams *params, GimpPaintCoreLoopsAlgorithm algorithms, identity algorithm, Dispatch disp, DispatchRest... disp_rest) { dispatch (visitor, params, algorithms, algorithm, disp_rest...); } }; template static inline void dispatch (Visitor visitor, const GimpPaintCoreLoopsParams *params, GimpPaintCoreLoopsAlgorithm algorithms, identity algorithm, Dispatch disp, DispatchRest... disp_rest) { dispatch_impl::apply ( visitor, params, algorithms, algorithm, disp, disp_rest...); } /* value_to_float(): * * Converts a component value to float. */ static inline gfloat value_to_float (guint8 value) { return value / 255.0f; } static inline gfloat value_to_float (gfloat value) { return value; } template static inline gfloat value_to_float (T value) = delete; /* AlgorithmBase: * * The base class of the algorithm hierarchy. */ struct AlgorithmBase { /* Used to filter-out dispatch functions; see the description of dispatch(). * Algorithms that redefine 'filter' should bitwise-OR their filter with that * of their base class. */ static constexpr guint filter = 0; /* The current maximal number of iterators used by the hierarchy. Algorithms * should redefine 'max_n_iterators' by adding the maximal number of * iterators they use to this value. */ static constexpr gint max_n_iterators = 0; /* Non-static data members should be initialized in the constructor, and * should not be further modified. */ explicit AlgorithmBase (const GimpPaintCoreLoopsParams *params) { } /* Algorithms should store their dynamic state in the 'State' member class * template. This template will be instantiated with the most-derived type * of the hierarchy, which allows an algorithm to depend on the properties of * its descendants. Algorithms that provide their own 'State' class should * derive it from the 'State' class of their base class, passing 'Derived' as * the template argument. * * Algorithms can be run in parallel on multiple threads. In this case, each * thread uses its own 'State' object, while the algorithm object itself is * either shared, or is a copy of a shared algorithm object. Either way, the * algorithm object itself is immutable, while the state object is mutable. */ template struct State { }; /* The 'init()' function is called once per state object before processing * starts, and should initialize the state object, and, if necessary, the * iterator. * * 'params' is the same parameter struct passed to the constructor. 'state' * is the state object. 'iter' is the iterator; each distinct state object * uses a distinct iterator; if the algorithm hierarchy doesn't use any * iterator, 'iter' may be NULL. 'roi' is the full region to be processed. * 'area' is the subregion to be processed by the current state object. * * An algorithm that overrides this function should call the 'init()' * function of its base class first, using the same arguments. */ template void init (const GimpPaintCoreLoopsParams *params, State *state, GeglBufferIterator *iter, const GeglRectangle *roi, const GeglRectangle *area) const { } /* The 'init_step()' function is called once after each * 'gegl_buffer_iterator_next()' call, and should perform any necessary * initialization required before processing the current chunk. * * The parameters are the same as for 'init()', with the addition of 'rect', * which is the area of the current chunk. * * An algorithm that overrides this function should call the 'init_step()' * function of its base class first, using the same arguments. */ template void init_step (const GimpPaintCoreLoopsParams *params, State *state, GeglBufferIterator *iter, const GeglRectangle *roi, const GeglRectangle *area, const GeglRectangle *rect) const { } /* The 'process_row()' function is called for each row in the current chunk, * and should perform the actual processing. * * The parameters are the same as for 'init_step()', with the addition of * 'y', which is the current row. * * An algorithm that overrides this function should call the 'process_row()' * function of its base class first, using the same arguments. */ template void process_row (const GimpPaintCoreLoopsParams *params, State *state, GeglBufferIterator *iter, const GeglRectangle *roi, const GeglRectangle *area, const GeglRectangle *rect, gint y) const { } /* The 'finalize_step()' function is called once per chunk after its * processing is done, and should finalize any chunk-specific resources of * the state object. * * 'params' is the same parameter struct passed to the constructor. 'state' * is the state object. * * An algorithm that overrides this function should call the * 'finalize_step()' function of its base class after performing its own * finalization, using the same arguments. */ template void finalize_step (const GimpPaintCoreLoopsParams *params, State *state) const { } /* The 'finalize()' function is called once per state object after processing * is done, and should finalize the state object. * * 'params' is the same parameter struct passed to the constructor. 'state' * is the state object. * * An algorithm that overrides this function should call the 'finalize()' * function of its base class after performing its own finalization, using * the same arguments. */ template void finalize (const GimpPaintCoreLoopsParams *params, State *state) const { } }; /* BasicDispatch: * * A class template implementing a simple dispatch function object, which adds * an algorithm to the hierarchy unconditionally. 'AlgorithmTemplate' is the * alogithm class template (usually a helper class, rather than an actual * algorithm), 'Mask' is the dispatch function mask, as described in * 'dispatch()', and 'Dependencies' is a list of (types of) dispatch functions * the algorithm depends on. * * Before adding the algorithm to the hierarchy, the hierarchy is augmented by * dispatching through the list of dependencies, in order. */ template