Open smfr opened 2 years ago
Certainly in 1998-2000 the SVG spec was created as sRGB-only. The color-interpolation-filters
property has the valuesauto
| sRGB
| linearRGB
where linearRGB
is the initial value, and corresponds to the CSS Color 4 srgb-linear
colorspace which (like all the predefined RGB spaces there) is unbounded.
There is an open issue SVG color-interpolation-filters to use more color spaces which could be solved by adding additional values to color-interpolation-filters
. As you say, another option is to allow extended sRGB as a way to access WCG colors, which would then not require new values on that property but would require careful review of wording about clipping out-of-range values. Such as this one:
The RGBA result from each filter primitive will be clamped into the allowable ranges for colors and opacity values. Thus, for example, the result from a given filter primitive will have any negative color values or opacity values adjusted up to color/opacity of zero. https://drafts.fxtf.org/filter-effects/#FilterPrimitivesOverviewIntro
Note that processing in unbounded srgb-linear
should give the same result as processing in CIE XYZ, both are linear-light.
Notice too that feColorMatrix has the sRGB-linear
to XYZ
conversion matrices baked in for saturate, hue rotate and luminance. So using unbounded srgb-linear
as the filter working space does seem a promising approach.
The only worry is whether existing content is depending on the clamping behavior; if so, some form of opt-in might be needed. Perhaps a linearRGBextended
value, or some such?
Related: Impact of colorspace on filters
So: given that
srgb-linear]()
](https://drafts.csswg.org/css-color-4/#predefined-sRGB-linear) and can represent wide color gamut colors, such as P3 colors
color-interpolation filters
exists in Filter Effects 1 with the values auto | sRGB | linearRGB
and the initial value is linearRGB
Then I propose to extend color-interpolation filters
to take an additional value with a definition link to CSS color 4, and that value is explicitly an extended, WCG space and has a 16-bit precision requirement.
Extended means that negative values, and values greater than 1.0, are allowed. For example color(display-p3 0 1 0)
, which is outside the sRGB gamut, is color(srgb-linear -0.225 1.0421 -0.079)
This will add WCG support to SVG filters, is opt-in so existing content continues to render the same, and can also be opted into to get the improved precision (8 bits linear light has visible banding) even for sRGB-only content.
The new value could be sRGB-linear
for compatibility with Canvas and with CSS Color 4, although above I suggested linearRGBextended
which I could also live with.
I'm guessing this would go in Filter Effects 2 ?
A new value for color-interpolation-filters
seems OK, but because it would be opt-in for web developers, doesn't address my initial concerns. I'd prefer that no-op CSS filters (like blur(0)
, saturate(1)
etc) act like no filter is applied, which means they can't use sRGB interpolation by default. I'd prefer this for two reasons:
Doing this would require a spec change along the lines of "CSS filters operate in the current compositing colorspace" (with some handwaving because we specify that the working colorspace is sRGB but that's not what browsers do now).
OK so this would be additional wording on no-op filter in particular (and means that saturate(1)
and saturate(0.99)
work differently) but is certainly doable.
Doing this would require a spec change along the lines of "CSS filters operate in the current compositing colorspace" (with some handwaving because we specify that the working colorspace is sRGB but that's not what browsers do now).
What do they do now? Do they all do the same thing?
What do they do now? Do they all do the same thing?
WebKit does compositing in the colorspace of the display. I don't know what Firefox and Chrome do.
The CSS Working Group just discussed [css-color] [filter-effects] Should no-op filters produce different output from no filter?
.
What do they do now? Do they all do the same thing?
WebKit does compositing in the colorspace of the display. I don't know what Firefox and Chrome do.
Chrome does compositing in the colorspace of the display. We also do rasterization in the colorspace of the display.
There are some exceptions. If the display has a color space that is too far from sRGB-like interoplationbehavior (e.g, has a linear or PQ transfer function), then we do composite and raster in extended-sRGB, and do a final blit converting to linear or PQ.
We haven't carefully quantified exactly what "too far from sRGB-like interpolation behavior" means (you can examine the current logic here).
Then I propose to extend
color-interpolation filters
to take an additional value with a definition link to CSS color 4, and that value is explicitly an extended, WCG space and has a 16-bit precision requirement.
P3 can get away with 8 bit, so I'm worried that requiring 16 bit will discourage implementations.
P3 can get away with 8 bit, so I'm worried that requiring 16 bit will discourage implementations.
No. Gamma-encoded P3 can get away with 8 bits per component, agreed. Linear-light needs considerably more bits as the space is not perceptually even, so avoiding banding requires more bits.
To see this, iterate from 0 to 255 and at each stage
Then count how many unique values there are. I wrote code to do this and 12 bits precision was the minimum to retain 256 unique values. (That code is for srgb-linear
, but display-p3
and srgb
use the same transfer function).
In addition, covering the full gamut of display-p3
in srgb-linear
requires more than 8 bits of gamma-encoded values because the range is a bit greater than 0.0 - 1.0. For example, color(display-p3 1 0 0)
is color(srgb-linear 1.22494 -0.0421 -0.0196)
The CSS Working Group just discussed [css-color] [filter-effects] Should no-op filters produce different output from no filter?
.
I'd prefer that no-op CSS filters (like
blur(0)
,saturate(1)
etc) act like no filter is applied, which means they can't use sRGB interpolation by default. I'd prefer this for two reasons:
- Web developers working on sRGB displays don't unintentionally clamp filtered Display-P3 assets to sRGB inside no-op filters
- User agents can optimize away no-op filters from their rendering pipeline
One argument against this is that we generally want to avoid discontinuities at special values. If we're animating between filter: blur(1)
and filter: blur(0)
for example, it would look odd if at the blur(0)
state the colors changed because we're no longer flattening to sRGB.
At the risk of derailing this discussion, my feeling on this issue is that we should add a feature to the web where the "working color space" of an element may be specified. This would be similar to a Canvas2D's color space. The behavior is equivalent to: all inputs are converted to that space, and then all interpolation (blending, filters, etc) is done in that space.
The default working color space today is "something not too perceptibly different from sRGB". The wiggle room there is so that compositors, etc, can make concessions to efficiency (e.g, working directly in the output device's color space).
With the ability to specify a working color space, the page's author can decide if they prefer "srgb-linear" or if they want "lab", or any of the other options we are exposing. There is no "right" space for interpolation for all applications (the main dividing line is content to have luminance that is physically linear versus perceptually uniform).
An issue that came up here is "what precision should we provide?". When exposing "display-p3" to Canvas2D, this was also a concern. The phrasing there came out as: Should the selection of a buffer's color space imply a certain precision for that buffer? That was a hard question, and we punted by only exposing "display-p3", where, like "srgb", the most reasonable default would be 8-bit-per-color (we excluded "rec2020" both because the transfer function for it had some contention, but also because 8-bit-per-color is not a reasonable default for that space). For a space like "srgb-linear", 8-bit-per-color is very-not-good. When a developer selects that, should we have a table of "minimum precision for each color space"? Or should the developer have to specify a minimum precision (and default to 8-bit if unspecified, which will look bad, but, if all browsers make it look bad, developers will not accidentally do it).
Re this question:
For GPU accelerated you're feeding through P3 color values when using srgb matrix?
To clarify, this is: Suppose the user specifies a color filter matrix M. Suppose we have an input color x in P3 space. What is the output in P3 space?
Option A: (1) let y= x converted to sRGB, (2) let z=My, (3) let w= z converted to to P3, write w to the P3 output buffer Option B: write Mx to the P3 output buffer
My understanding is that we do Option B in all paths (GPU and CPU).
my feeling on this issue is that we should add a feature to the web where the "working color space" of an element may be specified.
Already considered:
and rejected because, as you said:
There is no "right" space for interpolation for all applications (the main dividing line is content to have luminance that is physically linear versus perceptually uniform).
So yes, the appropriate colorspace depends on the operation being done so will vary for different properties on a given element as one size does not fit all. Basically the choices come down to:
An issue that came up here is "what precision should we provide?". When exposing "display-p3" to Canvas2D, this was also a concern. The phrasing there came out as: Should the selection of a buffer's color space imply a certain precision for that buffer? That was a hard question, and we punted by only exposing "display-p3", where, like "srgb", the most reasonable default would be 8-bit-per-color
That was a good choice for Canvas, given that dealing with greater than 8 bits per component was deferred until later. For the color()
syntax in CSS Color 4, the required precision per colorspace is listed in the spec. Note that compared to Canvas, which needs to store color values per-pixel, in CSS there is a need to only store color values per property declaration, greatly reducing the memory impact.
(we excluded "rec2020" both because the transfer function for it had some contention,
that issue was solved a while ago
but also because 8-bit-per-color is not a reasonable default for that space).
Right - it needs minimum 10, preferably 12 bits and Rec BT.2020 gives values for 10bit, 12bit and float representations.
For a space like "srgb-linear", 8-bit-per-color is very-not-good.
Right. 12 is the minimum here, to round-trip all 265 gamma-encoded 8 bit values.
Also, CSS is not like Photoshop where at all times you are one person working on one document. In CSS you may have effects coming in from different sources, so having a single working space doesn't make sense.
@svgeesus and @smfr, I think @ccameron-chromium 's comment above answers the question you wanted answered (with the "option B" sentence), let me know if you need more info.
my feeling on this issue is that we should add a feature to the web where the "working color space" of an element may be specified.
Already considered:
My thought on this was to have it be something not for the whole page, but could be set to apply at a lower level (e.g, one set of contents wants physical linear blending, but then some sub-content inside that wants perceptual linear blending within itself, etc). We can iterate and discuss at a later date (this thread was only slightly related to that feature).
The filter property states that "Functions must operate in the sRGB color space". This implies that all the input colors to filters, like display-p3 colors and images with P3 color profiles get flattened to sRGB before filter processing.
This has the unfortunate side effect that the results of
filter: none
andfilter: saturate(1)
are different when the filtered content contains P3 colors, and that authors can't apply nice filter effects to P3 images while retaining out-of-sRGB colors.Chrome appears to not follow this spec text precisely, and seems (on macOS at least) to apply filters in some extended sRGB colorspace (tested on iMac Pro with DisplayP3 display).
Testcase: https://codepen.io/smfr/pen/PoOVmPX
cc @svgeesus