Add a function for converting a single color from one
color state to another. This is a generalization of the
already existing function to convert a GdkRGBA to another
color state.
The outlook for mutter supporting this in GNOME 47 are cloudy,
so lets flip the switch back. You can still set
USE_POINTER_VIEWPORT in the environment to try this code.
When the compositor sends us an image description, we currently happily
reuse it.
However, those image descriptions may contain optional properties that
we do not handle - example: reference white level. So if we were to
reuse that image description, we would set a wrong reference white
level.
To avoid issues like that, never use compositor-provided image
descriptions.
However, query those image descriptions and map them to the closest
GdkColorState, so that we can quickly look up *our* version of that
image description and use that one.
When finalizing a subsurface, we need to make sure it is removed
from the sibling lists in its parent, or bad things will happen.
This should crashes seen in Epiphany nightly.
Fixes: #6891
convert_func2 is a 'from' conversion function, ie it expects to
be passed the target color state. This was wrong both in
gdk_memory_convert and gdk_memory_convert_color_state.
This is widely assumed, but is not guaranteed by Standard C, and is
known to be false on CHERI architectures (which have 64-bit sizes and
128-bit tagged pointers). Add a static assertion to ensure that GTK
will not build on platforms where this assumption does not hold.
As discussed on GNOME/gtk!7510, if GTK switches from gsize to uintptr_t
as its representation of the underlying bits in a pointer, GTK maintainers
would prefer that to be done project-wide so that it's done consistently,
after which this static assertion could be removed.
At the time of writing, GLib makes the same assumption (GNOME/glib#2842),
but GLib contributors are gradually removing it (mostly by replacing gsize
with uintptr_t where a pointer-sized quantity is needed). Finishing
that work in GLib would be a prerequisite for being able to make GTK
work on the affected platforms.
Signed-off-by: Simon McVittie <smcv@debian.org>
Some callers of these functions ask to copy 0 items from a NULL source,
which would be valid if they were copied in a loop (because NULL would
never be dereferenced), but is declared to be undefined behaviour for
Standard C memcpy. Guard the call to memcpy so that we only call it
if we have more than 0 items, and therefore should have a non-NULL
source pointer.
Detected by running a subset of the test suite with
-Dsanitize=address,undefined on x86_64.
Signed-off-by: Simon McVittie <smcv@debian.org>
Unfortunately the format string for a size_t, `%zu`, is not portable
to all Windows compilers, and the appropriate format string for the
fundamental type that implements size_t varies between platforms
(typically `%u` on 32-bit platforms, `%lu` on 64-bit Linux or
`%llu` on 64-bit Windows).
In gtk-demo, cast the number of search results to long, to avoid
breaking up a translatable string.
Elsewhere, use GLib's abstraction for this.
Signed-off-by: Simon McVittie <smcv@debian.org>
Main changes:
1. Avoid invalid writes by not passing pointers to a GArray that
realloc()s its data
2. Use a hash table to store image defs, instead of an array. This
requires a custom hash/equal function
3. Make image desc computation sync, so that setting a cs always
succeeds or always fails and doesn't depend on timing.
4. Add a few debug messages in failure paths. For lack of a category,
they ended up in MISC.
This adds machinery to create colorstate objects from cicp
tuples, as well as a function to return a cicp tuple for a
colorstate.
Still missing: a conversion shader for non-default colorstates.
Our conversion machinery supports converting from any color
state to any default color state or back. Direct conversion
between two non-default color states isn't guaranteed. For
converting *to* a cicp color state, we need this function.
Vulkan objects are integers on 32bit and it's failing when it's set to
just NULL.
```
../gdk/gdkvulkancontext.c:677:24: error: assignment to ‘VkSemaphore’ {aka ‘long long unsigned int’} from ‘void *’ makes integer from pointer without a cast [-Wint-conversion]
677 | priv->draw_semaphore = NULL;
```
Now that we don't use the fancy features anymore, we don't need to
enable them.
And that also means we don't need an env var to disable it for testing.
YUV dmabufs are not sRGB.
So instead of making the dmabuf builder have sRGB as the default
colorstate, add a NULL default option that makes the builder choose
the colorstate based on fourcc when build() is called.
If that happens, we pick sRGB usually, but for YUV we pick narrow range
BT601, like we did in versions before colorstates.
* We cannot map with offset, because offsets need to be page-size
aligned. And our code doesn't expect an offset anyway.
* The error return value from mmap() is MAP_FAILED aka -1, not NULL aka
0.
Vulkan requires us waiting on the image acquired from
vkAcquireNextImageKHR() before we start rendering to it, as that
function is allowed to return images that are still in use by the
compositor.
Because of that requirement, vkAcquireNextImageKHR() requires a
semaphore or fence to be passed that it can signal once it's done.
We now use a side channel to begin_frame() - calling
set_draw_semaphore() - to pass that semaphore so that the
vkAcquireNextImageKHR() call inside begin_frame() can use it, and then
we can wait on it later when we submit.
And yes, this is insanely convoluted, the Vulkan developers should
totally have thought about GTK's internal designs before coming up
with that idea.
When loading or saving png files, encode the CICP flags of the color
state into the PNG.
When loading, decode the CICP flags if available and detect the
colorstate they use.
If we do not support the cicp tags, we do not load the image.
So far, we ignore the ICC profiles.
Includes regeneration of nodeparse test *reference* output to include
the new tags we write to PNGs.
The original tests do not include those tags, so we implicitly test that
we read untagged files correctly.
We only download the data when we actually need it for writing into the
PNG stream.
This allows modifying the download parameters (in particular color state
in the next commit) while writing out their settings, so the code for
selecting the right colorstate liives in only one place.
We have to be careful though, because the download now happens after the
setjmp(), so we need to make sure the error path handles both cases
without leaking: Where the download has happened and where it hasn't.
Same thing as dmabuf and GL texture builders. Preparation for adding
color state support to texture constructors.
As a bonus, we can now do update regions with memory textures.
... and plumb the color state through the downloading machinery, where
no matter what path it takes it ends up in
gdk_memory_convert_color_state() or gdk_memory_convert().
The 2nd of those has been expanded to optionally do colorstate
conversion when the 2 colorstates are different.
This happens when buffer creation fails in `get_dmabuf_wl_buffer()` and
we manually call `listener->release (data, NULL)`.
Fixes: 2478dd8322 ("subsurface: Split a function")
This is a still experimental protocol (thus the xx prefix).
We are using it go obtain information about the compositors
preferred color state, and pass that on to our rendering machinery.
The currently supported color states are srgb, srgb-linear, rec2100-pq
and rec2100-linear. We don't have any support for ICC profiles.
Unlike other protocols, keep the support code for this protocol
fairly isolated behind wrapper objects, since the protocol is
still subject to change.
begin_frame is the place where we make decisions about the format,
depth and colorstate for our rendering. Make these calls take the
surface color state into account.
In particular, if the surface colorstate is suitable for GL_SRGB,
and we don't need high depth, set things up for that.
The modern incantation to get validation layers enabled is via
VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation
Vulkan has a bunch of environment variables to toggle stuff, let's use
those instead of doing our own.
The settings portal is reporting enums as string values, so
we need to translate this setting back to what we need.
Fixes
(gtk4-demo:18902): GLib-CRITICAL **: 19:06:14.783: g_variant_get_int32: assertion 'g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)' failed
that could be seen in recent nightly flatpaks.
Previously, we were always downloading into CAIRO_FORMAT_ARGB32.
Now we check the texture depth and pick a suitable format.
This improves rendering for high depth content, but it's slower.
That's why we're not yet making sure the depth is suitable for the
colorspace conversion. That would force all SRGB textures into float
surfaces as we don't consider conversions suitable for U8 in our generic
code.
This shader converts between two color states, by using the
same functions that we use on the cpu. The conversion to perform
is passed as part of the variation.
As premultiplication is part of color states on the shader, we also
encode the premultiplication in the shader.
And because opacity is a useful optimization, we also allow setting
opacity.
For now, the only possible color states are srgb and srgb-linear.
This adds the following:
- ccs argument to GskRenderNode::draw
This is the compositing color state to use when drawing.
- make implementations use the CCS argument
FIXME: Some implementations are missing
- gsk_render_node_draw_with_color_state()
Draws a node with any color state, by switching to its compositing
color state, drawing in that color state and then converting to the
desired color state.
This does draw the result OVER the previous contents in the passed in
color state, so this function should be called with the target being
empty.
- gsk_render_node_draw_ccs()
This needs to be passed a css and then draws with that ccs.
The main use for this is chaining up in rendernode draw()
implementations.
- split out shared Cairo functions into gdkcairoprivate.h
gskrendernode.c and gskrendernodeimpl.c need the same functions.
Plus, there's various code in GDK that wants to use it, so put it in
gdk/ not in gsk/
gsk_render_node_draw() now calls gsk_render_node_draw_with_color_state()
with GDK_COLOR_STATE_SRGB.