Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Allow out-of-standard-gamut colors with float canvases#4526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
kainino0x wants to merge6 commits intogpuweb:main
base:main
Choose a base branch
Loading
fromkainino0x:out-of-gamut-sometimes-valid
Draft
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 86 additions & 23 deletionsspec/index.bs
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2148,21 +2148,88 @@ premultiplication) in which the WebGPU numeric values are to be interpreted.
WebGPU allows all of the color spaces in the {{PredefinedColorSpace}} enum.
Note, each color space is defined over an extended range, as defined by the referenced CSS definitions,
to represent color values outside of its space (in both chrominance and luminance).
Any numeric value in any color space is a well-defined "color" according to its extended color
space definition, regardless of whether the point represents a real or imaginary color
(WebGPU makes no distinction between real and imaginary colors).
That "color" can be represented in other color spaces as well, where it may be in-gamut.

An <dfn dfn>out-of-gamut premultiplied RGBA value</dfn> is one where any of the R/G/B channel values
exceeds the alpha channel value. For example, the premultiplied sRGB RGBA value [1.0, 0, 0, 0.5]
represents the (unpremultiplied) color [2, 0, 0] with 50% alpha, written `rgb(srgb 2 0 0 / 50%)` in CSS.
Just like any color value outside the sRGB color gamut, this is a well defined point in the extended color space
(except when alpha is 0, in which case there is no color).
However, when such values are output to a visible canvas, the result is undefined
(see {{GPUCanvasAlphaMode}} {{GPUCanvasAlphaMode/"premultiplied"}}).
<h4 data-dfn-type=dfn>Out-of-Range Premultiplied RGBA Values
<span id=out-of-gamut-premultiplied-rgba-value><!-- historical permalink --></span>
</h4>

An [=out-of-range premultiplied RGBA value=] is one for which the unpremultiplied representation
of the same color would be outside of the range of the format.

<div class=example>
For example, on a display with a color space of exactly Display P3,
the unpremultiplied sRGB RGBA value `[1.04, 0, 0, 0.5]` and the
premultiplied sRGB RGBA value `[0.52, 0, 0, 0.5]` both represent the
CSS color <code><a funcdef>color</a>(srgb 1.04 0 0 / 0.5)</code>, which is equivalent to the
in-gamut Display P3 color <code><a funcdef>color</a>(display-p3 0.95 0.21 0.15 / 0.5)</code>.

When represented in a {{PredefinedColorSpace/"srgb"}} {{GPUTextureFormat/"rgba8unorm"}} canvas,
both values are out-of-range for the purposes of this definition,
even though the premultiplied value is representable.

(The colors in this example are in the gamut of the display to avoid any gamut mapping.)
</div>

When a canvas containing such a value is
[$get a copy of the image contents of a context|used as an image source$],
the returned image must represent the original color values without clamping,
regardless of the canvas's {{GPUCanvasConfiguration/format}}.

However, when a ({{GPUCanvasAlphaMode/"premultiplied"}}) canvas containing such a value is
displayed *on screen*, the visible result for the entire canvas is undefined.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Checking that I understand.

Consider a canvas that is premultiplied,rgba16float,srgb being displayed on a P3 monitor.

If the value[0.52, 0, 0, 0.5] is written to the canvas, and the canvas is displayed, then the result is undefined even though it's within the gamut of the display, because of various machinations that might happen throughout the display pipeline.

This seems reasonable to me. Would the idea be to make this valid when in extended mode?


<div class=example>
For example, on a display with a color space of exactly Display P3,
an on-screen, solid-color {{PredefinedColorSpace/"srgb"}} canvas displays as follows:

<table class=data>
<thead>
<tr><th>{{GPUCanvasConfiguration/alphaMode}},<br>{{GPUCanvasConfiguration/format}}<th>Pixel Value<th>Result
<tbody>
<tr><td>{{GPUCanvasAlphaMode/"opaque"}},<br>{{GPUTextureFormat/"rgba16float"}}
<td rowspan=2>`[1.04, 0, 0, 1.0]`
<td rowspan=2><code><a funcdef>color</a>(display-p3 0.95 0.21 0.15 / 1.0)</code>.
<tr><td>{{GPUCanvasAlphaMode/"premultiplied"}},<br>{{GPUTextureFormat/"rgba16float"}}
<tr><td>{{GPUCanvasAlphaMode/"premultiplied"}},<br>{{GPUTextureFormat/"rgba16float"}}
<td>`[0.52, 0, 0, 0.5]`
<td><code><a funcdef>color</a>(display-p3 0.95 0.21 0.15 / 0.5)</code>.
<tr><td>{{GPUCanvasAlphaMode/"premultiplied"}},<br>{{GPUTextureFormat/"rgba8unorm"}}
<td>`[0.50, 0, 0, 0.5]`
<td><code><a funcdef>color</a>(display-p3 0.92 0.20 0.14 / 0.5)</code>.
<tr><td>{{GPUCanvasAlphaMode/"premultiplied"}},<br>{{GPUTextureFormat/"rgba8unorm"}}
<td>`[0.52, 0, 0, 0.5]`
<td>(undefined result),
<br>because the unpremultiplied color cannot be represented in this format.
<!-- POSTV1(#4108): add example for XR formats, which *probably* handle this -->
</table>

Visible results may be undefined because the value could be lost at different steps of display:
Copy link
ContributorAuthor

@kainino0xkainino0xMar 19, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I wanted to write out an example of the actual blending math, but that ends up demonstrating a completelydifferent problem, which is that you get very different results doing nonlinear blendingin display color space (e.g.in display-p3), vsin srgb.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Yes, it gets complicated.


- Value blended directly to the display buffer as
<code><a funcdef>color</a>(display-p3 0.95 0.21 0.15 / 0.5)</code>.
- Value blended through an intermediate sRGB buffer as `[0.5, 0, 0, 0.5]`,
then sent to the display buffer resulting in the appearance of
<code><a funcdef>color</a>(display-p3 0.92 0.2 0.14 / 0.5)</code>.
- Value displayed by some other process.

(The colors in this example are in the gamut of the display to avoid any gamut mapping.)
</div>

Note:
Implementations may defer compositing steps to operating system compositors,
which often have undefined behavior in these cases. Implementations may not be able to avoid
these undefined behaviors without significant power usage penalties.

### Color Space Conversions ### {#color-space-conversions}

A color is converted between spaces by translating its representation in one space to a
representation in another according to the definitions above.

If the source value has fewer than 4 RGBA channels,the missing green/blue/alpha channels are set to
If the source value has fewer than 4 RGBA channels,any missing green/blue/alpha channels are set to
`0, 0, 1`, respectively, before converting for color space/encoding and alpha premultiplication.
After conversion, if the destination needs fewer than 4 channels, the additional channels
are ignored.
Expand All@@ -2174,11 +2241,12 @@ Colors are not lossily clamped during conversion: converting from one color spac
will result in values outside the range [0, 1] if the source color values were outside the range
of the destination color space's gamut. For an sRGB destination, for example, this can occur if the
source is rgba16float, in a wider color space like Display-P3, or is premultiplied and contains
[=out-of-gamut premultiplied RGBA value|out-of-gamut values=].
[=out-of-range premultiplied RGBA values=].

Similarly, if the source value has a high bit depth (e.g. PNG with 16 bits per component) or
extended range (e.g. canvas with `float16` storage), these colors are preserved through color space
conversion, with intermediate computations having at least the precision of the source.
Similarly, precision must be preserved through color space conversion, with intermediate
computations being at least as precise as the less-precise of the source and destination
(for example copying a PNG with 16 bits per component, or a canvas with `float16` storage, into a
{{GPUTextureFormat/rgba16float}} texture).

### Color Space Conversion Elision ### {#color-space-conversion-elision}

Expand DownExpand Up@@ -13748,19 +13816,14 @@ is being composited into (e.g. an HTML page rendering, or a 2D canvas).
: <dfn>"premultiplied"</dfn>
::
Read RGBA as premultiplied: color values are premultiplied by their alpha value.
100% red at 50% alpha is `[0.5, 0, 0, 0.5]`.
For example,100% red at 50% alpha is `[0.5, 0, 0, 0.5]`.

If [=out-of-gamut premultiplied RGBA values=] are output to the canvas, and the canvas is:
When alpha is 0, no color is represented, regardless of the RGB values.
(Attempting to compute the color results in division by zero.)

<dl class=switch>
: [$get a copy of the image contents of a context|used as an image source$]
:: Values are preserved, as described in [[#color-space-conversions|color space conversion]].

: displayed to the screen
:: Compositing results are undefined.
This is true even if color space conversion would produce in-gamut values before
compositing, because the intermediate format for compositing is not specified.
</dl>
In this mode, with some texture formats, the canvas texture can hold
[=out-of-range premultiplied RGBA values=], which have undefined display results.
Refer to that section for details.
</dl>

# Errors &amp; Debugging # {#errors-and-debugging}
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp