In gimp_operation_buffer_source_validate_process(), align the ROI
to the tile grid *before* intersecting it with the validate-
handler's dirty region. This is necessary since, even though
subsequent operations will only read data within the ROI, the
entire tiles containing the ROI will be fetched, resulting in an
area potentially greater than the ROI. We need to validate this
area in advance, or else it will be validated as part of the
subsequent operations, which can lead into the same deadlock we're
trying to prevent.
Fix a CRITICAL when calling gimp_layer_mode_get_format() with an
AUTO composite space and a NULL preferred format, which is valid:
it means the layer mode is composite-space agnostic (as DISSOLVE
is), and that there's no preferred format.
A NULL preferred format can occur during
gimp_operation_layer_mode_prepare() if the layer's mode node is not
yet attached anything through its "input" or "aux" pads, which is
the case during the call to gimp_layer_update_mode_node() while
constructing the layer's node in gimp_layer_get_node().
Our composite modes don't correspond directly to the Porter-Duff
operators after which they're named, and these names aren't too
descriptive anyway.
Rename the composite modes as follows:
Source Over => Union
Source Atop => Clip to Backdrop
Destination Atop => Clip to Layer
Source In => Intersection
Update relevant code, including UI text, enumerator names, function
names, and action names.
PDB function gimp_edit_blend() was based on "gimp:shapeburst" operation
whereas the rest of GIMP (in particular, the Blend tool) used
"gegl:distance-transform" which is much faster.
Setting the operation to "manhattan" metric ensures that it still
renders the same way as in 2.8 while being a lot faster.
There was still a problem regarding as how it renders differently from
the Blend tool, but it turns out that the Blend tool is the one
rendering differently from how it used to in 2.8. We should discuss
adding the "metric" property in the tool options.
This operation is currently broken on multi-thread. So disable
multi-threading, at least temporarily (if not forever since apparently
we can get similar output with "gegl:distance-transform", but much
faster and nicer). See bug 781621.
It seems gegl_buffer_sample() crashes with the first parameter being
NULL so let's just test its value first. This will output a huge
quantity of CRITICALs in this edge case but that's much better than a
crash. :-)
See also bug 793371 where this bug is being processed.
When checking the Cage Transform operation code, I saw some ifdef meant
to be switched to when bug 645810 is fixed. It also says in a comment:
> /* When Gegl bug #645810 will be solved,
> this should be a good optimisation */
Checking said bug, it appears it has been fixed since 2012!
I also fixed a bit the parameters in gegl_buffer_sample() call since it
seems the function signature has changed quite a bit.
which is just a #define to g_assert for now, but can now easily be
turned into something that does some nicer debugging using our new
stack trace infrastructure. This commit also reverts all constructed()
functions to use assert again.
The four remaining "classic" color tools (Brightness-Contrast, Curves,
Levels and Threshold) are in fact just special UIs for otherwise
completely normal filter ops.
Add normal filter actions for them and invoke them like all
other filters, which makes them show up in the filter history
automatically.
The only small hack needed is to special case them in
gimp_gegl_procedure_execute_async() so the right tools are created
instead of the default GimpOperationTool. Also, blacklist the
automatically generated tools actions from action search and the
shortcut editor.
... removed by commit 0f9da165e0, and
improved by this commit.
Our foo-light modes aren't really prepared to handle out-of-range
input. Make sure that in-range input doesn't result in out-of-
range output.
Add a safe_div() function to gimpoperationlayermode-blend.c, and
use it in the relevant blend funcs, instead of plain division.
This function clamps the quotient to some reasonable range, to
avoid infinities, and maps epsilon/... to 0, to avoid NaN. The
latter part results in similar qualitative results to the
corresponding legacy modes, when calculating 0/0.
...and present linear RGB Histograms
This is step one: implement the feature at all (without new defaults
or proper GUI, cough).
Add boolean "linear" properties to GimpOperationPointFilter,
GimpCurvesConfig and GimpLevelsConfig.
In the filter, simply set the input/output formats to linear in
prepare().
In the curves and levels tools, add "Linear" toggles from hell,
like in the histogram dockable, and make sure things work right
wrt changing and resetting the property, switching from levels
to curves, and picking colors.
The result currently changes when switching a non-nop curves/levels
between perceptual and linear, because adjusting the parameters
between the spaces is not implemented yet.
In legacy layer modes that may produce out-of-range output given
in-range input, clamp the result after blending and before
compositing, instead of after compositing, to avoid producing
different results than 2.8 in certain cases.
Add "clamp-input" (which clamps the input values to [0..1])
and "clamp-output" (which clips the final result to [0..1]),
properties, parameters and GUI to:
- GimpLevelsConfig
- GimpOperationLevels
- The levels tool dialog
- The gimp_drawable_levels() PDB API
The old deprecated gimp_levels() PDB API now sets both clamping
options to TRUE which restores the 2.8 behavior.
Also reorder some stuff in GimpLevelsConfig and elsewhere so the
levels parameters are always in the same order.
Override get_invalidated_by_change() with the same logic as
get_required_for_output(), to avoid unnecessary invalidation.
Avoid format conversion when input and aux have the same format.
Add pass-through fast path when the ROI is completely inside/
outside the cropped rectangle.
Use bulk memcpy(), instead of per-pixel test-and-copy, in
process().
This avoids unnecessarily processing regions of the input and/or
aux nodes that will get cropped out. In particular, this avoids
processing cropped-out regions when using the filter tool in split-
view mode.
Keep multi-threading disable on the cage transform operation. It is now
fixed but is a lot much slower than when single-threaded, making it
painful to use on bigger images.
So let's reenable later if we can improve this. See bug 787663.
Use gimp:buffer-source-validate, introduced in the previous commit,
for the source node of GimpDrawables. This avoids threading issues
with layer groups, or any other drawables that may use a validating
buffer, by making sure the buffer is validated before any
succeeding operations, and hence the associated graph is processed
on the same thread as the parent composition.
Restore multithreaded processing in GimpOperationLayerMode.
gimp:buffer-source-validate is a drop-in replacement for
gegl:buffer-source, however, if the attached buffer has a
validating tile-handler, it makes sure the required region is
validated during process(). This avoids a situation in which
validation happens in different worker threads at the same time
during the processing of a succeeding operation; since validation
is protected by the buffer's tile-storage mutex, this can result in
either a deadlock (currently), or an effective fallback to single-
threaded processing.
Update the dprod production of generated enum files to include
abbreviated value descriptions, as per the previous commits.
Add a comment for translators above the abbreviated descriptions,
specifying the full description they abbreviate.
Temporarily disable multithreading for GimpOperationLayerMode, to
avoid the deadlock. The environment variable
GIMP_MULTITHREADED_COMPOSITING can be set to reenable it, for the
sake of debugging.
It was accidentally made applicable to layers by commit
7d345071c7. Only the non-legacy
color-erase mode shoule be applicable to layers (since 2.8 didn't
allow it as a layer mode), while the legacy mode is only available
for painting, and in the fade dialog.
When rendering a gradient with a repeat mode of NONE, don't sample
the gradient at 0.0 and 1.0, for pixels that lie to the left and to
the right of the gradient, respectively. Instead, use the left
color of the leftmost segment directly, and, likewise, the right
color of the rightmost segment. This always gives us the right
color for such pixels, even when there are gradient stops, that may
use different colors, at 0.0 and 1.0,
Remember the gradient segment at which the most-recent sample lies,
and pass it to gimp_gradient_get_color_at() as a seed for segement
lookup on the next sample. This improves the performance
marginally.
Pass through mode uses the same compositing logic as REPLACE mode,
however, it's a special case of REPLACE, where the layer is already
composited against the backdrop. This allows us to take a few
shortcuts that aren't generally applicable to REPLACE mode.
Add a dedicated op class for pass through mode, derived from the
REPLACE mode op, implementing these shortcuts.
this commit changes just those which make no difference to
functionality: property and object member defaults that get overridden
anyway, return values of g_return_val_if_fail(), some other stuff.
Commit 3635cf04ab moved the special
handling of bottom-layer compositing to GimpOperationLayerMode.
This required giving the op more control over the process()
function of its subclasses. As a temporary workaround, the commit
bypassed the subclasses entirely, using "gimp:layer-mode" for all
modes. This is the reckoning :)
Add a process() virtual function to GimpOperationLayerMode, which
its subclasses should override instead of
GeglOperationPointComposer3's process() functions. Reinstate the
subclasses (by returning the correct op in
gimp_layer_mode_get_oepration()), and have them override this
function.
Improve the way gimp_operation_layer_mode_process() dispatches to
the actual process function, to slightly lower its overhead and
fix some thread-safety issues.
Remove the "function" field of the layer-mode info array, and have
gimp_layer_mode_get_function() return the
GimpOperationLayerMode::process() function of the corresponding
op's class (caching the result, to keep it cheap.) This reduces
redundancy, allows us to make the ops' process() functions private,
and simplifies SSE dispatching (only used by NORMAL mode,
currently.)
Move the blend and composite functions of the non-specialized
layer modes to gimpoperationlayermode-{blend,composite}.[hc],
respectively, to improve code organization.
Move the SSE2 composite functions to a separate file, so that they
can be built as part of libapplayermodes_sse2, allowing
libapplayermodes to be built without SSE2 compiler flags. This
allows building GIMP with SSE acceleration enabled, while running
the resulting binary on a target with no SSE accelration.
Add a "blend_function" field to the layer-mode info array, and use
it to specify the blend function for the non-specialized modes.
This replaces the separate switch() statement that we used
previously.
Remove the "affected_region" field of the layer-mode info array.
We don't need it anymore, since we can go back to using
GimpOperationLayerMode's virtual get_affected_region() function.
Last but not least, a bunch of code cleanups and consistency
adjustments.
GimpFilter's is_last_node field only reflects the item's position
within the parent stack. When a layer is contained in a pass-
through group, it can be the last layer of the group, while not
being the last layer in the graph as a whole (paticularly, if
there are visible layers below the group). In fact, when we have
nested pass-through groups, whether or not a layer is the last
node depends on which group we're considering as the root (since
we exclude the backdrop from the group's projection, resulting in
different graphs for different groups).
Instead of rolling our own graph traversal, just move the relevant
logic to GimpOperationLayerMode, and let GEGL do the work for us.
At processing time, we can tell if we're the last node by checking
if we have any input.
For this to work, GimpOperationLayerMode's process() function needs
to have control over what's going on. Replace the derived op
classes, which override process(), with a call to the layer mode's
function (as per gimp_layer_mode_get_function()) in
GimpOperationLayerMode's process() function. (Well, actually, this
commit keeps the ops around, and just hacks around them in
gimp_layer_mode_get_operation(), because laziness :P)
Keep using the layer's is_last_node property to do the invalidation.
More than 2000 lines of code less in app/, instead of
if (instance->member)
{
g_object_unref/g_free/g_whatever (instance->member);
instance->member = NULL;
}
we now simply use
g_clear_object/pointer (&instance->member);
which is the same as g_object_class_list_properties() but filters
out the properties for which we don't want to create a GUI.
Use it in gimp_prop_gui_new().