Don't enable conditionally based on the buildtype.
Further, don't use `add_project_arguments()` to enable the instructions:
this will lead to crashes within g-ir-scanner, which can't properly
parse these instructions.
https://gitlab.gnome.org/GNOME/gimp/-/issues/5053
This is a continuation of #5888 as I realized that most layer modes were
fixed with my commit b3fc24268a (and follow-up f40dc40cbc) but at least
2 were still crashing GIMP: "Luma Lighten/Darken only" modes.
There were 2 bugs here:
* The first bug was that when gimp_operation_layer_mode_real_process()
ran, gimp_operation_layer_mode_prepare() had not been run yet.
prepare() is called before the process() of GeglOperation, but it
would seem the process() of GimpOperationLayerMode on the other end
happens before GeglOperation's prepare() is run. I am absolutely
unsure if this is expected or not and have a hard time figuring out
all the details of the C/C++ cohabitation.
As a solution, I am moving out the fish caching (the needed part
inside gimp_operation_layer_mode_real_process()) in its own function
so that I can easily call it separately before inspecting the fishes.
* The second issue was that some blend functions needed more than a
GeglOperation alone. E.g. blend_function() for luma lighten
gimp_operation_layer_mode_blend_luma_lighten_only() would call
gegl_operation_get_source_space() which requires the node to exist.
Similarly for the Luma darken only mode. So I keep both the node and
operation around, and when finalizing, I free the node (which in turn
frees the operation).
Ell > if you are reading our commits, I would really appreciate your
review (or fixes) of my code here! :)
My previous commit broke the autotools build. Apparently when using
g_object_unref(), some C++ symbol leaked into libapppaint.a archive
library, hence the main binaries (e.g. gimp-2.99) could not be linked
without adding -lstdc++ flag:
> /usr/bin/ld: paint/libapppaint.a(gimppaintcore-loops.o): undefined reference to symbol '__gxx_personality_v0@@CXXABI_1.3'
> /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: error adding symbols: DSO missing from command line
Not exactly sure why using this GLib function in particular caused this,
but let's just try another approach in order not to link the main binary
with C++ standard lib.
Instead let's manage all GeglOperation allocation in gimp-layer-modes.c
by adding a gimp_layer_modes_exit() function and some static array for
storing operation object of each layer mode.
The GimpOperationLayerMode variable member in DoLayerBlend was not
properly constructed. C++ class constructor can be called by creating
object variables, but with GObject, we have to do it with pointers.
Otherwise here we were only allocating the memory for the struct, but
not actually calling any initialization functions.
Also it would seem that the struct was not initialized at zero, as the
space_fish variable was not NULL when it should (i.e. even with same
composite and blend space), hence composite_to_blend_fish was not NULL
and since the operation was not a valid GeglOperation when entering
gimp_operation_layer_mode_real_process(), we crashed.
Not sure how it went unseen for so long!
So instead let's make the layer_mode class member into a pointer. As
such, I have to properly allocate and free it. This is also why I am
adding a copy constructor which will ref the pointer (otherwise we unref
more than we ref as the default copy constructor would just copy the
pointer).
As per commit ed7ea51fb7, reintroduce
the "Fade" functionality for filters, by incorporating it directly
into GimpFilterTool.
Add "mode" and "opacity" options to GimpOperationSettings, and add
a corresponding "Fade" expander to the GimpFilterTool dialog
allowing to control them.
Reintroduce the FADE layer-mode context, and use it to mark the
layer modes avaialable for fading.
In GimpOperationLayerMode, when the op has a mask connected, and
we're processing an area outside the mask bounds, set the op's
opacity to 0, so that the backdrop shows through. The actual
process() function gets a NULL mask pointer in this case, and so
would composite the layer as if it had no mask, exposing areas that
should be masked out.
Add a GimpOperationLayerMode::parent_process() function, which
subclasses can override instead of GeglOperation::process(), and
make sure to update the GimpOperationLayerMode::opacity field
before calling this function (and, subsequently, before calling
GimpOperationLayerMode::process()).
Clean up the rest of the fields, and adjust the rest of the code.
In gimp:replace, when compositing the same content over itself,
i.e., when the input and aux buffers share the same storage and
same tile alignment, pass the input buffer directly as output,
instead of doing actual processing.
In particular, this happens when processing a pass-through group
outside of its actual bounds.
Fixes issue #3451 Space invasion/AnyRGB: Luminance blend mode doesn't work
It might be faster to fetch the RGB luminance and do the computation
ourselves than looking up the same fish for each processing request, at
least now we're faster. (commit message and code slightly revised by pippin)
Some blend funcs depend on constants from the specifc color space we are
operating in and needs the space or operation propagated to the worker function
of the operation as discovered in issue #3451.
This commit propagates the operation, leaving the specific blend functions
needing it to call gegl_operation_get_source_space or similar without needing
that overhead for the rest.
In GimpOperationLayerMode and GimpOperationReplace, make sure we
don't return a NULL output buffer, or forward a NULL input buffer,
but rather create an appropriate empty buffer in this case. This
avoids wrong results when the layer-mode op's output is connected
to the aux input of a subsequent op, as a result of the op behaving
differently with a NULL aux buffer (in particular, this can happen
when a drawable filter's output bounding box is smaller than the
drawable.)
Extend last commit to also disregard the composite space when the
layer mode is trivial and only the source region is included in
compositing, since, in this case, the source color is unmodified.
In gimp_layer_mode_get_format(), disregard the requested composite
space when selecting the format, if the input layer mode is alpha-
only, and the requested composite mode is not UNION, since, in this
case, the layer mode doesn't combine the layer/backdrop colors, and
rather only modifies the alpha of one of them. This allows us to
use the preferred format, avoiding gamma conversion.
This particularly improves the performance of the Eraser tool in
perceptual images.
When the result of compositing has an alpha value of 0, the
corresponding color value is not mathematically defined.
Currently, all out layer modes opt to preserve the destination's
color value in this case. However, REPLACE mode is different
enough to warrant a different behavior:
Unlike the other layer modes, when the compositing opacity
approaches 0 or 1, the output color value approaches the
destination or source color values, respectively, regardless of the
output alpha value. When the opacity doesn't approach 0 or 1, the
output color value generally doesn't approach a limit as the output
alpha value approaches 0, however, when both the destination and
source alpha values are equal, the output color value is always a
simple linear interpolation between the destination and source
color values, according to the opacity. In other words, this means
that it's reasonable to simply use the above linear interpolation
for the output color value, whenever the output alpha value is 0.
Since filters are commonly combined with the input using REPALCE
mode with full opacity, this has the effect that filters may now
modify the color values of fully-transparent pixels. This is
generally desirable, IMO, especially for point filters. Indeed,
painting with REPLACE mode (i.e., with tools that use
gimp_paint_core_replace()) behaved excatly as described above, and
had this property, before we switched gimp_paint_core_replace() to
use the common compositing code; this created a discrepancy between
painting and applying filters, which is now gone.
A side effect of this change is that we can now turn gimp:replace
into a NOP when the opacity is 100% and there's no mask, which
avoids the compositing step when applying filters. We could
previously only apply this optimization to PASS_THROUGH mode, which
is a subclass of REPLACE mode.
Note that the discussion above concerns the UNION composite mode,
which is the only mode we currently use REPLACE in. We modify the
rest of the composite modes to match the new behavior:
CLIP_TO_BACKDROP always preserves the color values of the
destionation, CLIP_TO_LAYER always preserves the color values of
the source, and INTERSECTION always produces fully-zeroed pixels.
The scratch allocator has been moved to GEGL (commit
gegl@b99032d799dda3436ffa8c1cc28f8b0d34fb965d). Remove gimp-
scratch, and replace all its uses with gegl-scratch.
This commit completely removes the "Edit -> Fade..." feature,
because...
- The main reason is that "fade" requires us to keep two buffers,
instead of one, for each fadeable undo step, doubling (or worse,
since the extra buffer might have higher precision than the
drawable) the space consumed by these steps. This has notable
impact when editing large images. This overhead is incurred even
when not actually using "fade", and since it seems to be very
rarely used, this is too wasteful.
- "Fade" is broken in 2.10: when comitting a filter, we copy the
cached parts of the result into the apply buffer. However, the
result cache sits after the mode node, while the apply buffer
should contain the result of the filter *before* the mode node,
which can lead to wrong results in the general case.
- The same behavior can be trivially achieved "manually", by
duplicating the layer, editing the duplicate, and changing its
opacity/mode.
- If we really want this feature, now that most filters are GEGL
ops, it makes more sense to just add opacity/mode options to the
filter tool, instead of having this be a separate step.
Add a TRIVIAL layer-mode flag, and corresponding
gimp_layer_mode_is_trivial() function, which indicates if the blend
function of a given layer mode is trivial, i.e., either never
modifies the source pixels (for non-subtractive modes), or always
clears the destination pixels (for subtractive modes).
In the Luminance layer-mode, use the scratch allocator for
allocating temporary buffers, instead of using VLAs.
GimpOperationLayerMode already allocates data on the stack,
calculated as not to overflow the stack on any platform, so having
any of its descendants also allocate big buffers on the stack is
risky.
There was a global 3x3 array of babl fishes used for converting between
blending and compositing pixel representations, these were all hard-coded to
operate within the sRGB babl-space family. This commit updates a per-instance
array during operation prepare instead, that comes preconfigured with fishes
derived from the correct space. Since the same operation instance might get
different space input during its life time we store and compare the cached
fishes with the current format (which is unique depending on space).
This should address the problem seen in issue #2592
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
The default stack size for new threads on MacOS is 512 KiB, making
our 512 KiB limit for stack-allocated buffers in
gimp_operation_layer_mode_real_process() too high. Lower it to
256 KiB.
... which determines if a layer mode's blend function only affects
the alpha, maintaining the backdrop's color. This is currently
true only for ERASE, SPLIT, and ANTI_ERASE modes.
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.
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.
... 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.
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.
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.
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.