Compare commits

...

40 Commits

Author SHA1 Message Date
Matthias Clasen
a71e97fbe8 Start an image tool
This is meant to provide a convenient way to produce images in
specific color states and memory formats.
2024-06-22 17:04:28 -04:00
Matthias Clasen
a5a3ea73d3 Add tests for colorstate saving
Make sure that we successfully round-trip the color state
information through the image formats that we support for
writing, regardless of memory format.
2024-06-22 13:42:34 -04:00
Matthias Clasen
7ae4b41cb5 pixbuf: Add color state support
When creating a GdkTexture from a GdkPixbuf, see if it has an
icc profile attached, and if so, use it.
2024-06-22 13:42:34 -04:00
Matthias Clasen
67992454a7 tiff: Add color state support
When loading or saving tiff files, translate between embedded
icc profiles and color state objects.
2024-06-22 13:42:33 -04:00
Benjamin Otte
5c3bb62ca4 jpeg: Add color state support
When loading or saving jpeg files, translate between embedded
icc profiles and color state objects.
2024-06-22 13:42:33 -04:00
Matthias Clasen
2f032ad0e1 Tell libpng not to poke icc profiles
We do that outselves.
2024-06-22 13:42:33 -04:00
Benjamin Otte
88613204eb png: Add color state support
When loading or saving png files, translate between embedded
icc profiles or cicp data and color state objects.
2024-06-22 13:21:33 -04:00
Matthias Clasen
ead70de246 Add GdkDmabufTextureBuilder:color-state
Add an api that lets us associate a color state with dmabuf textures
when we turn them into a GdkTexture object.
2024-06-22 13:21:33 -04:00
Matthias Clasen
0136696e34 Add GdkGLTextureBuilder:color-state
Add an api that lets us associate a color state with GL textures
when we turn them into a GdkTexture object.
2024-06-22 13:21:33 -04:00
Matthias Clasen
400ae52809 Add gdk_memory_texture_new_with_color_state
Add an api that lets us associate a color state with image
data when we wrap it in a GdkTexture object.
2024-06-22 13:21:33 -04:00
Matthias Clasen
2c2d868366 colorstate: Add serialization
Allow to save and load cicp and icc. We still only support
srgb and srgb-linear, though. To avoid dragging in lcms at
this stage, simply include the srgb and srgb-linear icc
profiles as resources. Keep this private api for now.
2024-06-22 13:21:33 -04:00
Matthias Clasen
ca6fe07b27 gl: Do linear compositing 2024-06-22 13:19:57 -04:00
Matthias Clasen
bdb6552408 gpu: Use stem darkening for linear composited glyphs
This involves tweaking a freetype driver property
directly, since cairo font options don't cover this.

So the code is a bit ugly, but it does make text
appear better, in particular at small sizes.

See https://freetype.org/freetype2/docs/hinting/text-rendering-general.html
2024-06-22 13:19:57 -04:00
Matthias Clasen
7626f8262d cairo: Use stem darkening for glyphs
This involves tweaking a freetype driver property
directly, since cairo font options don't cover this.

So the code is a bit ugly, but it does make text
appear better, in particular at small sizes.

See https://freetype.org/freetype2/docs/hinting/text-rendering-general.html
2024-06-22 13:19:57 -04:00
Matthias Clasen
05e470f2cd cairo: Convert the contents back to srgb
We let cairo operate in linear srgb (by giving it all colors and
texture input in linear srgb), and so we need to convert the
results back to srgb in the end.
2024-06-22 13:19:57 -04:00
Matthias Clasen
c5883853d7 cairo: Convert textures to srgb-linear
Use the new gdk_memort_format_convert_color_state api to
convert textures to linear srgb before passing them to
cairo.
2024-06-22 13:19:57 -04:00
Matthias Clasen
2250761474 cairo: Convert colors to srgb-linear 2024-06-22 13:19:57 -04:00
Matthias Clasen
d35df199b0 gdk: Add a fast-path
Special case u8 RGBA8p, which is the common case.
2024-06-22 13:19:57 -04:00
Matthias Clasen
87f9c26414 gdk: Add gdk_memory_format_convert_color_state
This allows in-place color state conversions.
2024-06-22 13:19:57 -04:00
Matthias Clasen
d2cc2b6ea8 Temporarily disable gsk compare test variant
Too much failure.
2024-06-22 13:19:57 -04:00
Matthias Clasen
f73a34e71a glx: Create srgb drawables if possible
Make our visual selection code prefer fbconfigs that are
'srgb framebuffer capable', and mark the surface as 'is srgb'
in this case.

This arranges things so that GSK knows not to use an offscreen
for converting contents back to srgb in the end.
2024-06-22 13:19:57 -04:00
Matthias Clasen
b5f5e6e34b gl: Enable GL_FRAMEBUFFER_SRGB
It seems that we need this for GL_SRGB to work in GLX.
2024-06-22 13:19:57 -04:00
Matthias Clasen
7f71443d6b gdk: Use the vulkan srgb image format
We want to do compositing in a linear colorspace, and this
will take care of the 'convert back to srgb in the end' step.
2024-06-22 13:19:57 -04:00
Matthias Clasen
bb130960e2 gdk: Create our egl surface with srgb colorspace
We want to do our compositing in a linear colorspace, and the
EXT_KHR_gl_colorspace extension helps for that. We don't hard-
require it, since it isn't super-common in the wild (37%).

If we have the extension, create our egl surface with the
srgb colorspace, and report that face in gdk_surface_gl_is_srgb().
2024-06-22 13:19:57 -04:00
Matthias Clasen
0ebc7660a2 gpu: Add debug spew 2024-06-22 13:19:57 -04:00
Matthias Clasen
fe885d9f41 gpu: Make compositing happen in linear space
For now, we always deliver our framebuffer in srgb, and we always
want to composite in srgb-linear. If GL/Vulkan have provided us
with a back buffer that does this conversion on its own, we just
use it. The is expected to work at least for cases where we use
an u8 frame buffer.

Otherwise, we pass the target and compositing color states down
to where we call into the node processor to process nodes, create
an offscreen for rendering to, and then do manual color conversion
afterwards to put the result into the frame buffer.
2024-06-22 13:19:57 -04:00
Matthias Clasen
3076cd9a47 gpu: Convert textures to the right color state
Add function to convert an image from one color state to another,
and call it whenever we upload a texture.
2024-06-22 13:19:57 -04:00
Matthias Clasen
b710e72e1e gpu: Return color state when uploading textures
We want to allow for the possibility that we can automatically
convert from srgb to srgb-linear by picking the right image
format, so we need the upload operation to return the proper
color state for the image that it created.

For now, we do nothing with the returned information.
2024-06-22 13:19:57 -04:00
Matthias Clasen
c6bb894507 gpu: Pass color state to upload ops
This is so we can make decisions about the kind of image to create
based on the kind of colorstate we are going to upload.
2024-06-22 13:19:57 -04:00
Matthias Clasen
a6351ea8be gpu: track color state in the texture cache
Keep the color state information around for cached images.

We keep up to two different images per texture - that is enough to
keep the original uploaded image and the one that has been converted
to the compositing colorstate.
2024-06-22 13:19:57 -04:00
Matthias Clasen
68e132d2c0 gpu: Pass linear colors to clear ops too
This was forgotten when colors were converted.
2024-06-22 13:19:57 -04:00
Matthias Clasen
dd79dd0a52 gpu: Pass colors in srgb-linear
GdkRGBA is defined to be in srgb. Since we want to do our
compositing in srgb-linear, convert the coors as we send
them to the shader.
2024-06-22 13:19:57 -04:00
Matthias Clasen
f7ff943d08 gpu: Pass compositing color states around
Make the node processor and the pattern writer track the current
compositing color state. Color state nodes change it. We pass
the surface color state down via the frame apis.
2024-06-22 13:19:57 -04:00
Matthias Clasen
6f37b64e4c gpu: Add a color convert shader
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 an integer encoding the pair of color states.

For now, the only possible color states are srgb and srgb-linear.
2024-06-22 13:19:57 -04:00
Matthias Clasen
7f7b104438 gpu: Mark images that convert srgb
This is a special property that gpu images can have, that they
automatically convert between the linear srgb that the shaders
see, and the nonlinear srgb that the image is stored in.
2024-06-22 13:19:57 -04:00
Matthias Clasen
c76a22224b gdk: Add gdk_surface_get_gl_is_srgb()
This is a way to query whether the framebuffer we use is using GL_SRGB
or equivalent. Currently, it just returns FALSE.
2024-06-22 13:19:57 -04:00
Matthias Clasen
531ca56a20 gdk: Add gdk_texture_get_color_state
This does not do anything yet, just return srgb.
2024-06-22 13:19:57 -04:00
Matthias Clasen
5eaba3b123 gdk: Add GdkColorState
This is mostly an empty shell for now. We only have static instances
for srgb and srgb-linear, which we will use as markers during our
node processing.

In the future, this object may grow more instances, as well as the
ability to create them from and save them to icc profiles or cicp
data. And a color conversion api.
2024-06-22 13:19:57 -04:00
Benjamin Otte
d697cce5b0 gdk: Allow querying GL SRGB formats
Nobody is using this yet.
2024-06-22 13:19:57 -04:00
Benjamin Otte
ccc646dda7 gdk: Allow querying Vulkan SRGB formats
Nobody is using this yet, this is just infrastructure.
2024-06-22 13:19:57 -04:00
80 changed files with 3305 additions and 185 deletions

View File

@@ -30,6 +30,7 @@
#include <gdk/gdkcairo.h>
#include <gdk/gdkcairocontext.h>
#include <gdk/gdkclipboard.h>
#include <gdk/gdkcolorstate.h>
#include <gdk/gdkconfig.h>
#include <gdk/gdkcontentdeserializer.h>
#include <gdk/gdkcontentformats.h>

355
gdk/gdkcolorstate.c Normal file
View File

@@ -0,0 +1,355 @@
/* gdkcolorstate.c
*
* Copyright 2024 Matthias Clasen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkcolorstateprivate.h"
#include <glib/gi18n-lib.h>
/**
* GdkColorState:
*
* A `GdkColorState` object provides the information to interpret
* colors and pixels in a variety of ways.
*
* They are also known as
* [*color spaces*](https://en.wikipedia.org/wiki/Color_space).
*
* Crucially, GTK knows how to convert colors from one color
* state to another.
*
* `GdkColorState objects are immutable and therefore threadsafe.
*
* Since 4.16
*/
G_DEFINE_BOXED_TYPE (GdkColorState, gdk_color_state,
gdk_color_state_ref, gdk_color_state_unref);
/* {{{ Public API */
/**
* gdk_color_state_ref:
* @self: a `GdkColorState`
*
* Increase the reference count of @self.
*
* Returns: the object that was passed in
*
* Since: 4.16
*/
GdkColorState *
(gdk_color_state_ref) (GdkColorState *self)
{
return _gdk_color_state_ref (self);
}
/**
* gdk_color_state_unref:
* @self:a `GdkColorState`
*
* Decrease the reference count of @self.
*
* Unless @self is static, it will be freed
* when the reference count reaches zero.
*
* Since: 4.16
*/
void
(gdk_color_state_unref) (GdkColorState *self)
{
_gdk_color_state_unref (self);
}
/**
* gdk_color_state_get_srgb:
*
* Returns the color state object representing the sRGB color space.
*
* Since: 4.16
*/
GdkColorState *
gdk_color_state_get_srgb (void)
{
return GDK_COLOR_STATE_SRGB;
}
/**
* gdk_color_state_get_srgb_linear:
*
* Returns the color state object representing the linearized sRGB color space.
*
* Since: 4.16
*/
GdkColorState *
gdk_color_state_get_srgb_linear (void)
{
return GDK_COLOR_STATE_SRGB_LINEAR;
}
/**
* gdk_color_state_equal:
* @self: a `GdkColorState`
* @other: another `GdkColorStatee`
*
* Compares two `GdkColorStates` for equality.
*
* Note that this function is not guaranteed to be perfect and two objects
* describing the same color state may compare not equal. However, different
* color states will never compare equal.
*
* Returns: %TRUE if the two color states compare equal
*
* Since: 4.16
*/
gboolean
(gdk_color_state_equal) (GdkColorState *self,
GdkColorState *other)
{
return _gdk_color_state_equal (self, other);
}
/*< private >
* gdk_color_state_new_from_icc_profile:
* @icc_profile: The ICC profiles given as a `GBytes`
* @error: Return location for an error
*
* Creates a new color state for the given ICC profile data.
*
* If the given ICC profile can not be represented as a
* [struct@Gdk.ColorState], `NULL` is returned and an error
* is raised.
*
* Returns: a new `GdkColorState` or %NULL on error
*
* Since: 4.16
*/
GdkColorState *
gdk_color_state_new_from_icc_profile (GBytes *icc_profile,
GError **error)
{
GBytes *bytes;
g_return_val_if_fail (icc_profile != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
bytes = g_resources_lookup_data ("/org/gtk/libgdk/icc/srgb.icc", 0, NULL);
if (g_bytes_equal (icc_profile, bytes))
{
g_bytes_unref (bytes);
return GDK_COLOR_STATE_SRGB;
}
bytes = g_resources_lookup_data ("/org/gtk/libgdk/icc/srgb-linear.icc", 0, NULL);
if (g_bytes_equal (icc_profile, bytes))
{
g_bytes_unref (bytes);
return GDK_COLOR_STATE_SRGB_LINEAR;
}
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Failed to load ICC profile"));
return NULL;
}
/*< private >
* gdk_color_state_new_from_cicp_data:
* @color_primaries: the color primaries
* @transfer_characteristics: the transfer function
* @matrix_coefficients: the color matrix
* @full_range: whether the data is 'full-range'
* @error: Return location for an error
*
* Creates a new color state for the given CICP data.
*
* If the given CICP data can not be represented as a
* [struct@Gdk.ColorState], `NULL` is returned and an error
* is raised.
*
* See [CICP](https://en.wikipedia.org/wiki/Coding-independent_code_points)
* for more information about CICP.
*
* Returns: a new `GdkColorState` or %NULL on error
*
* Since: 4.16
*/
GdkColorState *
gdk_color_state_new_from_cicp_data (int color_primaries,
int transfer_characteristics,
int matrix_coefficients,
gboolean full_range)
{
if (color_primaries == 0 && transfer_characteristics == 13 &&
matrix_coefficients == 0 && full_range)
return GDK_COLOR_STATE_SRGB;
else if (color_primaries == 0 && transfer_characteristics == 8 &&
matrix_coefficients == 0 && full_range)
return GDK_COLOR_STATE_SRGB_LINEAR;
return NULL;
}
/*< private >
* gdk_color_state_save_to_icc_profile:
* @self: a `GdkColorState`
* @error: Return location for an error
*
* Saves the color state to an
* [ICC profile](https://en.wikipedia.org/wiki/ICC_profile).
*
* It may not be possible to represent a color state as ICC profile.
* In that case, @error will be set and %NULL will be returned.
*
* Returns: (nullable): A new `GBytes` containing the ICC profile
*
* Since: 4.16
*/
GBytes *
gdk_color_state_save_to_icc_profile (GdkColorState *self,
GError **error)
{
GBytes *bytes;
if (self == GDK_COLOR_STATE_SRGB)
{
bytes = g_resources_lookup_data ("/org/gtk/libgdk/icc/srgb.icc", 0, NULL);
g_assert (bytes != NULL);
}
else if (self == GDK_COLOR_STATE_SRGB_LINEAR)
{
bytes = g_resources_lookup_data ("/org/gtk/libgdk/icc/srgb-linear.icc", 0, NULL);
g_assert (bytes != NULL);
}
else
{
bytes = NULL;
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("ICC profile not supported for this color state"));
}
return bytes;
}
/*< private >
* gdk_color_state_save_to_cicp_data:
* @self: a `GdkColorState`
* @color_primaries: return location for color primaries
* @transfer_characteristics: return location for transfer characteristics
* @matrix_coefficients: return location for matrix_coefficients
* @full_range: return location for the full range flag
* @error: Return location for an error
*
* Saves the color state as CICP data.
*
* It may not be possible to represent a color state as CICP data.
* In that case, @error will be set and `FALSE` will be returned.
*
* See [CICP](https://en.wikipedia.org/wiki/Coding-independent_code_points)
* for more information about CICP.
*
* Returns: (nullable): `TRUE` if the out arguments were set
*
* Since: 4.16
*/
gboolean
gdk_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristics,
int *matrix_coefficients,
gboolean *full_range,
GError **error)
{
if (self == GDK_COLOR_STATE_SRGB)
{
*color_primaries = 0;
*transfer_characteristics = 13;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
}
else if (self == GDK_COLOR_STATE_SRGB_LINEAR)
{
*color_primaries = 0;
*transfer_characteristics = 8;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
}
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("This color state does not support CICP data"));
return FALSE;
}
/* }}} */
/* {{{ Default implementation */
const char *
gdk_color_state_get_name_from_id (GdkColorStateId id)
{
const char *names[] = {
"srgb", "srgb-linear",
};
return names[id];
}
GdkColorState gdk_default_color_states[] = {
{ NULL, 0 },
{ NULL, 0 },
};
/* }}} */
/* {{{ Private API */
const char *
gdk_color_state_get_name (GdkColorState *self)
{
if (GDK_IS_DEFAULT_COLOR_STATE (self))
{
switch (GDK_DEFAULT_COLOR_STATE_ID (self))
{
case GDK_COLOR_STATE_ID_SRGB: return "srgb";
case GDK_COLOR_STATE_ID_SRGB_LINEAR: return "srgb-linear";
default: g_assert_not_reached ();
}
}
return self->klass->get_name (self);
}
void
gdk_color_state_print (GdkColorState *self,
GString *string)
{
g_string_append (string, gdk_color_state_get_name (self));
}
GdkMemoryDepth
gdk_color_state_get_min_depth (GdkColorState *self)
{
if (self == GDK_COLOR_STATE_SRGB || self == GDK_COLOR_STATE_SRGB_LINEAR)
return GDK_MEMORY_U8;
return GDK_MEMORY_FLOAT16;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

50
gdk/gdkcolorstate.h Normal file
View File

@@ -0,0 +1,50 @@
/* gdkcolorstate.h
*
* Copyright 2024 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdktypes.h>
G_BEGIN_DECLS
#define GDK_TYPE_COLOR_STATE (gdk_color_state_get_type ())
GDK_AVAILABLE_IN_4_16
GType gdk_color_state_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_ref (GdkColorState *self);
GDK_AVAILABLE_IN_4_16
void gdk_color_state_unref (GdkColorState *self);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_srgb (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_srgb_linear (void);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_state_equal (GdkColorState *self,
GdkColorState *other);
G_END_DECLS

102
gdk/gdkcolorstateprivate.h Normal file
View File

@@ -0,0 +1,102 @@
#pragma once
#include "gdkcolorstate.h"
#include "gdkmemoryformatprivate.h"
typedef enum
{
GDK_COLOR_STATE_ID_SRGB,
GDK_COLOR_STATE_ID_SRGB_LINEAR,
} GdkColorStateId;
typedef struct _GdkColorStateClass GdkColorStateClass;
struct _GdkColorState
{
GdkColorStateClass *klass;
int ref_count;
};
struct _GdkColorStateClass
{
void (* free) (GdkColorState *self);
gboolean (* equal) (GdkColorState *self,
GdkColorState *other);
const char * (* get_name) (GdkColorState *self);
};
extern GdkColorState gdk_default_color_states[];
#define GDK_COLOR_STATE_SRGB (&gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB])
#define GDK_COLOR_STATE_SRGB_LINEAR (&gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB_LINEAR])
#define GDK_IS_DEFAULT_COLOR_STATE(c) (GDK_COLOR_STATE_SRGB <= (c) && (c) <= GDK_COLOR_STATE_SRGB_LINEAR)
#define GDK_DEFAULT_COLOR_STATE_ID(c) ((GdkColorStateId) (c - gdk_default_color_states))
const char * gdk_color_state_get_name (GdkColorState *color_state);
const char * gdk_color_state_get_name_from_id (GdkColorStateId id);
void gdk_color_state_print (GdkColorState *color_state,
GString *string);
GdkMemoryDepth gdk_color_state_get_min_depth (GdkColorState *color_state);
#define gdk_color_state_ref(self) _gdk_color_state_ref (self)
static inline GdkColorState *
_gdk_color_state_ref (GdkColorState *self)
{
if (GDK_IS_DEFAULT_COLOR_STATE (self))
return self;
self->ref_count++;
return self;
}
#define gdk_color_state_unref(self) _gdk_color_state_unref (self)
static inline void
_gdk_color_state_unref (GdkColorState *self)
{
if (GDK_IS_DEFAULT_COLOR_STATE (self))
return;
self->ref_count--;
if (self->ref_count == 0)
self->klass->free (self);
}
#define gdk_color_state_equal(a,b) _gdk_color_state_equal ((a), (b))
static inline gboolean
_gdk_color_state_equal (GdkColorState *self,
GdkColorState *other)
{
if (self == other)
return TRUE;
if (GDK_IS_DEFAULT_COLOR_STATE (self) || GDK_IS_DEFAULT_COLOR_STATE (other))
return FALSE;
if (self->klass != other->klass)
return FALSE;
return self->klass->equal (self, other);
}
GdkColorState * gdk_color_state_new_from_icc_profile (GBytes *icc_profile,
GError **error);
GdkColorState * gdk_color_state_new_from_cicp_data (int color_primaries,
int transfer_characteristics,
int matrix_coefficients,
gboolean full_range);
GBytes * gdk_color_state_save_to_icc_profile (GdkColorState *self,
GError **error);
gboolean gdk_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristic,
int *matrix_coefficients,
gboolean *full_range,
GError **error);

View File

@@ -1874,6 +1874,8 @@ gdk_display_init_egl (GdkDisplay *self,
epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_image_dma_buf_import_modifiers");
self->have_egl_dma_buf_export =
epoxy_has_egl_extension (priv->egl_display, "EGL_MESA_image_dma_buf_export");
self->have_egl_gl_colorspace =
epoxy_has_egl_extension (priv->egl_display, "EGL_KHR_gl_colorspace");
if (self->have_egl_no_config_context)
priv->egl_config_high_depth = gdk_display_create_egl_config (self,

View File

@@ -130,6 +130,7 @@ struct _GdkDisplay
guint have_egl_pixel_format_float : 1;
guint have_egl_dma_buf_import : 1;
guint have_egl_dma_buf_export : 1;
guint have_egl_gl_colorspace : 1;
GdkDmabufFormats *dmabuf_formats;
GdkDmabufDownloader *dmabuf_downloaders[4];

View File

@@ -200,6 +200,7 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,
"width", width,
"height", height,
"color-state", gdk_dmabuf_texture_builder_get_color_state (builder),
NULL);
g_set_object (&self->display, display);

View File

@@ -24,6 +24,7 @@
#include "gdkdebugprivate.h"
#include "gdkdisplay.h"
#include "gdkenumtypes.h"
#include "gdkcolorstate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkdmabuftexturebuilderprivate.h"
@@ -41,6 +42,8 @@ struct _GdkDmabufTextureBuilder
GdkDmabuf dmabuf;
GdkColorState *color_state;
GdkTexture *update_texture;
cairo_region_t *update_region;
};
@@ -124,6 +127,7 @@ enum
PROP_MODIFIER,
PROP_PREMULTIPLIED,
PROP_N_PLANES,
PROP_COLOR_STATE,
PROP_UPDATE_REGION,
PROP_UPDATE_TEXTURE,
@@ -141,6 +145,7 @@ gdk_dmabuf_texture_builder_dispose (GObject *object)
g_clear_object (&self->update_texture);
g_clear_pointer (&self->update_region, cairo_region_destroy);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
G_OBJECT_CLASS (gdk_dmabuf_texture_builder_parent_class)->dispose (object);
}
@@ -183,6 +188,10 @@ gdk_dmabuf_texture_builder_get_property (GObject *object,
g_value_set_uint (value, self->dmabuf.n_planes);
break;
case PROP_COLOR_STATE:
g_value_set_boxed (value, self->color_state);
break;
case PROP_UPDATE_REGION:
g_value_set_boxed (value, self->update_region);
break;
@@ -235,6 +244,10 @@ gdk_dmabuf_texture_builder_set_property (GObject *object,
gdk_dmabuf_texture_builder_set_n_planes (self, g_value_get_uint (value));
break;
case PROP_COLOR_STATE:
gdk_dmabuf_texture_builder_set_color_state (self, g_value_get_boxed (value));
break;
case PROP_UPDATE_REGION:
gdk_dmabuf_texture_builder_set_update_region (self, g_value_get_boxed (value));
break;
@@ -347,6 +360,18 @@ gdk_dmabuf_texture_builder_class_init (GdkDmabufTextureBuilderClass *klass)
1, GDK_DMABUF_MAX_PLANES, 1,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:color-state: (attributes org.gtk.Property.get=gdk_dmabuf_texture_builder_get_color_state org.gtk.Property.set=gdk_dmabuf_texture_builder_set_color_state)
*
* The color state of the texture.
*
* Since: 4.16
*/
properties[PROP_COLOR_STATE] =
g_param_spec_boxed ("color-state", NULL, NULL,
GDK_TYPE_COLOR_STATE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:update-region: (attributes org.gtk.Property.get=gdk_dmabuf_texture_builder_get_update_region org.gtk.Property.set=gdk_dmabuf_texture_builder_set_update_region)
*
@@ -383,6 +408,8 @@ gdk_dmabuf_texture_builder_init (GdkDmabufTextureBuilder *self)
for (int i = 0; i < GDK_DMABUF_MAX_PLANES; i++)
self->dmabuf.planes[i].fd = -1;
self->color_state = gdk_color_state_get_srgb ();
}
/**
@@ -843,6 +870,48 @@ gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self,
self->dmabuf.planes[plane].offset = offset;
}
/**
* gdk_dmabuf_texture_builder_get_color_state: (attributes org.gtk.Method.get_property=color-state)
* @self: a `GdkDmabufTextureBuilder`
*
* Gets the color state previously set via gdk_dmabuf_texture_builder_set_color_state().
*
* Returns: the color state
*
* Since: 4.16
*/
GdkColorState *
gdk_dmabuf_texture_builder_get_color_state (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
return self->color_state;
}
/**
* gdk_dmabuf_texture_builder_set_color_state: (attributes org.gtk.Method.set_property=color-state)
* @self: a `GdkDmabufTextureBuilder`
* @color_state: a `GdkColorState`
*
* Sets the color state for the texture. The default is SRGB.
*
* Since: 4.16
*/
void
gdk_dmabuf_texture_builder_set_color_state (GdkDmabufTextureBuilder *self,
GdkColorState *color_state)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
g_return_if_fail (color_state != NULL);
if (self->color_state != color_state)
{
g_clear_pointer (&self->color_state, gdk_color_state_unref);
self->color_state = gdk_color_state_ref (color_state);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_STATE]);
}
}
/**
* gdk_dmabuf_texture_builder_get_update_texture: (attributes org.gtk.Method.get_property=update-texture)
* @self: a `GdkDmabufTextureBuilder`

View File

@@ -100,6 +100,12 @@ void gdk_dmabuf_texture_builder_set_offset (GdkDmabufT
unsigned int plane,
unsigned int offset);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_dmabuf_texture_builder_get_color_state (GdkDmabufTextureBuilder *self);
GDK_AVAILABLE_IN_4_16
void gdk_dmabuf_texture_builder_set_color_state (GdkDmabufTextureBuilder *self,
GdkColorState *color_state);
GDK_AVAILABLE_IN_4_14
GdkTexture * gdk_dmabuf_texture_builder_get_update_texture (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14

View File

@@ -1758,6 +1758,8 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
priv->features = supported_features & ~disabled_features;
glEnable (GL_FRAMEBUFFER_SRGB);
gdk_gl_context_init_memory_flags (context);
if ((priv->features & GDK_GL_FEATURE_DEBUG) && gl_debug)

View File

@@ -151,7 +151,7 @@ gdk_gl_texture_find_format (GdkGLContext *context,
for (format = 0; format < GDK_MEMORY_N_FORMATS; format++)
{
GLint q_internal_format;
GLint q_internal_format, q_internal_srgb_format;
GLenum q_format, q_type;
GLint q_swizzle[4];
@@ -164,6 +164,7 @@ gdk_gl_texture_find_format (GdkGLContext *context,
gdk_memory_format_gl_format (format,
gdk_gl_context_get_use_es (context),
&q_internal_format,
&q_internal_srgb_format,
&q_format,
&q_type,
q_swizzle);
@@ -187,7 +188,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
GdkMemoryFormat format;
gsize expected_stride;
Download *download = download_;
GLint gl_internal_format;
GLint gl_internal_format, gl_internal_srgb_format;
GLenum gl_format, gl_type;
GLint gl_swizzle[4];
@@ -199,7 +200,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
{
gdk_memory_format_gl_format (format,
gdk_gl_context_get_use_es (context),
&gl_internal_format,
&gl_internal_format, &gl_internal_srgb_format,
&gl_format, &gl_type, gl_swizzle);
if (download->stride == expected_stride &&
download->format == format)
@@ -262,7 +263,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
gdk_memory_format_gl_format (actual_format,
gdk_gl_context_get_use_es (context),
&gl_internal_format,
&gl_internal_format, &gl_internal_srgb_format,
&gl_read_format, &gl_read_type, gl_swizzle);
}
}
@@ -274,7 +275,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
gdk_memory_format_gl_format (actual_format,
gdk_gl_context_get_use_es (context),
&gl_internal_format,
&gl_internal_format, &gl_internal_srgb_format,
&gl_read_format, &gl_read_type, gl_swizzle);
}
@@ -487,6 +488,7 @@ gdk_gl_texture_new_from_builder (GdkGLTextureBuilder *builder,
self = g_object_new (GDK_TYPE_GL_TEXTURE,
"width", gdk_gl_texture_builder_get_width (builder),
"height", gdk_gl_texture_builder_get_height (builder),
"color-state", gdk_gl_texture_builder_get_color_state (builder),
NULL);
self->context = g_object_ref (gdk_gl_texture_builder_get_context (builder));

View File

@@ -23,6 +23,7 @@
#include "gdkenumtypes.h"
#include "gdkglcontext.h"
#include "gdkcolorstate.h"
#include "gdkgltextureprivate.h"
#include <cairo-gobject.h>
@@ -38,6 +39,7 @@ struct _GdkGLTextureBuilder
GdkMemoryFormat format;
gboolean has_mipmap;
gpointer sync;
GdkColorState *color_state;
GdkTexture *update_texture;
cairo_region_t *update_region;
@@ -75,6 +77,7 @@ enum
PROP_HEIGHT,
PROP_ID,
PROP_SYNC,
PROP_COLOR_STATE,
PROP_UPDATE_REGION,
PROP_UPDATE_TEXTURE,
PROP_WIDTH,
@@ -95,6 +98,7 @@ gdk_gl_texture_builder_dispose (GObject *object)
g_clear_object (&self->update_texture);
g_clear_pointer (&self->update_region, cairo_region_destroy);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
G_OBJECT_CLASS (gdk_gl_texture_builder_parent_class)->dispose (object);
}
@@ -133,6 +137,10 @@ gdk_gl_texture_builder_get_property (GObject *object,
g_value_set_pointer (value, self->sync);
break;
case PROP_COLOR_STATE:
g_value_set_object (value, self->color_state);
break;
case PROP_UPDATE_REGION:
g_value_set_boxed (value, self->update_region);
break;
@@ -185,6 +193,10 @@ gdk_gl_texture_builder_set_property (GObject *object,
gdk_gl_texture_builder_set_sync (self, g_value_get_pointer (value));
break;
case PROP_COLOR_STATE:
gdk_gl_texture_builder_set_color_state (self, g_value_get_object (value));
break;
case PROP_UPDATE_REGION:
gdk_gl_texture_builder_set_update_region (self, g_value_get_boxed (value));
break;
@@ -286,6 +298,18 @@ gdk_gl_texture_builder_class_init (GdkGLTextureBuilderClass *klass)
g_param_spec_pointer ("sync", NULL, NULL,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:color-state: (attributes org.gtk.Property.get=gdk_gl_texture_builder_get_color_state org.gtk.Property.set=gdk_gl_texture_builder_set_color_state)
*
* The color state of the texture.
*
* Since: 4.16
*/
properties[PROP_COLOR_STATE] =
g_param_spec_boxed ("color-state", NULL, NULL,
GDK_TYPE_COLOR_STATE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:update-region: (attributes org.gtk.Property.get=gdk_gl_texture_builder_get_update_region org.gtk.Property.set=gdk_gl_texture_builder_set_update_region)
*
@@ -329,6 +353,7 @@ static void
gdk_gl_texture_builder_init (GdkGLTextureBuilder *self)
{
self->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
self->color_state = gdk_color_state_get_srgb ();
}
/**
@@ -672,6 +697,49 @@ gdk_gl_texture_builder_set_format (GdkGLTextureBuilder *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FORMAT]);
}
/**
* gdk_gl_texture_builder_get_color_state: (attributes org.gtk.Method.get_property=color-state)
* @self: a `GdkGLTextureBuilder`
*
* Gets the color state previously set via gdk_gl_texture_builder_set_color_state().
*
* Returns: the color state
*
* Since: 4.16
*/
GdkColorState *
gdk_gl_texture_builder_get_color_state (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL);
return self->color_state;
}
/**
* gdk_gl_texture_builder_set_color_state: (attributes org.gtk.Method.set_property=color-state)
* @self: a `GdkGLTextureBuilder`
* @color_state: a `GdkColorState`
*
* Sets the color state for the texture.
* Sets the color state of the texture. The default is SRGB.
*
* Since: 4.16
*/
void
gdk_gl_texture_builder_set_color_state (GdkGLTextureBuilder *self,
GdkColorState *color_state)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
g_return_if_fail (color_state != NULL);
if (self->color_state != color_state)
{
g_clear_pointer (&self->color_state, gdk_color_state_unref);
self->color_state = gdk_color_state_ref (color_state);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_STATE]);
}
}
/**
* gdk_gl_texture_builder_get_update_texture: (attributes org.gtk.Method.get_property=update-texture)
* @self: a `GdkGLTextureBuilder`

View File

@@ -64,6 +64,12 @@ GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_format (GdkGLTextureBuilder *self,
GdkMemoryFormat format);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_gl_texture_builder_get_color_state (GdkGLTextureBuilder *self);
GDK_AVAILABLE_IN_4_16
void gdk_gl_texture_builder_set_color_state (GdkGLTextureBuilder *self,
GdkColorState *color_state);
GDK_AVAILABLE_IN_4_12
gboolean gdk_gl_texture_builder_get_has_mipmap (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12

View File

@@ -23,6 +23,8 @@
#include "gdkdmabuffourccprivate.h"
#include "gdkglcontextprivate.h"
#include "gdkcolorstateprivate.h"
#include "gtk/gtkcolorutilsprivate.h"
#include "gsk/gl/fp16private.h"
@@ -338,7 +340,9 @@ struct _GdkMemoryFormatDescription
struct {
GLint internal_gl_format;
GLint internal_gles_format;
GLint internal_srgb_format;
GLenum format;
GLenum srgb_format;
GLenum type;
GLint swizzle[4];
/* -1 if none exists, ie the format is already RGBA
@@ -348,6 +352,7 @@ struct _GdkMemoryFormatDescription
} gl;
#ifdef GDK_RENDERING_VULKAN
VkFormat vk_format;
VkFormat vk_srgb_format;
#endif
#ifdef HAVE_DMABUF
guint32 dmabuf_fourcc;
@@ -380,6 +385,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_BGRA,
.internal_srgb_format = -1,
.format = GL_BGRA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -388,6 +394,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_B8G8R8A8_UNORM,
.vk_srgb_format = VK_FORMAT_B8G8R8A8_SRGB,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_ARGB8888,
@@ -409,6 +416,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.internal_srgb_format = GL_SRGB8_ALPHA8,
.format = GL_BGRA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -417,6 +425,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_UNDEFINED,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_BGRA8888,
@@ -438,6 +447,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.internal_srgb_format = GL_SRGB8_ALPHA8,
.format = GL_RGBA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -445,6 +455,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R8G8B8A8_UNORM,
.vk_srgb_format = VK_FORMAT_R8G8B8A8_SRGB,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_ABGR8888,
@@ -466,6 +477,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.internal_srgb_format = GL_SRGB8_ALPHA8,
.format = GL_RGBA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -474,6 +486,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_UNDEFINED,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_RGBA8888,
@@ -495,6 +508,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_BGRA,
.internal_srgb_format = -1,
.format = GL_BGRA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -503,6 +517,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_B8G8R8A8_UNORM,
.vk_srgb_format = VK_FORMAT_B8G8R8A8_SRGB,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_ARGB8888,
@@ -524,6 +539,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.internal_srgb_format = GL_SRGB8_ALPHA8,
.format = GL_BGRA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -532,6 +548,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_UNDEFINED,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_BGRA8888,
@@ -553,6 +570,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.internal_srgb_format = GL_SRGB8_ALPHA8,
.format = GL_RGBA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -560,6 +578,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R8G8B8A8_UNORM,
.vk_srgb_format = VK_FORMAT_R8G8B8A8_SRGB,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_ABGR8888,
@@ -581,6 +600,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.internal_srgb_format = GL_SRGB8_ALPHA8,
.format = GL_RGBA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -589,6 +609,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_UNDEFINED,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_RGBA8888,
@@ -611,6 +632,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_BGRA,
.internal_srgb_format = -1,
.format = GL_BGRA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
@@ -619,6 +641,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_B8G8R8A8_UNORM,
.vk_srgb_format = VK_FORMAT_B8G8R8A8_SRGB,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_XRGB8888,
@@ -641,6 +664,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.internal_srgb_format = GL_SRGB8_ALPHA8,
.format = GL_BGRA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
@@ -649,6 +673,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_UNDEFINED,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_BGRX8888,
@@ -671,6 +696,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.internal_srgb_format = GL_SRGB8_ALPHA8,
.format = GL_RGBA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
@@ -678,6 +704,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R8G8B8A8_UNORM,
.vk_srgb_format = VK_FORMAT_R8G8B8A8_SRGB,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_XBGR8888,
@@ -700,6 +727,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.internal_srgb_format = GL_SRGB8_ALPHA8,
.format = GL_RGBA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
@@ -708,6 +736,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_UNDEFINED,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_RGBX8888,
@@ -730,6 +759,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGB8,
.internal_gles_format = GL_RGB8,
.internal_srgb_format = GL_SRGB8,
.format = GL_RGB,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -737,6 +767,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R8G8B8_UNORM,
.vk_srgb_format = VK_FORMAT_R8G8B8_SRGB,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_BGR888,
@@ -759,6 +790,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGB8,
.internal_gles_format = GL_RGB8,
.internal_srgb_format = GL_SRGB8,
.format = GL_BGR,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -767,6 +799,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_B8G8R8_UNORM,
.vk_srgb_format = VK_FORMAT_B8G8R8_SRGB,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_RGB888,
@@ -792,6 +825,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGB16,
.internal_gles_format = GL_RGB16,
.internal_srgb_format = -1,
.format = GL_RGB,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -799,6 +833,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16G16B16_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -823,6 +858,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA16,
.internal_gles_format = GL_RGBA16,
.internal_srgb_format = -1,
.format = GL_RGBA,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -830,6 +866,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16G16B16A16_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_ABGR16161616,
@@ -854,6 +891,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA16,
.internal_gles_format = GL_RGBA16,
.internal_srgb_format = -1,
.format = GL_RGBA,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -861,6 +899,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16G16B16A16_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_ABGR16161616,
@@ -885,6 +924,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGB16F,
.internal_gles_format = GL_RGB16F,
.internal_srgb_format = -1,
.format = GL_RGB,
.type = GL_HALF_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -892,6 +932,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16G16B16_SFLOAT,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -915,6 +956,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA16F,
.internal_gles_format = GL_RGBA16F,
.internal_srgb_format = -1,
.format = GL_RGBA,
.type = GL_HALF_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -922,6 +964,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16G16B16A16_SFLOAT,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_ABGR16161616F,
@@ -945,6 +988,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA16F,
.internal_gles_format = GL_RGBA16F,
.internal_srgb_format = -1,
.format = GL_RGBA,
.type = GL_HALF_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -952,6 +996,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16G16B16A16_SFLOAT,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_ABGR16161616F,
@@ -976,6 +1021,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGB32F,
.internal_gles_format = GL_RGB32F,
.internal_srgb_format = -1,
.format = GL_RGB,
.type = GL_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -983,6 +1029,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R32G32B32_SFLOAT,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1006,6 +1053,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA32F,
.internal_gles_format = GL_RGBA32F,
.internal_srgb_format = -1,
.format = GL_RGBA,
.type = GL_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -1013,6 +1061,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R32G32B32A32_SFLOAT,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1036,6 +1085,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RGBA32F,
.internal_gles_format = GL_RGBA32F,
.internal_srgb_format = -1,
.format = GL_RGBA,
.type = GL_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -1043,6 +1093,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R32G32B32A32_SFLOAT,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1065,6 +1116,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RG8,
.internal_gles_format = GL_RG8,
.internal_srgb_format = -1,
.format = GL_RG,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
@@ -1072,6 +1124,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R8G8_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1094,6 +1147,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RG8,
.internal_gles_format = GL_RG8,
.internal_srgb_format = -1,
.format = GL_RG,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
@@ -1101,6 +1155,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R8G8_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1123,6 +1178,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_R8,
.internal_gles_format = GL_R8,
.internal_srgb_format = -1,
.format = GL_RED,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_ONE },
@@ -1130,6 +1186,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R8_UNORM,
.vk_srgb_format = VK_FORMAT_R8_SRGB,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_R8,
@@ -1155,6 +1212,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RG16,
.internal_gles_format = GL_RG16,
.internal_srgb_format = -1,
.format = GL_RG,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
@@ -1162,6 +1220,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16G16_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1187,6 +1246,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_RG16,
.internal_gles_format = GL_RG16,
.internal_srgb_format = -1,
.format = GL_RG,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
@@ -1194,6 +1254,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16G16_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1219,6 +1280,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_R16,
.internal_gles_format = GL_R16,
.internal_srgb_format = -1,
.format = GL_RED,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_ONE },
@@ -1226,6 +1288,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = DRM_FORMAT_R16,
@@ -1248,6 +1311,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_R8,
.internal_gles_format = GL_R8,
.internal_srgb_format = -1,
.format = GL_RED,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
@@ -1255,6 +1319,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R8_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1280,6 +1345,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_R16,
.internal_gles_format = GL_R16,
.internal_srgb_format = -1,
.format = GL_RED,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
@@ -1287,6 +1353,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16_UNORM,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1311,6 +1378,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_R16F,
.internal_gles_format = GL_R16F,
.internal_srgb_format = -1,
.format = GL_RED,
.type = GL_HALF_FLOAT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
@@ -1318,6 +1386,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R16_SFLOAT,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1342,6 +1411,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.gl = {
.internal_gl_format = GL_R32F,
.internal_gles_format = GL_R32F,
.internal_srgb_format = -1,
.format = GL_RED,
.type = GL_FLOAT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
@@ -1349,6 +1419,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
},
#ifdef GDK_RENDERING_VULKAN
.vk_format = VK_FORMAT_R32_SFLOAT,
.vk_srgb_format = VK_FORMAT_UNDEFINED,
#endif
#ifdef HAVE_DMABUF
.dmabuf_fourcc = 0,
@@ -1543,6 +1614,7 @@ void
gdk_memory_format_gl_format (GdkMemoryFormat format,
gboolean gles,
GLint *out_internal_format,
GLint *out_internal_srgb_format,
GLenum *out_format,
GLenum *out_type,
GLint out_swizzle[4])
@@ -1551,6 +1623,7 @@ gdk_memory_format_gl_format (GdkMemoryFormat format,
*out_internal_format = memory_formats[format].gl.internal_gles_format;
else
*out_internal_format = memory_formats[format].gl.internal_gl_format;
*out_internal_srgb_format = memory_formats[format].gl.internal_srgb_format;
*out_format = memory_formats[format].gl.format;
*out_type = memory_formats[format].gl.type;
memcpy (out_swizzle, memory_formats[format].gl.swizzle, sizeof(GLint) * 4);
@@ -1562,6 +1635,8 @@ gdk_memory_format_gl_format (GdkMemoryFormat format,
* @gles: TRUE for GLES, FALSE for GL
* @out_actual_format: The actual RGBA format
* @out_internal_format: the GL internal format
* @out_internal_srgb_format: the GL internal format to use for automatic
* sRGB<=>linear conversion
* @out_format: the GL format
* @out_type: the GL type
* @out_swizzle: The swizzle to use
@@ -1580,6 +1655,7 @@ gdk_memory_format_gl_rgba_format (GdkMemoryFormat format,
gboolean gles,
GdkMemoryFormat *out_actual_format,
GLint *out_internal_format,
GLint *out_internal_srgb_format,
GLenum *out_format,
GLenum *out_type,
GLint out_swizzle[4])
@@ -1594,6 +1670,7 @@ gdk_memory_format_gl_rgba_format (GdkMemoryFormat format,
*out_internal_format = memory_formats[actual].gl.internal_gles_format;
else
*out_internal_format = memory_formats[actual].gl.internal_gl_format;
*out_internal_srgb_format = memory_formats[actual].gl.internal_srgb_format;
*out_format = memory_formats[actual].gl.format;
*out_type = memory_formats[actual].gl.type;
memcpy (out_swizzle, memory_formats[format].gl.rgba_swizzle, sizeof(GLint) * 4);
@@ -1647,6 +1724,14 @@ gdk_memory_format_vk_format (GdkMemoryFormat format,
return memory_formats[format].vk_format;
}
/* Gets the matching SRGB version of a VkFormat
* Returns VK_FORMAT_UNDEFINED if none exists */
VkFormat
gdk_memory_format_vk_srgb_format (GdkMemoryFormat format)
{
return memory_formats[format].vk_srgb_format;
}
/* Vulkan version of gdk_memory_format_gl_rgba_format()
* Returns VK_FORMAT_UNDEFINED on failure */
VkFormat
@@ -1748,6 +1833,10 @@ gdk_memory_convert (guchar *dest_data,
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
g_assert (src_format < GDK_MEMORY_N_FORMATS);
/* We don't allow overlap here. If you want to do in-place color state conversions,
* use gdk_memory_convert_color_state.
*/
g_assert (dest_data + height * dest_stride < src_data || src_data + height * src_stride < dest_data);
if (src_format == dest_format)
{
@@ -1833,3 +1922,201 @@ gdk_memory_convert (guchar *dest_data,
g_free (tmp);
}
static const guchar srgb_lookup[] = {
0, 12, 21, 28, 33, 38, 42, 46, 49, 52, 55, 58, 61, 63, 66, 68,
70, 73, 75, 77, 79, 81, 82, 84, 86, 88, 89, 91, 93, 94, 96, 97,
99, 100, 102, 103, 104, 106, 107, 109, 110, 111, 112, 114, 115, 116, 117, 118,
120, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134, 135, 136,
137, 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
151, 152, 153, 154, 155, 156, 157, 157, 158, 159, 160, 161, 161, 162, 163, 164,
165, 165, 166, 167, 168, 168, 169, 170, 171, 171, 172, 173, 174, 174, 175, 176,
176, 177, 178, 179, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187,
187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 194, 195, 196, 196, 197,
197, 198, 199, 199, 200, 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206,
207, 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215,
216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224,
224, 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232,
233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 237, 238, 238, 239, 239, 240,
240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247,
248, 248, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255
};
static const guchar srgb_inverse_lookup[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7,
7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12,
13, 13, 13, 14, 14, 15, 15, 16, 16, 16, 17, 17, 18, 18, 19, 19,
20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29,
29, 30, 31, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, 38, 39, 40,
41, 42, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54,
55, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70,
71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87, 88,
89, 90, 92, 93, 94, 95, 97, 98, 99, 101, 102, 103, 105, 106, 107, 109,
110, 112, 113, 114, 116, 117, 119, 120, 122, 123, 125, 126, 128, 129, 131, 132,
134, 135, 137, 139, 140, 142, 144, 145, 147, 148, 150, 152, 153, 155, 157, 159,
160, 162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 188,
190, 192, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 218, 220,
222, 224, 226, 228, 230, 232, 235, 237, 239, 241, 243, 245, 248, 250, 252, 255
};
static void
convert_srgb_to_srgb_linear (guchar *data,
gsize n)
{
for (gsize i = 0; i < n; i++)
{
guint8 r = data[0];
guint8 g = data[1];
guint8 b = data[2];
guchar a = data[3];
float f = a / 255.0;
if (a < 255)
{
r = r / f;
g = g / f;
b = b / f;
}
r = srgb_inverse_lookup[r];
g = srgb_inverse_lookup[g];
b = srgb_inverse_lookup[b];
data[0] = r * f;
data[1] = g * f;
data[2] = b * f;
data += 4;
}
}
static void
convert_srgb_linear_to_srgb (guchar *data,
gsize n)
{
for (gsize i = 0; i < n; i++)
{
guint8 r = data[0];
guint8 g = data[1];
guint8 b = data[2];
guchar a = data[3];
float f = a / 255.0;
if (a < 255)
{
r = r / f;
g = g / f;
b = b / f;
}
r = srgb_lookup[r];
g = srgb_lookup[g];
b = srgb_lookup[b];
data[0] = r * f;
data[1] = g * f;
data[2] = b * f;
data += 4;
}
}
static void
convert_srgb_to_srgb_linear_in_place (guchar *data,
gsize stride,
gsize width,
gsize height)
{
if (stride == width * 4)
{
convert_srgb_to_srgb_linear (data, height * width);
}
else
{
for (gsize y = 0; y < height; y++)
{
convert_srgb_to_srgb_linear (data, width);
data += stride;
}
}
}
static void
convert_srgb_linear_to_srgb_in_place (guchar *data,
gsize stride,
gsize width,
gsize height)
{
if (stride == width * 4)
{
convert_srgb_linear_to_srgb (data, height * width);
}
else
{
for (gsize y = 0; y < height; y++)
{
convert_srgb_linear_to_srgb (data, width);
data += stride;
}
}
}
typedef void (* StepFunc) (float s0, float s1, float s2,
float *d0, float *d1, float *d2);
void
gdk_memory_convert_color_state (guchar *data,
gsize stride,
GdkMemoryFormat format,
GdkColorState *src_color_state,
GdkColorState *dest_color_state,
gsize width,
gsize height)
{
if (format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED &&
src_color_state == GDK_COLOR_STATE_SRGB &&
dest_color_state == GDK_COLOR_STATE_SRGB_LINEAR)
{
convert_srgb_to_srgb_linear_in_place (data, stride, width, height);
}
else if (format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED &&
src_color_state == GDK_COLOR_STATE_SRGB_LINEAR &&
dest_color_state == GDK_COLOR_STATE_SRGB)
{
convert_srgb_linear_to_srgb_in_place (data, stride, width, height);
}
else
{
/* General case, treat it just like gdk_memory_convert */
const GdkMemoryFormatDescription *desc = &memory_formats[format];
StepFunc func;
float *tmp;
if (src_color_state == GDK_COLOR_STATE_SRGB &&
dest_color_state == GDK_COLOR_STATE_SRGB_LINEAR)
func = gtk_rgb_to_linear_srgb;
else if (src_color_state == GDK_COLOR_STATE_SRGB_LINEAR &&
dest_color_state == GDK_COLOR_STATE_SRGB)
func = gtk_linear_srgb_to_rgb;
else
return;
tmp = g_new (float, width * 4);
for (gsize y = 0; y < height; y++)
{
desc->to_float (tmp, data, width);
if (desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED)
unpremultiply (tmp, width);
for (gsize x = 0; x < 4 * width; x += 4)
func (tmp[x], tmp[x+1], tmp[x+2], &tmp[x], &tmp[x+1], &tmp[x+2]);
if (desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
desc->from_float (data, tmp, width);
data += stride;
}
g_free (tmp);
}
}

View File

@@ -57,6 +57,7 @@ GdkMemoryFormat gdk_memory_depth_get_alpha_format (GdkMemoryDepth
void gdk_memory_format_gl_format (GdkMemoryFormat format,
gboolean gles,
GLint *out_internal_format,
GLint *out_internal_srgb_format,
GLenum *out_format,
GLenum *out_type,
GLint out_swizzle[4]);
@@ -64,12 +65,14 @@ gboolean gdk_memory_format_gl_rgba_format (GdkMemoryFormat
gboolean gles,
GdkMemoryFormat *out_actual_format,
GLint *out_internal_format,
GLint *out_internal_srgb_format,
GLenum *out_format,
GLenum *out_type,
GLint out_swizzle[4]);
#ifdef GDK_RENDERING_VULKAN
VkFormat gdk_memory_format_vk_format (GdkMemoryFormat format,
VkComponentMapping *out_swizzle);
VkFormat gdk_memory_format_vk_srgb_format (GdkMemoryFormat format);
VkFormat gdk_memory_format_vk_rgba_format (GdkMemoryFormat format,
GdkMemoryFormat *out_rgba_format,
VkComponentMapping *out_swizzle);
@@ -85,6 +88,13 @@ void gdk_memory_convert (guchar
GdkMemoryFormat src_format,
gsize width,
gsize height);
void gdk_memory_convert_color_state (guchar *data,
gsize stride,
GdkMemoryFormat format,
GdkColorState *src_color_state,
GdkColorState *dest_color_state,
gsize width,
gsize height);
G_END_DECLS

View File

@@ -22,6 +22,7 @@
#include "gdkmemorytextureprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkcolorstateprivate.h"
#include "gsk/gl/fp16private.h"
/**
@@ -131,11 +132,15 @@ gdk_memory_sanitize (GBytes *bytes,
* @bytes: the `GBytes` containing the pixel data
* @stride: rowstride for the data
*
* Creates a new texture for a blob of image data.
* Creates a new texture for a blob of sRGB image data.
*
* The `GBytes` must contain @stride × @height pixels
* in the given format.
*
* The data is assumed to be in SRGB. See
* [constructor@Gdk.MemoryTexutre.new_with_color_state]
* for data in other color states.
*
* Returns: (type GdkMemoryTexture): A newly-created `GdkTexture`
*/
GdkTexture *
@@ -144,11 +149,43 @@ gdk_memory_texture_new (int width,
GdkMemoryFormat format,
GBytes *bytes,
gsize stride)
{
return gdk_memory_texture_new_with_color_state (width, height, format,
GDK_COLOR_STATE_SRGB,
bytes, stride);
}
/**
* gdk_memory_texture_new_with_color_state:
* @width: the width of the texture
* @height: the height of the texture
* @format: the format of the data
* @color_state: the `GdkColorState` of the data
* @bytes: the `GBytes` containing the pixel data
* @stride: rowstride for the data
*
* Creates a new texture for a blob of image data.
*
* The `GBytes` must contain @stride x @height pixels
* in the given format and color state.
*
* Returns: A newly-created `GdkTexture`
*
* Since: 4.16
*/
GdkTexture *
gdk_memory_texture_new_with_color_state (int width,
int height,
GdkMemoryFormat format,
GdkColorState *color_state,
GBytes *bytes,
gsize stride)
{
GdkMemoryTexture *self;
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
g_return_val_if_fail (color_state != NULL, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
/* needs to be this complex to support subtexture of the bottom right part */
@@ -159,6 +196,7 @@ gdk_memory_texture_new (int width,
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
"width", width,
"height", height,
"color-state", color_state,
NULL);
GDK_TEXTURE (self)->format = format;
@@ -191,11 +229,12 @@ gdk_memory_texture_new_subtexture (GdkMemoryTexture *source,
size = source->stride * (height - 1) + width * bpp;
bytes = g_bytes_new_from_bytes (source->bytes, offset, size);
result = gdk_memory_texture_new (width,
height,
texture->format,
bytes,
source->stride);
result = gdk_memory_texture_new_with_color_state (width,
height,
texture->format,
texture->color_state,
bytes,
source->stride);
g_bytes_unref (bytes);
return result;
@@ -219,11 +258,12 @@ gdk_memory_texture_from_texture (GdkTexture *texture)
gdk_texture_do_download (texture, texture->format, data, stride);
bytes = g_bytes_new_take (data, stride * texture->height);
result = gdk_memory_texture_new (texture->width,
texture->height,
texture->format,
bytes,
stride);
result = gdk_memory_texture_new_with_color_state (texture->width,
texture->height,
texture->format,
texture->color_state,
bytes,
stride);
g_bytes_unref (bytes);
return GDK_MEMORY_TEXTURE (result);

View File

@@ -68,6 +68,14 @@ GdkTexture * gdk_memory_texture_new (int
GBytes *bytes,
gsize stride);
GDK_AVAILABLE_IN_4_16
GdkTexture * gdk_memory_texture_new_with_color_state (int width,
int height,
GdkMemoryFormat format,
GdkColorState *color_state,
GBytes *bytes,
gsize stride);
G_END_DECLS

View File

@@ -1148,9 +1148,11 @@ gdk_surface_ensure_egl_surface (GdkSurface *self,
g_return_if_fail (priv->egl_native_window != NULL);
if (gdk_display_get_egl_config_high_depth (display) == gdk_display_get_egl_config (display))
high_depth = FALSE;
if (priv->egl_surface_high_depth != high_depth &&
priv->egl_surface != NULL &&
gdk_display_get_egl_config_high_depth (display) != gdk_display_get_egl_config (display))
priv->egl_surface != NULL)
{
gdk_gl_context_clear_current_if_surface (self);
eglDestroySurface (gdk_display_get_egl_display (display), priv->egl_surface);
@@ -1159,16 +1161,35 @@ gdk_surface_ensure_egl_surface (GdkSurface *self,
if (priv->egl_surface == NULL)
{
EGLint attribs[4];
int i;
i = 0;
if (!high_depth && display->have_egl_gl_colorspace)
{
attribs[i++] = EGL_GL_COLORSPACE_KHR;
attribs[i++] = EGL_GL_COLORSPACE_SRGB_KHR;
}
g_assert (i < G_N_ELEMENTS (attribs));
attribs[i++] = EGL_NONE;
priv->egl_surface = eglCreateWindowSurface (gdk_display_get_egl_display (display),
high_depth ? gdk_display_get_egl_config_high_depth (display)
: gdk_display_get_egl_config (display),
(EGLNativeWindowType) priv->egl_native_window,
NULL);
attribs);
priv->egl_surface_high_depth = high_depth;
self->is_srgb = !high_depth && display->have_egl_gl_colorspace;
}
#endif
}
gboolean
gdk_surface_get_gl_is_srgb (GdkSurface *self)
{
return self->is_srgb;
}
GdkGLContext *
gdk_surface_get_paint_gl_context (GdkSurface *surface,
GError **error)

View File

@@ -70,6 +70,7 @@ struct _GdkSurface
guint shortcuts_inhibited : 1;
guint request_motion : 1;
guint has_pointer : 1;
guint is_srgb : 1;
guint request_motion_id;
@@ -302,6 +303,8 @@ void gdk_surface_ensure_egl_surface (GdkSurface
gboolean hdr);
gpointer /*EGLSurface*/ gdk_surface_get_egl_surface (GdkSurface *self);
gboolean gdk_surface_get_gl_is_srgb (GdkSurface *self);
void gdk_surface_set_widget (GdkSurface *self,
gpointer widget);
gpointer gdk_surface_get_widget (GdkSurface *self);

View File

@@ -44,6 +44,7 @@
#include "gdkmemorytextureprivate.h"
#include "gdkpaintable.h"
#include "gdksnapshot.h"
#include "gdkcolorstateprivate.h"
#include <graphene.h>
#include "loaders/gdkpngprivate.h"
@@ -69,6 +70,7 @@ enum {
PROP_0,
PROP_WIDTH,
PROP_HEIGHT,
PROP_COLOR_STATE,
N_PROPS
};
@@ -282,6 +284,12 @@ gdk_texture_set_property (GObject *gobject,
self->height = g_value_get_int (value);
break;
case PROP_COLOR_STATE:
if (self->color_state)
gdk_color_state_unref (self->color_state);
self->color_state = gdk_color_state_ref (g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@@ -306,6 +314,10 @@ gdk_texture_get_property (GObject *gobject,
g_value_set_int (value, self->height);
break;
case PROP_COLOR_STATE:
g_value_set_boxed (value, self->color_state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@@ -344,6 +356,8 @@ gdk_texture_dispose (GObject *object)
gdk_texture_clear_render_data (self);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
G_OBJECT_CLASS (gdk_texture_parent_class)->dispose (object);
}
@@ -388,12 +402,28 @@ gdk_texture_class_init (GdkTextureClass *klass)
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GdkTexture:color-state: (attributes org.gtk.Property.get=gdk_texture_get_color_state)
*
* The color state of the texture.
*
* Since: 4.16
*/
properties[PROP_COLOR_STATE] =
g_param_spec_boxed ("color-state", NULL, NULL,
GDK_TYPE_COLOR_STATE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gdk_texture_init (GdkTexture *self)
{
self->color_state = GDK_COLOR_STATE_SRGB;
}
/**
@@ -435,6 +465,30 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
return texture;
}
static GdkColorState *
gdk_color_state_from_pixbuf (GdkPixbuf *pixbuf)
{
const char *icc_profile_base64;
GdkColorState *color_state = NULL;
icc_profile_base64 = gdk_pixbuf_get_option (pixbuf, "icc-profile");
if (icc_profile_base64)
{
guchar *icc_data;
gsize icc_len;
GBytes *bytes;
icc_data = g_base64_decode (icc_profile_base64, &icc_len);
bytes = g_bytes_new_take (icc_data, icc_len);
color_state = gdk_color_state_new_from_icc_profile (bytes, NULL);
g_bytes_unref (bytes);
}
if (!color_state)
color_state = GDK_COLOR_STATE_SRGB;
return color_state;
}
/**
* gdk_texture_new_for_pixbuf:
* @pixbuf: a `GdkPixbuf`
@@ -452,24 +506,31 @@ gdk_texture_new_for_pixbuf (GdkPixbuf *pixbuf)
{
GdkTexture *texture;
GBytes *bytes;
GdkColorState *color_state;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
color_state = gdk_color_state_from_pixbuf (pixbuf);
bytes = g_bytes_new_with_free_func (gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_height (pixbuf)
* (gsize) gdk_pixbuf_get_rowstride (pixbuf),
g_object_unref,
g_object_ref (pixbuf));
texture = gdk_memory_texture_new (gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? GDK_MEMORY_GDK_PIXBUF_ALPHA
: GDK_MEMORY_GDK_PIXBUF_OPAQUE,
bytes,
gdk_pixbuf_get_rowstride (pixbuf));
texture = gdk_memory_texture_new_with_color_state (gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? GDK_MEMORY_GDK_PIXBUF_ALPHA
: GDK_MEMORY_GDK_PIXBUF_OPAQUE,
color_state,
bytes,
gdk_pixbuf_get_rowstride (pixbuf));
g_bytes_unref (bytes);
gdk_color_state_unref (color_state);
return texture;
}
@@ -727,6 +788,23 @@ gdk_texture_get_height (GdkTexture *texture)
return texture->height;
}
/**
* gdk_texture_get_color_state: (attributes org.gtk.Method.get_property=color-state)
* @texture: a `GdkTexture`
*
* Returns the color state associsated with @texture.
*
* Returns: (transfer none): the color state of the `GdkTexture`
*
* Since: 4.16
*/
GdkColorState *
gdk_texture_get_color_state (GdkTexture *texture)
{
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
return texture->color_state;
}
void
gdk_texture_do_download (GdkTexture *texture,
GdkMemoryFormat format,

View File

@@ -83,6 +83,9 @@ int gdk_texture_get_height (GdkTexture
GDK_AVAILABLE_IN_4_10
GdkMemoryFormat gdk_texture_get_format (GdkTexture *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_texture_get_color_state (GdkTexture *self);
GDK_AVAILABLE_IN_ALL
void gdk_texture_download (GdkTexture *texture,
guchar *data,

View File

@@ -26,6 +26,8 @@ struct _GdkTexture
int width;
int height;
GdkColorState *color_state;
gpointer render_key;
gpointer render_data;
GDestroyNotify render_notify;

View File

@@ -74,6 +74,7 @@ typedef cairo_rectangle_int_t GdkRectangle;
/* Forward declarations of commonly used types */
typedef struct _GdkRGBA GdkRGBA;
typedef struct _GdkColorState GdkColorState;
typedef struct _GdkContentFormats GdkContentFormats;
typedef struct _GdkContentProvider GdkContentProvider;
typedef struct _GdkCursor GdkCursor;

View File

@@ -884,7 +884,9 @@ gdk_vulkan_context_real_init (GInitable *initable,
switch ((int) formats[i].format)
{
case VK_FORMAT_B8G8R8A8_UNORM:
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED)
case VK_FORMAT_B8G8R8A8_SRGB:
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED ||
priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_B8G8R8A8_UNORM)
{
priv->formats[GDK_MEMORY_U8].vk_format = formats[i];
priv->formats[GDK_MEMORY_U8].gdk_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED;
@@ -893,7 +895,9 @@ gdk_vulkan_context_real_init (GInitable *initable,
break;
case VK_FORMAT_R8G8B8A8_UNORM:
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED)
case VK_FORMAT_R8G8B8A8_SRGB:
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED ||
priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_R8G8B8A8_UNORM)
{
priv->formats[GDK_MEMORY_U8].vk_format = formats[i];
priv->formats[GDK_MEMORY_U8].gdk_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;

View File

@@ -26,6 +26,8 @@ xml = '''<?xml version='1.0' encoding='UTF-8'?>
<gresources>
<gresource prefix='/org/gtk/libgdk'>
<file alias='cursor/default'>default_cursor.png</file>
<file alias='icc/srgb.icc'>srgb.icc</file>
<file alias='icc/srgb-linear.icc'>srgb-linear.icc</file>
'''
def get_files(subdir,extension):

View File

@@ -24,6 +24,8 @@
#include <glib/gi18n-lib.h>
#include "gdktexture.h"
#include "gdktexturedownloaderprivate.h"
#include "gdkcolorstateprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
@@ -74,7 +76,51 @@ output_message_handler (j_common_ptr cinfo)
}
/* }}} */
/* {{{ Format conversion */
/* {{{ Color profile handling */
static GdkColorState *
gdk_jpeg_get_color_state (struct jpeg_decompress_struct *info)
{
GdkColorState *color_state;
JOCTET *icc_data;
unsigned int icc_len;
if (jpeg_read_icc_profile (info, &icc_data, &icc_len))
{
GBytes *icc_bytes = g_bytes_new_with_free_func (icc_data, icc_len, free, icc_data);
color_state = gdk_color_state_new_from_icc_profile (icc_bytes, NULL);
g_bytes_unref (icc_bytes);
if (!color_state)
{
g_debug ("Failed to load icc profile, assuming SRGB");
color_state = GDK_COLOR_STATE_SRGB;
}
}
else
color_state = GDK_COLOR_STATE_SRGB;
return color_state;
}
static void
gdk_jpeg_set_color_state (struct jpeg_compress_struct *info,
GdkColorState *color_state)
{
GBytes *bytes;
bytes = gdk_color_state_save_to_icc_profile (color_state, NULL);
if (bytes)
{
jpeg_write_icc_profile (info,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
g_bytes_unref (bytes);
}
}
/* }}} */
/* {{{ Format conversion */
static void
convert_grayscale_to_rgb (guchar *data,
@@ -131,7 +177,7 @@ convert_cmyk_to_rgba (guchar *data,
}
}
/* }}} */
/* }}} */
/* {{{ Public API */
GdkTexture *
@@ -146,6 +192,7 @@ gdk_load_jpeg (GBytes *input_bytes,
GBytes *bytes;
GdkTexture *texture;
GdkMemoryFormat format;
GdkColorState *color_state;
G_GNUC_UNUSED guint64 before = GDK_PROFILER_CURRENT_TIME;
info.err = jpeg_std_error (&jerr.pub);
@@ -169,6 +216,9 @@ gdk_load_jpeg (GBytes *input_bytes,
g_bytes_get_data (input_bytes, NULL),
g_bytes_get_size (input_bytes));
/* save color space */
jpeg_save_markers (&info, JPEG_APP0 + 2, 0xFFFF);
jpeg_read_header (&info, TRUE);
jpeg_start_decompress (&info);
@@ -226,19 +276,23 @@ gdk_load_jpeg (GBytes *input_bytes,
g_assert_not_reached ();
}
color_state = gdk_jpeg_get_color_state (&info);
jpeg_finish_decompress (&info);
jpeg_destroy_decompress (&info);
bytes = g_bytes_new_take (data, stride * height);
texture = gdk_memory_texture_new (width, height,
format,
bytes, stride);
texture = gdk_memory_texture_new_with_color_state (width, height,
format,
color_state,
bytes, stride);
gdk_color_state_unref (color_state);
g_bytes_unref (bytes);
gdk_profiler_end_mark (before, "Load jpeg", NULL);
return texture;
}
@@ -257,9 +311,11 @@ gdk_save_jpeg (GdkTexture *texture)
gsize texstride;
guchar *row;
int width, height;
GdkColorState *color_state;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
color_state = gdk_texture_get_color_state (texture);
info.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = fatal_error_handler;
@@ -298,6 +354,8 @@ gdk_save_jpeg (GdkTexture *texture)
jpeg_start_compress (&info, TRUE);
gdk_jpeg_set_color_state (&info, color_state);
while (info.next_scanline < info.image_height)
{
row = (guchar *) texdata + info.next_scanline * texstride;

View File

@@ -20,11 +20,14 @@
#include "gdkpngprivate.h"
#include <glib/gi18n-lib.h>
#include "gdkcolorstateprivate.h"
#include "gdkcolorstateprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytexture.h"
#include "gdkprofilerprivate.h"
#include "gdktexturedownloaderprivate.h"
#include "gsk/gl/fp16private.h"
#include <png.h>
#include <stdio.h>
@@ -126,6 +129,143 @@ png_simple_warning_callback (png_structp png,
{
}
/* }}} */
/* {{{ Color profile handling */
typedef struct
{
gboolean cicp_chunk_read;
int color_primaries;
int transfer_function;
int matrix_coefficients;
int full_range;
} CICPData;
static int
png_read_chunk_func (png_structp png,
png_unknown_chunkp chunk)
{
if (strcmp ((char *) chunk->name, "cICP") == 0 &&
chunk->size == 4)
{
CICPData *cicp = png_get_user_chunk_ptr (png);
cicp->cicp_chunk_read = TRUE;
cicp->color_primaries = chunk->data[0];
cicp->transfer_function = chunk->data[1];
cicp->matrix_coefficients = chunk->data[2];
cicp->full_range = chunk->data[3];
return 1;
}
return 0;
}
static GdkColorState *
gdk_png_get_color_state (png_struct *png,
png_info *info)
{
GdkColorState *color_state;
guchar *icc_data;
png_uint_32 icc_len;
char *name;
CICPData *cicp;
int intent;
cicp = png_get_user_chunk_ptr (png);
if (cicp->cicp_chunk_read)
{
color_state = gdk_color_state_new_from_cicp_data (cicp->color_primaries,
cicp->transfer_function,
cicp->matrix_coefficients,
cicp->full_range);
if (color_state)
{
g_debug ("Color state from cICP data: %s", gdk_color_state_get_name (color_state));
return color_state;
}
else
{
g_debug ("Failed to create color state from cICP data: %d/%d/%d %d",
cicp->color_primaries,
cicp->transfer_function,
cicp->matrix_coefficients,
cicp->full_range);
}
}
if (png_get_iCCP (png, info, &name, NULL, &icc_data, &icc_len))
{
GBytes *bytes = g_bytes_new (icc_data, icc_len);
color_state = gdk_color_state_new_from_icc_profile (bytes, NULL);
g_bytes_unref (bytes);
if (color_state)
return color_state;
}
if (png_get_sRGB (png, info, &intent))
return GDK_COLOR_STATE_SRGB;
/* If neither of those is valid, the result is sRGB */
if (!png_get_valid (png, info, PNG_INFO_gAMA) &&
!png_get_valid (png, info, PNG_INFO_cHRM))
return GDK_COLOR_STATE_SRGB;
g_debug ("Failed to find color state, assuming SRGB");
return GDK_COLOR_STATE_SRGB;
}
static void
gdk_png_set_color_state (png_struct *png,
png_info *info,
GdkColorState *color_state,
png_byte *chunk_data)
{
int cp, tc, mc;
gboolean fr;
GBytes *bytes;
if (gdk_color_state_save_to_cicp_data (color_state, &cp, &tc, &mc, &fr, NULL))
{
png_unknown_chunk chunk = {
.name = { 'c', 'I', 'C', 'P', '\0' },
.data = chunk_data,
.size = 4,
.location = PNG_HAVE_IHDR,
};
chunk_data[0] = (png_byte)cp;
chunk_data[1] = (png_byte)tc;
chunk_data[2] = (png_byte)mc;
chunk_data[3] = (png_byte)fr;
png_set_unknown_chunks (png, info, &chunk, 1);
}
/* Since most tools don't understand cicp, we save an icc profile as well */
bytes = gdk_color_state_save_to_icc_profile (color_state, NULL);
if (bytes)
{
png_set_iCCP (png, info,
"ICC profile",
0,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
g_bytes_unref (bytes);
}
/* For good measure, we add an sRGB chunk too */
if (color_state == GDK_COLOR_STATE_SRGB)
png_set_sRGB (png, info, PNG_sRGB_INTENT_PERCEPTUAL);
}
/* }}} */
/* {{{ Public API */
@@ -147,8 +287,11 @@ gdk_load_png (GBytes *bytes,
guchar *buffer = NULL;
guchar **row_pointers = NULL;
GBytes *out_bytes;
GdkColorState *color_state;
GdkTexture *texture;
int bpp;
CICPData cicp = { FALSE, };
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
io.data = (guchar *)g_bytes_get_data (bytes, &io.size);
@@ -169,6 +312,7 @@ gdk_load_png (GBytes *bytes,
g_error ("Out of memory");
png_set_read_fn (png, &io, png_read_func);
png_set_read_user_chunk_fn (png, &cicp, png_read_chunk_func);
if (sigsetjmp (png_jmpbuf (png), 1))
{
@@ -266,6 +410,8 @@ gdk_load_png (GBytes *bytes,
return NULL;
}
color_state = gdk_png_get_color_state (png, info);
bpp = gdk_memory_format_bytes_per_pixel (format);
if (!g_size_checked_mul (&stride, width, bpp) ||
!g_size_checked_add (&stride, stride, (8 - stride % 8) % 8))
@@ -281,6 +427,7 @@ gdk_load_png (GBytes *bytes,
if (!buffer || !row_pointers)
{
gdk_color_state_unref (color_state);
g_free (buffer);
g_free (row_pointers);
png_destroy_read_struct (&png, &info, NULL);
@@ -297,8 +444,11 @@ gdk_load_png (GBytes *bytes,
png_read_end (png, info);
out_bytes = g_bytes_new_take (buffer, height * stride);
texture = gdk_memory_texture_new (width, height, format, out_bytes, stride);
texture = gdk_memory_texture_new_with_color_state (width, height,
format, color_state,
out_bytes, stride);
g_bytes_unref (out_bytes);
gdk_color_state_unref (color_state);
if (options && png_get_text (png, info, &text, &num_texts))
{
@@ -337,11 +487,14 @@ gdk_save_png (GdkTexture *texture)
GBytes *bytes;
gsize stride;
const guchar *data;
GdkColorState *color_state;
int png_format;
int depth;
png_byte chunk_data[4];
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
color_state = gdk_texture_get_color_state (texture);
format = gdk_texture_get_format (texture);
switch (format)
@@ -436,6 +589,10 @@ gdk_save_png (GdkTexture *texture)
/* 2^31-1 is the maximum size for PNG files */
png_set_user_limits (png, (1u << 31) - 1, (1u << 31) - 1);
png_set_keep_unknown_chunks (png, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);
png_set_option (png, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
info = png_create_info_struct (png);
if (!info)
{
@@ -465,6 +622,8 @@ gdk_save_png (GdkTexture *texture)
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
gdk_png_set_color_state (png, info, color_state, chunk_data);
png_write_info (png, info);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN

View File

@@ -24,6 +24,7 @@
#include "gdkmemorytexture.h"
#include "gdkprofilerprivate.h"
#include "gdktexturedownloaderprivate.h"
#include "gdkcolorstateprivate.h"
#include <tiffio.h>
@@ -219,6 +220,53 @@ tiff_open_write (GBytes **result)
NULL, NULL);
}
/* }}} */
/* {{{ Color profile handling */
static GdkColorState *
gdk_tiff_get_color_state (TIFF *tiff)
{
GdkColorState *color_state;
const char *icc_data;
guint icc_len;
if (TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_len, &icc_data))
{
GBytes *icc_bytes;
icc_bytes = g_bytes_new (icc_data, icc_len);
color_state = gdk_color_state_new_from_icc_profile (icc_bytes, NULL);
g_bytes_unref (icc_bytes);
if (!color_state)
{
g_debug ("Failed to load icc profile, assuming SRGB");
color_state = GDK_COLOR_STATE_SRGB;
}
}
else
color_state = GDK_COLOR_STATE_SRGB;
return color_state;
}
static void
gdk_tiff_set_color_state (TIFF *tiff,
GdkColorState *color_state)
{
GBytes *bytes;
bytes = gdk_color_state_save_to_icc_profile (color_state, NULL);
if (bytes)
{
TIFFSetField (tiff, TIFFTAG_ICCPROFILE,
g_bytes_get_size (bytes),
g_bytes_get_data (bytes, NULL));
g_bytes_unref (bytes);
}
}
/* }}} */
/* {{{ Public API */
@@ -282,6 +330,7 @@ gdk_save_tiff (GdkTexture *texture)
GBytes *bytes, *result = NULL;
GdkTextureDownloader downloader;
GdkMemoryFormat format;
GdkColorState *color_state;
const FormatData *fdata = NULL;
tif = tiff_open_write (&result);
@@ -289,6 +338,7 @@ gdk_save_tiff (GdkTexture *texture)
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
format = gdk_texture_get_format (texture);
color_state = gdk_texture_get_color_state (texture);
fdata = &format_data[format];
if (fdata == NULL)
@@ -308,6 +358,8 @@ gdk_save_tiff (GdkTexture *texture)
TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, fdata->photometric);
TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
gdk_tiff_set_color_state (tif, color_state);
gdk_texture_downloader_init (&downloader, texture);
gdk_texture_downloader_set_format (&downloader, fdata->format);
bytes = gdk_texture_downloader_download_bytes (&downloader, &stride);
@@ -344,6 +396,7 @@ load_fallback (TIFF *tif,
int width, height;
guchar *data;
GBytes *bytes;
GdkColorState *color_state;
GdkTexture *texture;
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width);
@@ -360,14 +413,18 @@ load_fallback (TIFF *tif,
return NULL;
}
color_state = gdk_tiff_get_color_state (tif);
bytes = g_bytes_new_take (data, width * height * 4);
texture = gdk_memory_texture_new (width, height,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
bytes,
width * 4);
texture = gdk_memory_texture_new_with_color_state (width, height,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
color_state,
bytes,
width * 4);
g_bytes_unref (bytes);
gdk_color_state_unref (color_state);
return texture;
}
@@ -390,6 +447,7 @@ gdk_load_tiff (GBytes *input_bytes,
gsize stride;
int bpp;
GBytes *bytes;
GdkColorState *color_state;
GdkTexture *texture;
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
@@ -490,13 +548,16 @@ gdk_load_tiff (GBytes *input_bytes,
line += stride;
}
color_state = gdk_tiff_get_color_state (tif);
bpp = gdk_memory_format_bytes_per_pixel (format);
bytes = g_bytes_new_take (data, width * height * bpp);
texture = gdk_memory_texture_new (width, height,
format,
bytes, width * bpp);
texture = gdk_memory_texture_new_with_color_state (width, height,
format, color_state,
bytes, width * bpp);
g_bytes_unref (bytes);
gdk_color_state_unref (color_state);
TIFFClose (tif);

View File

@@ -6,6 +6,7 @@ gdk_public_sources = files([
'gdkcairo.c',
'gdkcairocontext.c',
'gdkclipboard.c',
'gdkcolorstate.c',
'gdkcontentdeserializer.c',
'gdkcontentformats.c',
'gdkcontentprovider.c',
@@ -75,6 +76,7 @@ gdk_public_headers = files([
'gdkcairo.h',
'gdkcairocontext.h',
'gdkclipboard.h',
'gdkcolorstate.h',
'gdkcontentdeserializer.h',
'gdkcontentformats.h',
'gdkcontentprovider.h',

BIN
gdk/srgb-linear.icc Normal file

Binary file not shown.

BIN
gdk/srgb.icc Normal file

Binary file not shown.

View File

@@ -24,6 +24,7 @@
#include "gdkprofilerprivate.h"
#include <glib/gi18n-lib.h>
#include "gdksurfaceprivate.h"
#include <cairo-xlib.h>
@@ -53,6 +54,9 @@ gdk_x11_surface_get_glx_drawable (GdkSurface *surface)
GdkX11Surface *self = GDK_X11_SURFACE (surface);
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (self));
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
Display *dpy = gdk_x11_display_get_xdisplay (display);
XVisualInfo *visinfo;
int value;
if (self->glx_drawable)
return self->glx_drawable;
@@ -62,6 +66,11 @@ gdk_x11_surface_get_glx_drawable (GdkSurface *surface)
gdk_x11_surface_get_xid (surface),
NULL);
visinfo = glXGetVisualFromFBConfig (dpy, display_x11->glx_config);
glXGetConfig (dpy, visinfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &value);
surface->is_srgb = value != 0;
XFree (visinfo);
return self->glx_drawable;
}
@@ -758,6 +767,17 @@ visual_is_rgba (XVisualInfo *visinfo)
visinfo->visual->blue_mask == 0x0000ff;
}
static gboolean
visual_is_srgb (Display *display,
XVisualInfo *visinfo)
{
int value;
glXGetConfig (display, visinfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &value);
return value != 0;
}
#define MAX_GLX_ATTRS 30
static gboolean
@@ -777,6 +797,7 @@ gdk_x11_display_create_glx_config (GdkX11Display *self,
WITH_STENCIL_AND_DEPTH_BUFFER,
NO_ALPHA,
NO_ALPHA_VISUAL,
NO_SRGB,
PERFECT
} best_features;
int i = 0;
@@ -865,6 +886,20 @@ gdk_x11_display_create_glx_config (GdkX11Display *self,
continue;
}
if (!visual_is_srgb (dpy, visinfo))
{
if (best_features < NO_SRGB)
{
GDK_DISPLAY_DEBUG (display, OPENGL, "Best GLX config is %u for visual 0x%lX with no SRGB", i, visinfo->visualid);
best_features = NO_SRGB;
*out_visual = visinfo->visual;
*out_depth = visinfo->depth;
self->glx_config = configs[i];
}
XFree (visinfo);
continue;
}
GDK_DISPLAY_DEBUG (display, OPENGL, "GLX config %u for visual 0x%lX is the perfect choice", i, visinfo->visualid);
best_features = PERFECT;
*out_visual = visinfo->visual;

View File

@@ -1483,6 +1483,7 @@ memory_format_gl_format (GskGLCommandQueue *self,
gboolean ensure_mipmap,
gboolean *out_can_mipmap,
GLint *gl_internalformat,
GLint *gl_internalsrgbformat,
GLenum *gl_format,
GLenum *gl_type,
GLint gl_swizzle[4])
@@ -1507,6 +1508,7 @@ memory_format_gl_format (GskGLCommandQueue *self,
gdk_memory_format_gl_format (data_format,
gdk_gl_context_get_use_es (self->context),
gl_internalformat,
gl_internalsrgbformat,
gl_format,
gl_type,
gl_swizzle);
@@ -1519,6 +1521,7 @@ memory_format_gl_format (GskGLCommandQueue *self,
gdk_gl_context_get_use_es (self->context),
&alt_format,
gl_internalformat,
gl_internalsrgbformat,
gl_format,
gl_type,
gl_swizzle))
@@ -1534,6 +1537,7 @@ memory_format_gl_format (GskGLCommandQueue *self,
gdk_memory_format_gl_format (alt_format,
gdk_gl_context_get_use_es (self->context),
gl_internalformat,
gl_internalsrgbformat,
gl_format,
gl_type,
gl_swizzle);
@@ -1552,6 +1556,7 @@ memory_format_gl_format (GskGLCommandQueue *self,
gdk_memory_format_gl_format (fallbacks[i],
gdk_gl_context_get_use_es (self->context),
gl_internalformat,
gl_internalsrgbformat,
gl_format,
gl_type,
gl_swizzle);
@@ -1670,7 +1675,7 @@ gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self,
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
int width, height;
GdkMemoryFormat data_format;
GLint gl_internalformat;
GLint gl_internalformat, gl_internalsrgbformat;
GLenum gl_format;
GLenum gl_type;
GLint gl_swizzle[4];
@@ -1713,6 +1718,7 @@ gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self,
ensure_mipmap,
out_can_mipmap,
&gl_internalformat,
&gl_internalsrgbformat,
&gl_format,
&gl_type,
gl_swizzle);

View File

@@ -30,6 +30,13 @@
#include "gskdebugprivate.h"
#ifdef HAVE_PANGOFT
#include <pango/pangofc-font.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_PARAMETER_TAGS_H
#endif
#define MAX_GLYPH_SIZE 128
G_DEFINE_TYPE (GskGLGlyphLibrary, gsk_gl_glyph_library, GSK_TYPE_GL_TEXTURE_LIBRARY)
@@ -218,6 +225,16 @@ render_glyph (cairo_surface_t *surface,
cairo_t *cr;
PangoGlyphString glyph_string;
PangoGlyphInfo glyph_info;
#ifdef HAVE_PANGOFT
FT_Face face;
FT_Bool darken = 1;
FT_Parameter property = { FT_PARAM_TAG_STEM_DARKENING, &darken };
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
face = pango_fc_font_lock_face (PANGO_FC_FONT (key->font));
G_GNUC_END_IGNORE_DEPRECATIONS
FT_Face_Properties (face, 1, &property);
#endif
g_assert (surface != NULL);
@@ -236,6 +253,12 @@ render_glyph (cairo_surface_t *surface,
cairo_destroy (cr);
cairo_surface_flush (surface);
#ifdef HAVE_PANGOFT
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
pango_fc_font_unlock_face (PANGO_FC_FONT (key->font));
G_GNUC_END_IGNORE_DEPRECATIONS
#endif
}
static void

View File

@@ -102,3 +102,8 @@ GSK_GL_DEFINE_PROGRAM_NO_CLIP (external,
GSK_GL_DEFINE_PROGRAM_NO_CLIP (premultiply,
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("premultiply.glsl")),
GSK_GL_NO_UNIFORMS)
GSK_GL_DEFINE_PROGRAM (colorconvert,
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("colorconvert.glsl")),
GSK_GL_ADD_UNIFORM (1, TO_LINEAR, u_to_linear))

View File

@@ -34,6 +34,7 @@
#include <gdk/gdkglcontextprivate.h>
#include <gdk/gdksurfaceprivate.h>
#include <gdk/gdksubsurfaceprivate.h>
#include <gdk/gdkcolorstateprivate.h>
#include <glib/gi18n-lib.h>
#include <gsk/gskdebugprivate.h>
#include <gsk/gskrendererprivate.h>
@@ -362,6 +363,7 @@ gsk_gl_renderer_render (GskRenderer *renderer,
GdkSurface *surface;
gboolean clear_framebuffer;
float scale;
GdkColorState *target_color_state;
g_assert (GSK_IS_GL_RENDERER (renderer));
g_assert (root != NULL);
@@ -384,6 +386,17 @@ gsk_gl_renderer_render (GskRenderer *renderer,
gsk_render_node_get_preferred_depth (root),
update_area);
if (gdk_surface_get_gl_is_srgb (surface))
{
g_debug ("Relying on GL to do srgb-linear->srgb conversion");
target_color_state = GDK_COLOR_STATE_SRGB_LINEAR;
}
else
{
g_debug ("Using an offscreen for srgb-linear->srgb conversion");
target_color_state = GDK_COLOR_STATE_SRGB;
}
gdk_gl_context_make_current (self->context);
/* Must be called *AFTER* gdk_draw_context_begin_frame() */
@@ -392,7 +405,7 @@ gsk_gl_renderer_render (GskRenderer *renderer,
gsk_gl_driver_begin_frame (self->driver, self->command_queue);
job = gsk_gl_render_job_new (self->driver, &viewport, scale, render_region, 0, clear_framebuffer);
gsk_gl_render_job_render (job, root);
gsk_gl_render_job_render (job, root, target_color_state);
gsk_gl_driver_end_frame (self->driver);
gsk_gl_render_job_free (job);
@@ -476,7 +489,7 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
{
gsk_gl_driver_begin_frame (self->driver, self->command_queue);
job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, render_target->framebuffer_id, TRUE);
gsk_gl_render_job_render_flipped (job, root);
gsk_gl_render_job_render_flipped (job, root, GDK_COLOR_STATE_SRGB);
texture_id = gsk_gl_driver_release_render_target (self->driver, render_target, FALSE);
texture = gsk_gl_driver_create_gdk_texture (self->driver, texture_id, gdk_format);
gsk_gl_driver_end_frame (self->driver);

View File

@@ -33,6 +33,7 @@
#include <gdk/gdkdmabuftexture.h>
#include <gdk/gdksurfaceprivate.h>
#include <gdk/gdksubsurfaceprivate.h>
#include <gdk/gdkcolorstateprivate.h>
#include <gsk/gsktransformprivate.h>
#include <gsk/gskroundedrectprivate.h>
#include <gsk/gskrectprivate.h>
@@ -972,11 +973,28 @@ gsk_gl_render_job_update_clip (GskGLRenderJob *job,
return TRUE;
}
static inline float
srgb_inverse_transfer_function (float v)
{
if (v >= 0.04045)
return powf (((v + 0.055)/(1 + 0.055)), 2.4);
else
return v / 12.92;
}
static inline void
rgba_to_half (const GdkRGBA *rgba,
guint16 h[4])
{
float_to_half4 ((const float *)rgba, h);
float v[4];
v[0] = srgb_inverse_transfer_function (rgba->red);
v[1] = srgb_inverse_transfer_function (rgba->green);
v[2] = srgb_inverse_transfer_function (rgba->blue);
v[3] = rgba->alpha;
float_to_half4 (v, h);
}
/* fill_vertex_data */
@@ -3677,8 +3695,11 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
g_assert (offscreen.texture_id);
g_assert (offscreen.was_offscreen == FALSE);
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)))
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, colorconvert)))
{
gsk_gl_program_set_uniform1i (job->current_program,
UNIFORM_TO_LINEAR, 0,
1);
gsk_gl_program_set_uniform_texture_with_sync (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
@@ -3704,7 +3725,7 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
g_assert (slices != NULL);
g_assert (n_slices > 0);
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)))
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, colorconvert)))
{
for (unsigned int i = 0; i < n_slices; i++)
{
@@ -3718,6 +3739,9 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
if (i > 0)
gsk_gl_render_job_split_draw (job);
gsk_gl_program_set_uniform1i (job->current_program,
UNIFORM_TO_LINEAR, 0,
1);
gsk_gl_program_set_uniform_texture_with_filter (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
@@ -3832,8 +3856,11 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
u1 = (clip_rect.origin.x + clip_rect.size.width - bounds->origin.x) / bounds->size.width;
v1 = (clip_rect.origin.y + clip_rect.size.height - bounds->origin.y) / bounds->size.height;
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)))
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, colorconvert)))
{
gsk_gl_program_set_uniform1i (job->current_program,
UNIFORM_TO_LINEAR, 0,
1);
gsk_gl_program_set_uniform_texture_with_sync (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
@@ -3859,7 +3886,7 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
gsk_gl_driver_slice_texture (job->driver, texture, need_mipmap, &slices, &n_slices);
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)))
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, colorconvert)))
{
for (guint i = 0; i < n_slices; i++)
{
@@ -3877,6 +3904,9 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
if (i > 0)
gsk_gl_render_job_split_draw (job);
gsk_gl_program_set_uniform1i (job->current_program,
UNIFORM_TO_LINEAR, 0,
1);
gsk_gl_program_set_uniform_texture_with_filter (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
@@ -3910,8 +3940,11 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
gsk_gl_driver_cache_texture (job->driver, &key, texture_id);
render_texture:
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)))
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, colorconvert)))
{
gsk_gl_program_set_uniform1i (job->current_program,
UNIFORM_TO_LINEAR, 0,
1);
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
@@ -4464,7 +4497,8 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
void
gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
GskRenderNode *root)
GskRenderNode *root,
GdkColorState *target_color_state)
{
graphene_matrix_t proj;
guint framebuffer_id;
@@ -4506,8 +4540,17 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
gsk_gl_render_job_set_alpha (job, 1.0f);
gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)))
GskGLProgram *program;
if (target_color_state == GDK_COLOR_STATE_SRGB)
program = CHOOSE_PROGRAM (job, colorconvert);
else
program = CHOOSE_PROGRAM (job, blit);
if (gsk_gl_render_job_begin_draw (job, program))
{
if (target_color_state == GDK_COLOR_STATE_SRGB)
gsk_gl_program_set_uniform1i (job->current_program, UNIFORM_TO_LINEAR, 0, 0);
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
@@ -4528,7 +4571,8 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
void
gsk_gl_render_job_render (GskGLRenderJob *job,
GskRenderNode *root)
GskRenderNode *root,
GdkColorState *target_color_state)
{
G_GNUC_UNUSED gint64 start_time;
float scale;
@@ -4551,7 +4595,38 @@ gsk_gl_render_job_render (GskGLRenderJob *job,
gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
if (job->clear_framebuffer)
gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
gsk_gl_render_job_visit_node (job, root);
if (target_color_state == GDK_COLOR_STATE_SRGB_LINEAR)
{
gsk_gl_render_job_visit_node (job, root);
}
else
{
GskGLRenderOffscreen offscreen = {0};
offscreen.bounds = &root->bounds;
offscreen.force_offscreen = TRUE;
offscreen.reset_clip = TRUE;
offscreen.do_not_cache = TRUE;
gsk_gl_render_job_visit_node_with_offscreen (job, root, &offscreen);
g_assert (offscreen.texture_id);
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, colorconvert)))
{
gsk_gl_program_set_uniform1i (job->current_program, UNIFORM_TO_LINEAR, 0, 0);
gsk_gl_program_set_uniform_texture (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id);
job->source_is_glyph_atlas = FALSE;
gsk_gl_render_job_draw_offscreen_rect (job, &root->bounds);
gsk_gl_render_job_end_draw (job);
}
}
gdk_gl_context_pop_debug_group (job->command_queue->context);
gdk_profiler_end_mark (start_time, "Build GL command queue", "");

View File

@@ -30,7 +30,9 @@ GskGLRenderJob *gsk_gl_render_job_new (GskGLDriver *dri
gboolean clear_framebuffer);
void gsk_gl_render_job_free (GskGLRenderJob *job);
void gsk_gl_render_job_render (GskGLRenderJob *job,
GskRenderNode *root);
GskRenderNode *root,
GdkColorState *color_state);
void gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
GskRenderNode *root);
GskRenderNode *root,
GdkColorState *color_state);

View File

@@ -0,0 +1,63 @@
// VERTEX_SHADER:
// colorconvert.glsl
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
}
// FRAGMENT_SHADER:
// colorconvert.glsl
uniform int u_to_linear;
float
srgb_transfer_function (float v)
{
if (v >= 0.04045)
return pow (((v + 0.055)/(1.0 + 0.055)), 2.4);
else
return v / 12.92;
}
float
srgb_inverse_transfer_function (float v)
{
if (v > 0.0031308)
return 1.055 * pow (v, 1.0/2.4) - 0.055;
else
return 12.92 * v;
}
vec4
srgb_to_linear_srgb (vec4 color)
{
return vec4 (srgb_transfer_function (color.r),
srgb_transfer_function (color.g),
srgb_transfer_function (color.b),
color.a);
}
vec4
linear_srgb_to_srgb (vec4 color)
{
return vec4 (srgb_inverse_transfer_function (color.r),
srgb_inverse_transfer_function (color.g),
srgb_inverse_transfer_function (color.b),
color.a);
}
void main() {
vec4 color = GskTexture(u_source, vUv);
if (color.a != 0.0)
color.rgb /= color.a;
if (u_to_linear != 0)
color = srgb_to_linear_srgb (color);
else
color = linear_srgb_to_srgb (color);
gskSetOutputColor(gsk_scaled_premultiply(color, u_alpha));
}

View File

@@ -10,6 +10,7 @@
#include "gdk/gdkdisplayprivate.h"
#include "gdk/gdkglcontextprivate.h"
#include "gdk/gdkprofilerprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#include <glib/gi18n-lib.h>
@@ -76,6 +77,7 @@ gsk_gl_device_create_offscreen_image (GskGpuDevice *device,
return gsk_gl_image_new (self,
gdk_memory_depth_get_format (depth),
GDK_COLOR_STATE_SRGB_LINEAR,
GSK_GPU_IMAGE_RENDERABLE | GSK_GPU_IMAGE_FILTERABLE,
width,
height);
@@ -85,6 +87,7 @@ static GskGpuImage *
gsk_gl_device_create_upload_image (GskGpuDevice *device,
gboolean with_mipmap,
GdkMemoryFormat format,
GdkColorState *color_state,
gsize width,
gsize height)
{
@@ -92,6 +95,7 @@ gsk_gl_device_create_upload_image (GskGpuDevice *device,
return gsk_gl_image_new (self,
format,
color_state,
0,
width,
height);
@@ -107,6 +111,7 @@ gsk_gl_device_create_download_image (GskGpuDevice *device,
return gsk_gl_image_new (self,
gdk_memory_depth_get_format (depth),
GDK_COLOR_STATE_SRGB_LINEAR,
GSK_GPU_IMAGE_RENDERABLE,
width,
height);
@@ -121,6 +126,7 @@ gsk_gl_device_create_atlas_image (GskGpuDevice *device,
return gsk_gl_image_new (self,
GDK_MEMORY_DEFAULT,
GDK_COLOR_STATE_SRGB_LINEAR,
GSK_GPU_IMAGE_RENDERABLE,
width,
height);
@@ -635,6 +641,7 @@ gsk_gl_device_find_gl_format (GskGLDevice *self,
GdkMemoryFormat *out_format,
GskGpuImageFlags *out_flags,
GLint *out_gl_internal_format,
GLint *out_gl_internal_srgb_format,
GLenum *out_gl_format,
GLenum *out_gl_type,
GLint out_swizzle[4])
@@ -654,6 +661,7 @@ gsk_gl_device_find_gl_format (GskGLDevice *self,
gdk_memory_format_gl_format (format,
gdk_gl_context_get_use_es (context),
out_gl_internal_format,
out_gl_internal_srgb_format,
out_gl_format,
out_gl_type,
out_swizzle);
@@ -665,6 +673,7 @@ gsk_gl_device_find_gl_format (GskGLDevice *self,
gdk_gl_context_get_use_es (context),
&alt_format,
out_gl_internal_format,
out_gl_internal_srgb_format,
out_gl_format,
out_gl_type,
out_swizzle) &&
@@ -688,6 +697,7 @@ gsk_gl_device_find_gl_format (GskGLDevice *self,
gdk_memory_format_gl_format (fallbacks[i],
gdk_gl_context_get_use_es (context),
out_gl_internal_format,
out_gl_internal_srgb_format,
out_gl_format,
out_gl_type,
out_swizzle);

View File

@@ -26,6 +26,7 @@ void gsk_gl_device_find_gl_format (GskGLDe
GdkMemoryFormat *out_format,
GskGpuImageFlags *out_flags,
GLint *out_gl_internal_format,
GLint *out_gl_internal_srgb_format,
GLenum *out_gl_format,
GLenum *out_gl_type,
GLint out_swizzle[4]);

View File

@@ -1,9 +1,10 @@
#include "config.h"
#include "config.h"
#include "gskglimageprivate.h"
#include "gdk/gdkdisplayprivate.h"
#include "gdk/gdkglcontextprivate.h"
#include "gdk/gdkcolorstateprivate.h"
struct _GskGLImage
{
@@ -73,11 +74,13 @@ gsk_gl_image_new_backbuffer (GskGLDevice *device,
GdkGLContext *context,
GdkMemoryFormat format,
gsize width,
gsize height)
gsize height,
gboolean is_srgb)
{
GskGLImage *self;
GskGpuImageFlags flags;
GLint swizzle[4];
GLint gl_internal_format, gl_internal_srgb_format;
self = g_object_new (GSK_TYPE_GL_IMAGE, NULL);
@@ -87,11 +90,25 @@ gsk_gl_image_new_backbuffer (GskGLDevice *device,
0,
&format,
&flags,
&self->gl_internal_format,
&gl_internal_format,
&gl_internal_srgb_format,
&self->gl_format,
&self->gl_type,
swizzle);
if (is_srgb)
{
if (gl_internal_srgb_format != -1)
self->gl_internal_format = gl_internal_srgb_format;
else /* FIXME: not really correct */
self->gl_internal_format = gl_internal_format;
flags |= GSK_GPU_IMAGE_SRGB;
}
else
{
self->gl_internal_format = gl_internal_format;
}
gsk_gpu_image_setup (GSK_GPU_IMAGE (self), flags, format, width, height);
/* texture_id == 0 means backbuffer */
@@ -109,6 +126,7 @@ gsk_gl_image_new_backbuffer (GskGLDevice *device,
GskGpuImage *
gsk_gl_image_new (GskGLDevice *device,
GdkMemoryFormat format,
GdkColorState *color_state,
GskGpuImageFlags required_flags,
gsize width,
gsize height)
@@ -116,6 +134,7 @@ gsk_gl_image_new (GskGLDevice *device,
GskGLImage *self;
GLint swizzle[4];
GskGpuImageFlags flags;
GLint gl_internal_format, gl_internal_srgb_format;
gsize max_size;
max_size = gsk_gpu_device_get_max_image_size (GSK_GPU_DEVICE (device));
@@ -129,11 +148,23 @@ gsk_gl_image_new (GskGLDevice *device,
required_flags,
&format,
&flags,
&self->gl_internal_format,
&gl_internal_format,
&gl_internal_srgb_format,
&self->gl_format,
&self->gl_type,
swizzle);
if (gl_internal_srgb_format != -1 &&
gdk_color_state_equal (color_state, GDK_COLOR_STATE_SRGB))
{
self->gl_internal_format = gl_internal_srgb_format;
flags |= GSK_GPU_IMAGE_SRGB;
}
else
{
self->gl_internal_format = gl_internal_format;
}
gsk_gpu_image_setup (GSK_GPU_IMAGE (self),
flags,
format,
@@ -177,6 +208,7 @@ gsk_gl_image_new_for_texture (GskGLDevice *device,
GdkMemoryFormat format, real_format;
GskGpuImageFlags flags;
GskGLImage *self;
GLint gl_internal_format, gl_internal_srgb_format;
GLint swizzle[4];
format = gdk_texture_get_format (owner);
@@ -188,10 +220,14 @@ gsk_gl_image_new_for_texture (GskGLDevice *device,
0,
&real_format,
&flags,
&self->gl_internal_format,
&gl_internal_format,
&gl_internal_srgb_format,
&self->gl_format,
&self->gl_type,
swizzle);
self->gl_internal_format = gl_internal_format;
if (format != real_format)
flags = GSK_GPU_IMAGE_NO_BLIT |
(gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT ? GSK_GPU_IMAGE_STRAIGHT_ALPHA : 0);

View File

@@ -14,9 +14,11 @@ GskGpuImage * gsk_gl_image_new_backbuffer (GskGLDe
GdkGLContext *context,
GdkMemoryFormat format,
gsize width,
gsize height);
gsize height,
gboolean converts_srgb);
GskGpuImage * gsk_gl_image_new (GskGLDevice *device,
GdkMemoryFormat format,
GdkColorState *color_state,
GskGpuImageFlags required_flags,
gsize width,
gsize height);

View File

@@ -14,7 +14,7 @@ struct _GskGpuClearOp
GskGpuOp op;
cairo_rectangle_int_t rect;
GdkRGBA color;
float color[4];
};
static void
@@ -29,23 +29,14 @@ gsk_gpu_clear_op_print (GskGpuOp *op,
guint indent)
{
GskGpuClearOp *self = (GskGpuClearOp *) op;
float rgba[4];
gsk_gpu_print_op (string, indent, "clear");
gsk_gpu_print_int_rect (string, &self->rect);
gsk_gpu_rgba_to_float (&self->color, rgba);
gsk_gpu_print_rgba (string, rgba);
gsk_gpu_print_rgba (string, self->color);
gsk_gpu_print_newline (string);
}
#ifdef GDK_RENDERING_VULKAN
static void
gsk_gpu_init_clear_value (VkClearValue *value,
const GdkRGBA *rgba)
{
gsk_gpu_rgba_to_float (rgba, value->color.float32);
}
static GskGpuOp *
gsk_gpu_clear_op_vk_command (GskGpuOp *op,
GskGpuFrame *frame,
@@ -54,7 +45,7 @@ gsk_gpu_clear_op_vk_command (GskGpuOp *op,
GskGpuClearOp *self = (GskGpuClearOp *) op;
VkClearValue clear_value;
gsk_gpu_init_clear_value (&clear_value, &self->color);
memcpy (clear_value.color.float32, self->color, sizeof (float) * 4);
vkCmdClearAttachments (state->vk_command_buffer,
1,
@@ -92,7 +83,7 @@ gsk_gpu_clear_op_gl_command (GskGpuOp *op,
else
glScissor (self->rect.x, self->rect.y, self->rect.width, self->rect.height);
glClearColor (self->color.red, self->color.green, self->color.blue, self->color.alpha);
glClearColor (self->color[0], self->color[1], self->color[2], self->color[3]);
glClear (GL_COLOR_BUFFER_BIT);
glScissor (scissor[0], scissor[1], scissor[2], scissor[3]);
@@ -121,5 +112,5 @@ gsk_gpu_clear_op (GskGpuFrame *frame,
self = (GskGpuClearOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_CLEAR_OP_CLASS);
self->rect = *rect;
self->color = *color;
gsk_gpu_rgba_to_float (color, self->color);
}

View File

@@ -0,0 +1,86 @@
#include "config.h"
#include "gskgpucolorconvertopprivate.h"
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
#include "gskrectprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#include "gpu/shaders/gskgpucolorconvertinstance.h"
typedef struct _GskGpuColorConvertOp GskGpuColorConvertOp;
struct _GskGpuColorConvertOp
{
GskGpuShaderOp op;
};
static guint
gsk_gpu_color_conversion (GdkColorState *from,
GdkColorState *to)
{
if (from == to)
return 0;
return GDK_DEFAULT_COLOR_STATE_ID (from) | (GDK_DEFAULT_COLOR_STATE_ID (to) << 16);
}
static void
gsk_gpu_color_convert_op_print_instance (GskGpuShaderOp *shader,
gpointer instance_,
GString *string)
{
GskGpuColorconvertInstance *instance = (GskGpuColorconvertInstance *) instance_;
gsk_gpu_print_rect (string, instance->rect);
gsk_gpu_print_image_descriptor (string, shader->desc, instance->tex_id);
gsk_gpu_print_color_conversion (string, shader->variation);
}
static const GskGpuShaderOpClass GSK_GPU_COLOR_CONVERT_OP_CLASS = {
{
GSK_GPU_OP_SIZE (GskGpuColorConvertOp),
GSK_GPU_STAGE_SHADER,
gsk_gpu_shader_op_finish,
gsk_gpu_shader_op_print,
#ifdef GDK_RENDERING_VULKAN
gsk_gpu_shader_op_vk_command,
#endif
gsk_gpu_shader_op_gl_command
},
"gskgpucolorconvert",
sizeof (GskGpuColorconvertInstance),
#ifdef GDK_RENDERING_VULKAN
&gsk_gpu_colorconvert_info,
#endif
gsk_gpu_color_convert_op_print_instance,
gsk_gpu_colorconvert_setup_attrib_locations,
gsk_gpu_colorconvert_setup_vao
};
void
gsk_gpu_color_convert_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GdkColorState *from,
GdkColorState *to,
GskGpuDescriptors *desc,
guint32 descriptor,
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect)
{
GskGpuColorconvertInstance *instance;
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_COLOR_CONVERT_OP_CLASS,
gsk_gpu_color_conversion (from, to),
clip,
desc,
&instance);
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_rect_to_float (tex_rect, offset, instance->tex_rect);
instance->tex_id = descriptor;
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include "gskgpushaderopprivate.h"
#include <graphene.h>
G_BEGIN_DECLS
void gsk_gpu_color_convert_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GdkColorState *from,
GdkColorState *to,
GskGpuDescriptors *desc,
guint32 descriptor,
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect);
G_END_DECLS

View File

@@ -12,6 +12,7 @@
#include "gsk/gskdebugprivate.h"
#include "gsk/gskprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#define MAX_SLICES_PER_ATLAS 64
@@ -252,6 +253,9 @@ struct _GskGpuCachedTexture
GdkTexture *texture;
GskGpuImage *image;
GdkColorState *color_state;
GskGpuImage *image2;
GdkColorState *color_state2;
};
static void
@@ -263,6 +267,9 @@ gsk_gpu_cached_texture_free (GskGpuDevice *device,
gpointer key, value;
g_clear_object (&self->image);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
g_clear_object (&self->image2);
g_clear_pointer (&self->color_state2, gdk_color_state_unref);
if (g_hash_table_steal_extended (priv->texture_cache, self->texture, &key, &value))
{
@@ -325,9 +332,10 @@ gsk_gpu_cached_texture_destroy_cb (gpointer data)
}
static GskGpuCachedTexture *
gsk_gpu_cached_texture_new (GskGpuDevice *device,
GdkTexture *texture,
GskGpuImage *image)
gsk_gpu_cached_texture_new (GskGpuDevice *device,
GdkTexture *texture,
GskGpuImage *image,
GdkColorState *color_state)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (device);
GskGpuCachedTexture *self;
@@ -340,6 +348,9 @@ gsk_gpu_cached_texture_new (GskGpuDevice *device,
self = gsk_gpu_cached_new (device, &GSK_GPU_CACHED_TEXTURE_CLASS, NULL);
self->texture = texture;
self->image = g_object_ref (image);
self->color_state = gdk_color_state_ref (color_state);
self->image2 = NULL;
self->color_state2 = NULL;
((GskGpuCached *)self)->pixels = gsk_gpu_image_get_width (image) * gsk_gpu_image_get_height (image);
self->dead_pixels_counter = &priv->dead_texture_pixels;
self->use_count = 2;
@@ -696,13 +707,14 @@ gsk_gpu_device_create_offscreen_image (GskGpuDevice *self,
}
GskGpuImage *
gsk_gpu_device_create_upload_image (GskGpuDevice *self,
gboolean with_mipmap,
GdkMemoryFormat format,
gsize width,
gsize height)
gsk_gpu_device_create_upload_image (GskGpuDevice *self,
gboolean with_mipmap,
GdkMemoryFormat format,
GdkColorState *color_state,
gsize width,
gsize height)
{
return GSK_GPU_DEVICE_GET_CLASS (self)->create_upload_image (self, with_mipmap, format, width, height);
return GSK_GPU_DEVICE_GET_CLASS (self)->create_upload_image (self, with_mipmap, format, color_state, width, height);
}
void
@@ -850,34 +862,65 @@ gsk_gpu_device_add_atlas_image (GskGpuDevice *self,
}
GskGpuImage *
gsk_gpu_device_lookup_texture_image (GskGpuDevice *self,
GdkTexture *texture,
gint64 timestamp)
gsk_gpu_device_lookup_texture_image (GskGpuDevice *self,
GdkTexture *texture,
GdkColorState *color_state,
gint64 timestamp)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
GskGpuCachedTexture *cache;
GskGpuImage *image;
cache = gdk_texture_get_render_data (texture, self);
if (cache == NULL)
cache = g_hash_table_lookup (priv->texture_cache, texture);
if (!cache || !cache->image || gsk_gpu_cached_texture_is_invalid (cache))
if (!cache || gsk_gpu_cached_texture_is_invalid (cache))
return NULL;
if (gdk_color_state_equal (color_state, cache->color_state))
image = cache->image;
else if (cache->color_state2 && gdk_color_state_equal (color_state, cache->color_state2))
image = cache->image2;
else
return NULL;
gsk_gpu_cached_use (self, (GskGpuCached *) cache, timestamp);
return g_object_ref (cache->image);
return g_object_ref (image);
}
void
gsk_gpu_device_cache_texture_image (GskGpuDevice *self,
GdkTexture *texture,
gint64 timestamp,
GskGpuImage *image)
gsk_gpu_device_cache_texture_image (GskGpuDevice *self,
GdkTexture *texture,
gint64 timestamp,
GskGpuImage *image,
GdkColorState *color_state)
{
GskGpuCachedTexture *cache;
cache = gsk_gpu_cached_texture_new (self, texture, image);
cache = gdk_texture_get_render_data (texture, self);
if (cache)
{
if (gdk_color_state_equal (color_state, gdk_texture_get_color_state (texture)))
{
g_clear_pointer (&cache->color_state, gdk_color_state_unref);
g_clear_object (&cache->image);
cache->color_state = gdk_color_state_ref (color_state);
cache->image = g_object_ref (image);
}
else
{
g_clear_pointer (&cache->color_state2, gdk_color_state_unref);
g_clear_object (&cache->image2);
cache->color_state2 = gdk_color_state_ref (color_state);
cache->image2 = g_object_ref (image);
}
}
else
{
cache = gsk_gpu_cached_texture_new (self, texture, image, color_state);
}
gsk_gpu_cached_use (self, (GskGpuCached *) cache, timestamp);
}
@@ -950,7 +993,7 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
}
else
{
image = gsk_gpu_device_create_upload_image (self, FALSE, GDK_MEMORY_DEFAULT, rect.size.width, rect.size.height),
image = gsk_gpu_device_create_upload_image (self, FALSE, GDK_MEMORY_DEFAULT, GDK_COLOR_STATE_SRGB, rect.size.width, rect.size.height),
rect.origin.x = 0;
rect.origin.y = 0;
padding = 0;

View File

@@ -35,6 +35,7 @@ struct _GskGpuDeviceClass
GskGpuImage * (* create_upload_image) (GskGpuDevice *self,
gboolean with_mipmap,
GdkMemoryFormat format,
GdkColorState *color_state,
gsize width,
gsize height);
GskGpuImage * (* create_download_image) (GskGpuDevice *self,
@@ -64,6 +65,7 @@ GskGpuImage * gsk_gpu_device_create_offscreen_image (GskGpuD
GskGpuImage * gsk_gpu_device_create_upload_image (GskGpuDevice *self,
gboolean with_mipmap,
GdkMemoryFormat format,
GdkColorState *color_state,
gsize width,
gsize height);
GskGpuImage * gsk_gpu_device_create_download_image (GskGpuDevice *self,
@@ -73,11 +75,13 @@ GskGpuImage * gsk_gpu_device_create_download_image (GskGpuD
void gsk_gpu_device_make_current (GskGpuDevice *self);
GskGpuImage * gsk_gpu_device_lookup_texture_image (GskGpuDevice *self,
GdkTexture *texture,
GdkColorState *color_state,
gint64 timestamp);
void gsk_gpu_device_cache_texture_image (GskGpuDevice *self,
GdkTexture *texture,
gint64 timestamp,
GskGpuImage *image);
GskGpuImage *image,
GdkColorState *color_state);
typedef enum
{

View File

@@ -146,7 +146,7 @@ gsk_gpu_download_op_vk_command (GskGpuOp *op,
GskVulkanDevice *device = GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame));
VkDevice vk_device = gsk_vulkan_device_get_vk_device (device);
gsk_gpu_device_cache_texture_image (GSK_GPU_DEVICE (device), self->texture, gsk_gpu_frame_get_timestamp (frame), self->image);
gsk_gpu_device_cache_texture_image (GSK_GPU_DEVICE (device), self->texture, gsk_gpu_frame_get_timestamp (frame), self->image, gdk_texture_get_color_state (self->texture));
if (gsk_vulkan_device_has_feature (device, GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT))
{

View File

@@ -17,6 +17,7 @@
#include "gdk/gdkdmabufdownloaderprivate.h"
#include "gdk/gdktexturedownloaderprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#define DEFAULT_VERTEX_BUFFER_SIZE 128 * 1024
@@ -402,17 +403,26 @@ gsk_gpu_frame_get_last_op (GskGpuFrame *self)
}
GskGpuImage *
gsk_gpu_frame_upload_texture (GskGpuFrame *self,
gboolean with_mipmap,
GdkTexture *texture)
gsk_gpu_frame_upload_texture (GskGpuFrame *self,
gboolean with_mipmap,
GdkTexture *texture,
GdkColorState **out_color_state)
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
GskGpuImage *image;
GdkColorState *color_state;
image = GSK_GPU_FRAME_GET_CLASS (self)->upload_texture (self, with_mipmap, texture);
if (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_SRGB)
color_state = GDK_COLOR_STATE_SRGB_LINEAR;
else
color_state = gdk_texture_get_color_state (texture);
if (image)
gsk_gpu_device_cache_texture_image (priv->device, texture, priv->timestamp, image);
gsk_gpu_device_cache_texture_image (priv->device, texture, priv->timestamp, image, color_state);
*out_color_state = color_state;
return image;
}
@@ -561,6 +571,7 @@ copy_texture (gpointer user_data,
static void
gsk_gpu_frame_record_rect (GskGpuFrame *self,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_rectangle_int_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport)
@@ -572,6 +583,7 @@ gsk_gpu_frame_record_rect (GskGpuFrame *self,
gsk_gpu_node_processor_process (self,
target,
target_color_state,
clip,
node,
viewport);
@@ -585,6 +597,7 @@ static void
gsk_gpu_frame_record (GskGpuFrame *self,
gint64 timestamp,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_region_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport,
@@ -603,13 +616,14 @@ gsk_gpu_frame_record (GskGpuFrame *self,
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (clip, i, &rect);
gsk_gpu_frame_record_rect (self, target, &rect, node, viewport);
gsk_gpu_frame_record_rect (self, target, target_color_state, &rect, node, viewport);
}
}
else
{
gsk_gpu_frame_record_rect (self,
target,
target_color_state,
&(cairo_rectangle_int_t) {
0, 0,
gsk_gpu_image_get_width (target),
@@ -656,6 +670,7 @@ void
gsk_gpu_frame_render (GskGpuFrame *self,
gint64 timestamp,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_region_t *region,
GskRenderNode *node,
const graphene_rect_t *viewport,
@@ -663,7 +678,7 @@ gsk_gpu_frame_render (GskGpuFrame *self,
{
gsk_gpu_frame_cleanup (self);
gsk_gpu_frame_record (self, timestamp, target, region, node, viewport, texture);
gsk_gpu_frame_record (self, timestamp, target, target_color_state, region, node, viewport, texture);
gsk_gpu_frame_submit (self);
}
@@ -702,10 +717,11 @@ gsk_gpu_frame_download_texture (GskGpuFrame *self,
{
GskGpuFramePrivate *priv = gsk_gpu_frame_get_instance_private (self);
GskGpuImage *image;
GdkColorState *color_state;
image = gsk_gpu_device_lookup_texture_image (priv->device, texture, timestamp);
image = gsk_gpu_device_lookup_texture_image (priv->device, texture, GDK_COLOR_STATE_SRGB, timestamp);
if (image == NULL)
image = gsk_gpu_frame_upload_texture (self, FALSE, texture);
image = gsk_gpu_frame_upload_texture (self, FALSE, texture, &color_state);
if (image == NULL)
{
g_critical ("Could not upload texture");

View File

@@ -58,7 +58,8 @@ gpointer gsk_gpu_frame_alloc_op (GskGpuF
gsize size);
GskGpuImage * gsk_gpu_frame_upload_texture (GskGpuFrame *self,
gboolean with_mipmap,
GdkTexture *texture);
GdkTexture *texture,
GdkColorState **out_color_state);
GskGpuDescriptors * gsk_gpu_frame_create_descriptors (GskGpuFrame *self);
gsize gsk_gpu_frame_reserve_vertex_data (GskGpuFrame *self,
gsize size);
@@ -75,6 +76,7 @@ void gsk_gpu_frame_wait (GskGpuF
void gsk_gpu_frame_render (GskGpuFrame *self,
gint64 timestamp,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_region_t *region,
GskRenderNode *node,
const graphene_rect_t *viewport,

View File

@@ -114,7 +114,7 @@ gsk_gpu_image_toggle_ref_texture (GskGpuImage *self,
g_object_add_toggle_ref (G_OBJECT (self), gsk_gpu_image_texture_toggle_ref_cb, texture);
g_object_unref (self);
}
GdkMemoryFormat
gsk_gpu_image_get_format (GskGpuImage *self)
{

View File

@@ -10,6 +10,7 @@
#include "gskgpubluropprivate.h"
#include "gskgpuclearopprivate.h"
#include "gskgpuclipprivate.h"
#include "gskgpucolorconvertopprivate.h"
#include "gskgpucolorizeopprivate.h"
#include "gskgpucolormatrixopprivate.h"
#include "gskgpucoloropprivate.h"
@@ -44,6 +45,7 @@
#include "gdk/gdkrgbaprivate.h"
#include "gdk/gdksubsurfaceprivate.h"
#include "gdk/gdkcolorstateprivate.h"
/* the epsilon we allow pixels to be off due to rounding errors.
* Chosen rather randomly.
@@ -120,6 +122,7 @@ struct _GskGpuNodeProcessor
float opacity;
GskGpuGlobals pending_globals;
GdkColorState *color_state;
};
#define GDK_ARRAY_NAME pattern_buffer
@@ -141,6 +144,7 @@ struct _GskGpuPatternWriter
guint stack;
PatternBuffer buffer;
GdkColorState *color_state;
};
static void gsk_gpu_node_processor_add_node (GskGpuNodeProcessor *self,
@@ -153,6 +157,7 @@ gsk_gpu_node_processor_finish (GskGpuNodeProcessor *self)
{
g_clear_pointer (&self->modelview, gsk_transform_unref);
g_clear_object (&self->desc);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
}
static void
@@ -160,6 +165,7 @@ gsk_gpu_node_processor_init (GskGpuNodeProcessor *self,
GskGpuFrame *frame,
GskGpuDescriptors *desc,
GskGpuImage *target,
GdkColorState *color_state,
const cairo_rectangle_int_t *clip,
const graphene_rect_t *viewport)
{
@@ -202,6 +208,8 @@ gsk_gpu_node_processor_init (GskGpuNodeProcessor *self,
-viewport->origin.y);
self->opacity = 1.0;
self->pending_globals = GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND;
self->color_state = gdk_color_state_ref (color_state);
}
static void
@@ -338,6 +346,7 @@ gsk_gpu_node_processor_init_draw (GskGpuNodeProcessor *self,
GskGpuFrame *frame,
GdkMemoryDepth depth,
const graphene_vec2_t *scale,
GdkColorState *color_state,
const graphene_rect_t *viewport)
{
GskGpuImage *image;
@@ -359,6 +368,7 @@ gsk_gpu_node_processor_init_draw (GskGpuNodeProcessor *self,
frame,
NULL,
image,
color_state,
&area,
viewport);
@@ -381,9 +391,97 @@ gsk_gpu_node_processor_finish_draw (GskGpuNodeProcessor *self,
gsk_gpu_node_processor_finish (self);
}
static GskGpuImage *
gsk_gpu_color_convert (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *from,
GdkColorState *to)
{
GskGpuNodeProcessor other;
int width, height;
GdkMemoryDepth depth;
GskGpuImage *copy;
guint32 descriptor;
graphene_rect_t rect;
if (gdk_color_state_equal (from, to))
return image;
width = gsk_gpu_image_get_width (image);
height = gsk_gpu_image_get_height (image);
depth = gdk_memory_format_get_depth (gsk_gpu_image_get_format (image));
depth = gdk_memory_depth_merge (depth, gdk_color_state_get_min_depth (from));
depth = gdk_memory_depth_merge (depth, gdk_color_state_get_min_depth (to));
rect = GRAPHENE_RECT_INIT (0, 0, width, height);
copy = gsk_gpu_device_create_offscreen_image (gsk_gpu_frame_get_device (frame),
FALSE,
depth,
width, height);
gsk_gpu_node_processor_init (&other,
frame,
NULL,
copy,
to,
&(cairo_rectangle_int_t) { 0, 0, width, height },
&rect);
gsk_gpu_render_pass_begin_op (other.frame,
copy,
&(cairo_rectangle_int_t) { 0, 0, width, height },
GSK_RENDER_PASS_OFFSCREEN);
descriptor = gsk_gpu_node_processor_add_image (&other, image, GSK_GPU_SAMPLER_DEFAULT);
gsk_gpu_node_processor_sync_globals (&other, 0);
gsk_gpu_color_convert_op (frame,
GSK_GPU_SHADER_CLIP_NONE,
from,
to,
other.desc,
descriptor,
&rect,
&other.offset,
&rect);
gsk_gpu_render_pass_end_op (other.frame,
copy,
GSK_RENDER_PASS_OFFSCREEN);
gsk_gpu_node_processor_finish (&other);
g_object_unref (image);
return copy;
}
static void
gsk_gpu_node_processor_get_clip_bounds (GskGpuNodeProcessor *self,
graphene_rect_t *out_bounds)
{
graphene_rect_offset_r (&self->clip.rect.bounds,
- self->offset.x,
- self->offset.y,
out_bounds);
/* FIXME: We could try the scissor rect here.
* But how often is that smaller than the clip bounds?
*/
}
static GskGpuImage * gsk_gpu_get_node_as_image (GskGpuFrame *frame,
const graphene_rect_t *clip_bounds,
const graphene_vec2_t *scale,
GdkColorState *color_state,
GskRenderNode *node,
graphene_rect_t *out_bounds);
void
gsk_gpu_node_processor_process (GskGpuFrame *frame,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_rectangle_int_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport)
@@ -394,10 +492,46 @@ gsk_gpu_node_processor_process (GskGpuFrame *frame,
frame,
NULL,
target,
GDK_COLOR_STATE_SRGB_LINEAR,
clip,
viewport);
gsk_gpu_node_processor_add_node (&self, node);
if (gdk_color_state_equal (target_color_state, GDK_COLOR_STATE_SRGB_LINEAR))
{
gsk_gpu_node_processor_add_node (&self, node);
}
else
{
GskGpuImage *image;
graphene_rect_t clip_bounds;
graphene_rect_t bounds;
guint32 descriptor;
gsk_gpu_node_processor_sync_globals (&self, 0);
gsk_gpu_node_processor_get_clip_bounds (&self, &clip_bounds);
image = gsk_gpu_get_node_as_image (frame,
&clip_bounds,
&self.scale,
GDK_COLOR_STATE_SRGB_LINEAR,
node,
&bounds);
descriptor = gsk_gpu_node_processor_add_image (&self, image, GSK_GPU_SAMPLER_DEFAULT);
gsk_gpu_color_convert_op (frame,
GSK_GPU_SHADER_CLIP_NONE,
GDK_COLOR_STATE_SRGB_LINEAR,
target_color_state,
self.desc,
descriptor,
&bounds,
&self.offset,
&bounds);
g_object_unref (image);
}
gsk_gpu_node_processor_finish (&self);
}
@@ -406,6 +540,7 @@ static void
gsk_gpu_pattern_writer_init (GskGpuPatternWriter *self,
GskGpuFrame *frame,
const graphene_vec2_t *scale,
GdkColorState *color_state,
const graphene_point_t *offset,
const graphene_rect_t *bounds)
{
@@ -419,6 +554,8 @@ gsk_gpu_pattern_writer_init (GskGpuPatternWriter *self,
self->scale = *scale;
self->stack = 0;
self->color_state = gdk_color_state_ref (color_state);
pattern_buffer_init (&self->buffer);
}
@@ -546,6 +683,7 @@ gsk_gpu_pattern_writer_finish (GskGpuPatternWriter *self)
pattern_buffer_clear (&self->buffer);
g_assert (self->stack == 0);
g_clear_object (&self->desc);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
}
static gboolean
@@ -664,20 +802,6 @@ gsk_gpu_node_processor_rect_is_integer (GskGpuNodeProcessor *self,
&& int_rect->height == rect->size.height * scale_y;
}
static void
gsk_gpu_node_processor_get_clip_bounds (GskGpuNodeProcessor *self,
graphene_rect_t *out_bounds)
{
graphene_rect_offset_r (&self->clip.rect.bounds,
- self->offset.x,
- self->offset.y,
out_bounds);
/* FIXME: We could try the scissor rect here.
* But how often is that smaller than the clip bounds?
*/
}
static gboolean G_GNUC_WARN_UNUSED_RESULT
gsk_gpu_node_processor_clip_node_bounds (GskGpuNodeProcessor *self,
GskRenderNode *node,
@@ -742,6 +866,7 @@ gsk_gpu_node_processor_image_op (GskGpuNodeProcessor *self,
static GskGpuImage *
gsk_gpu_node_processor_create_offscreen (GskGpuFrame *frame,
const graphene_vec2_t *scale,
GdkColorState *color_state,
const graphene_rect_t *viewport,
GskRenderNode *node)
{
@@ -752,6 +877,7 @@ gsk_gpu_node_processor_create_offscreen (GskGpuFrame *frame,
frame,
gsk_render_node_get_preferred_depth (node),
scale,
color_state,
viewport);
if (image == NULL)
return NULL;
@@ -768,6 +894,7 @@ gsk_gpu_node_processor_create_offscreen (GskGpuFrame *frame,
* @frame: frame to render in
* @clip_bounds: region of node that must be included in image
* @scale: scale factor to use for the image
* @color_state: the color state to composite in
* @node: the node to render
* @out_bounds: the actual bounds of the result
*
@@ -789,10 +916,12 @@ static GskGpuImage *
gsk_gpu_get_node_as_image (GskGpuFrame *frame,
const graphene_rect_t *clip_bounds,
const graphene_vec2_t *scale,
GdkColorState *color_state,
GskRenderNode *node,
graphene_rect_t *out_bounds)
{
GskGpuImage *result;
GdkColorState *image_color_state;
switch ((guint) gsk_render_node_get_node_type (node))
{
@@ -801,9 +930,19 @@ gsk_gpu_get_node_as_image (GskGpuFrame *frame,
GdkTexture *texture = gsk_texture_node_get_texture (node);
GskGpuDevice *device = gsk_gpu_frame_get_device (frame);
gint64 timestamp = gsk_gpu_frame_get_timestamp (frame);
result = gsk_gpu_device_lookup_texture_image (device, texture, timestamp);
result = gsk_gpu_device_lookup_texture_image (device, texture, color_state, timestamp);
if (result == NULL)
result = gsk_gpu_frame_upload_texture (frame, FALSE, texture);
{
result = gsk_gpu_frame_upload_texture (frame, FALSE, texture, &image_color_state);
if (result &&
!gdk_color_state_equal (image_color_state, color_state))
{
result = gsk_gpu_color_convert (frame, result, image_color_state, color_state);
gsk_gpu_device_cache_texture_image (device, texture, timestamp, result, color_state);
}
}
if (result)
{
@@ -821,6 +960,8 @@ gsk_gpu_get_node_as_image (GskGpuFrame *frame,
gsk_render_node_ref (node),
(GDestroyNotify) gsk_render_node_unref);
result = gsk_gpu_color_convert (frame, result, GDK_COLOR_STATE_SRGB, color_state);
g_object_ref (result);
*out_bounds = *clip_bounds;
@@ -833,6 +974,7 @@ gsk_gpu_get_node_as_image (GskGpuFrame *frame,
GSK_DEBUG (FALLBACK, "Offscreening node '%s'", g_type_name_from_instance ((GTypeInstance *) node));
result = gsk_gpu_node_processor_create_offscreen (frame,
scale,
color_state,
clip_bounds,
node);
@@ -843,6 +985,7 @@ gsk_gpu_get_node_as_image (GskGpuFrame *frame,
static GskGpuImage *
gsk_gpu_node_processor_ensure_image (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *color_state,
GskGpuImageFlags required_flags,
GskGpuImageFlags disallowed_flags)
{
@@ -895,6 +1038,7 @@ gsk_gpu_node_processor_ensure_image (GskGpuFrame *frame,
frame,
NULL,
copy,
color_state,
&(cairo_rectangle_int_t) { 0, 0, width, height },
&rect);
@@ -968,6 +1112,7 @@ gsk_gpu_node_processor_get_node_as_image (GskGpuNodeProcessor *self,
image = gsk_gpu_get_node_as_image (self->frame,
&clip,
&self->scale,
self->color_state,
node,
out_bounds);
if (image == NULL)
@@ -975,6 +1120,7 @@ gsk_gpu_node_processor_get_node_as_image (GskGpuNodeProcessor *self,
ensure = gsk_gpu_node_processor_ensure_image (self->frame,
image,
self->color_state,
required_flags,
disallowed_flags);
@@ -985,7 +1131,8 @@ gsk_gpu_node_processor_get_node_as_image (GskGpuNodeProcessor *self,
gsk_gpu_device_cache_texture_image (gsk_gpu_frame_get_device (self->frame),
gsk_texture_node_get_texture (node),
gsk_gpu_frame_get_timestamp (self->frame),
ensure);
ensure,
self->color_state);
}
return ensure;
@@ -1026,6 +1173,7 @@ gsk_gpu_node_processor_blur_op (GskGpuNodeProcessor *self,
self->frame,
source_depth,
&self->scale,
self->color_state,
&intermediate_rect);
gsk_gpu_node_processor_sync_globals (&other, 0);
@@ -1205,6 +1353,7 @@ gsk_gpu_node_processor_try_node_as_pattern (GskGpuNodeProcessor *self,
gsk_gpu_pattern_writer_init (&writer,
self->frame,
&self->scale,
self->color_state,
&self->offset,
&clipped);
@@ -1454,6 +1603,7 @@ gsk_gpu_node_processor_add_rounded_clip_node_with_mask (GskGpuNodeProcessor *sel
self->frame,
gsk_render_node_get_preferred_depth (node),
&self->scale,
self->color_state,
&clip_bounds);
gsk_gpu_node_processor_sync_globals (&other, 0);
gsk_gpu_rounded_color_op (other.frame,
@@ -1927,15 +2077,16 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
GskGpuImage *image;
GdkTexture *texture;
gint64 timestamp;
GdkColorState *image_color_state;
device = gsk_gpu_frame_get_device (self->frame);
texture = gsk_texture_node_get_texture (node);
timestamp = gsk_gpu_frame_get_timestamp (self->frame);
image = gsk_gpu_device_lookup_texture_image (device, texture, timestamp);
image = gsk_gpu_device_lookup_texture_image (device, texture, self->color_state, timestamp);
if (image == NULL)
{
image = gsk_gpu_frame_upload_texture (self->frame, FALSE, texture);
image = gsk_gpu_frame_upload_texture (self->frame, FALSE, texture, &image_color_state);
if (image == NULL)
{
GSK_DEBUG (FALLBACK, "Unsupported texture format %u for size %dx%d",
@@ -1945,6 +2096,12 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
gsk_gpu_node_processor_add_fallback_node (self, node);
return;
}
if (!gdk_color_state_equal (image_color_state, self->color_state))
{
image = gsk_gpu_color_convert (self->frame, image, image_color_state, self->color_state);
gsk_gpu_device_cache_texture_image (device, texture, timestamp, image, self->color_state);
}
}
if (gsk_gpu_frame_should_optimize (self->frame, GSK_GPU_OPTIMIZE_MIPMAP) &&
@@ -1955,6 +2112,7 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
image = gsk_gpu_node_processor_ensure_image (self->frame,
image,
self->color_state,
GSK_GPU_IMAGE_MIPMAP,
GSK_GPU_IMAGE_STRAIGHT_ALPHA);
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_MIPMAP_DEFAULT);
@@ -2001,17 +2159,24 @@ gsk_gpu_node_processor_create_texture_pattern (GskGpuPatternWriter *self,
guint32 descriptor;
GskGpuImage *image;
GskGpuSampler sampler;
GdkColorState *image_color_state;
device = gsk_gpu_frame_get_device (self->frame);
texture = gsk_texture_node_get_texture (node);
timestamp = gsk_gpu_frame_get_timestamp (self->frame);
image = gsk_gpu_device_lookup_texture_image (device, texture, timestamp);
image = gsk_gpu_device_lookup_texture_image (device, texture, self->color_state, timestamp);
if (image == NULL)
{
image = gsk_gpu_frame_upload_texture (self->frame, FALSE, texture);
image = gsk_gpu_frame_upload_texture (self->frame, FALSE, texture, &image_color_state);
if (image == NULL)
return FALSE;
if (!gdk_color_state_equal (image_color_state, self->color_state))
{
image = gsk_gpu_color_convert (self->frame, image, image_color_state, self->color_state);
gsk_gpu_device_cache_texture_image (device, texture, timestamp, image, self->color_state);
}
}
if (gsk_gpu_frame_should_optimize (self->frame, GSK_GPU_OPTIMIZE_MIPMAP) &&
@@ -2020,6 +2185,7 @@ gsk_gpu_node_processor_create_texture_pattern (GskGpuPatternWriter *self,
{
image = gsk_gpu_node_processor_ensure_image (self->frame,
image,
self->color_state,
GSK_GPU_IMAGE_MIPMAP,
GSK_GPU_IMAGE_STRAIGHT_ALPHA);
sampler = GSK_GPU_SAMPLER_MIPMAP_DEFAULT;
@@ -2058,6 +2224,7 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
gint64 timestamp;
guint32 descriptor;
gboolean need_mipmap, need_offscreen;
GdkColorState *image_color_state;
need_offscreen = self->modelview != NULL ||
!graphene_vec2_equal (&self->scale, graphene_vec2_one ());
@@ -2081,6 +2248,7 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
clip_bounds.size.height = ceilf (clip_bounds.size.height);
offscreen = gsk_gpu_node_processor_create_offscreen (self->frame,
graphene_vec2_one (),
self->color_state,
&clip_bounds,
node);
descriptor = gsk_gpu_node_processor_add_image (self, offscreen, GSK_GPU_SAMPLER_DEFAULT);
@@ -2101,10 +2269,10 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
timestamp = gsk_gpu_frame_get_timestamp (self->frame);
need_mipmap = scaling_filter == GSK_SCALING_FILTER_TRILINEAR;
image = gsk_gpu_device_lookup_texture_image (device, texture, timestamp);
image = gsk_gpu_device_lookup_texture_image (device, texture, self->color_state, timestamp);
if (image == NULL)
{
image = gsk_gpu_frame_upload_texture (self->frame, need_mipmap, texture);
image = gsk_gpu_frame_upload_texture (self->frame, need_mipmap, texture, &image_color_state);
if (image == NULL)
{
GSK_DEBUG (FALLBACK, "Unsupported texture format %u for size %dx%d",
@@ -2114,10 +2282,16 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
gsk_gpu_node_processor_add_fallback_node (self, node);
return;
}
if (!gdk_color_state_equal (image_color_state, self->color_state))
{
image = gsk_gpu_color_convert (self->frame, image, image_color_state, self->color_state);
gsk_gpu_device_cache_texture_image (device, texture, timestamp, image, self->color_state);
}
}
image = gsk_gpu_node_processor_ensure_image (self->frame,
image,
self->color_state,
need_mipmap ? (GSK_GPU_IMAGE_CAN_MIPMAP | GSK_GPU_IMAGE_MIPMAP) : 0,
GSK_GPU_IMAGE_STRAIGHT_ALPHA);
@@ -2282,6 +2456,7 @@ gsk_gpu_node_processor_add_gradient_node (GskGpuNodeProcessor *self,
self->frame,
gsk_render_node_get_preferred_depth (node),
&self->scale,
self->color_state,
&bounds);
other.blend = GSK_GPU_BLEND_ADD;
@@ -3331,6 +3506,7 @@ gsk_gpu_node_processor_repeat_tile (GskGpuNodeProcessor *self,
GSK_DEBUG (FALLBACK, "Offscreening node '%s' for tiling", g_type_name_from_instance ((GTypeInstance *) child));
image = gsk_gpu_node_processor_create_offscreen (self->frame,
&self->scale,
self->color_state,
&clipped_child_bounds,
child);
@@ -4123,6 +4299,7 @@ gsk_gpu_node_processor_create_node_pattern (GskGpuPatternWriter *self,
image = gsk_gpu_get_node_as_image (self->frame,
&bounds,
&self->scale,
self->color_state,
node,
&bounds);
if (image == NULL)

View File

@@ -7,6 +7,7 @@ G_BEGIN_DECLS
void gsk_gpu_node_processor_process (GskGpuFrame *frame,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_rectangle_int_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport);

View File

@@ -2,6 +2,8 @@
#include "gskgpuprintprivate.h"
#include "gdk/gdkrgbaprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#include "gskgpudescriptorsprivate.h"
#include "gskgpuimageprivate.h"
@@ -155,3 +157,11 @@ gsk_gpu_print_image_descriptor (GString *string,
gsk_gpu_print_image (string, gsk_gpu_descriptors_get_image (desc, id));
}
void
gsk_gpu_print_color_conversion (GString *string,
guint conversion)
{
g_string_append_printf (string, "%s->%s ",
gdk_color_state_get_name_from_id (conversion & 0xffff),
gdk_color_state_get_name_from_id (conversion >> 16));
}

View File

@@ -35,3 +35,5 @@ void gsk_gpu_print_image (GString
void gsk_gpu_print_image_descriptor (GString *string,
GskGpuDescriptors *desc,
guint32 descriptor);
void gsk_gpu_print_color_conversion (GString *string,
guint conversion);

View File

@@ -18,6 +18,7 @@
#include "gdk/gdktextureprivate.h"
#include "gdk/gdktexturedownloaderprivate.h"
#include "gdk/gdkdrawcontextprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#include <graphene.h>
@@ -298,6 +299,7 @@ gsk_gpu_renderer_fallback_render_texture (GskGpuRenderer *self,
gsk_gpu_frame_render (frame,
g_get_monotonic_time (),
image,
GDK_COLOR_STATE_SRGB,
NULL,
root,
&GRAPHENE_RECT_INIT (rounded_viewport->origin.x + x,
@@ -360,6 +362,7 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer,
gsk_gpu_frame_render (frame,
g_get_monotonic_time (),
image,
GDK_COLOR_STATE_SRGB,
NULL,
root,
&rounded_viewport,
@@ -387,6 +390,8 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
GskGpuImage *backbuffer;
cairo_region_t *render_region;
double scale;
GdkMemoryDepth depth;
GdkColorState *target_color_state;
if (cairo_region_is_empty (region))
{
@@ -394,9 +399,9 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
return;
}
gdk_draw_context_begin_frame_full (priv->context,
gsk_render_node_get_preferred_depth (root),
region);
depth = gsk_render_node_get_preferred_depth (root);
gdk_draw_context_begin_frame_full (priv->context, depth, region);
gsk_gpu_device_maybe_gc (priv->device);
@@ -408,9 +413,21 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
render_region = get_render_region (self);
scale = gsk_gpu_renderer_get_scale (self);
if (gsk_gpu_image_get_flags (backbuffer) & GSK_GPU_IMAGE_SRGB)
{
g_debug ("Relying on GL/Vulkan to do srgb-linear->srgb conversion");
target_color_state = GDK_COLOR_STATE_SRGB_LINEAR;
}
else
{
g_debug ("Using an offscreen for srgb-linear->srgb conversion");
target_color_state = GDK_COLOR_STATE_SRGB;
}
gsk_gpu_frame_render (frame,
g_get_monotonic_time (),
backbuffer,
target_color_state,
render_region,
root,
&GRAPHENE_RECT_INIT (

View File

@@ -4,6 +4,8 @@
#include "gskgputypesprivate.h"
#include <math.h>
G_BEGIN_DECLS
struct _GskGpuShaderOp
@@ -63,13 +65,23 @@ GskGpuOp * gsk_gpu_shader_op_gl_command (GskGpuO
GskGpuFrame *frame,
GskGLCommandState *state);
static inline float
srgb_inverse_transfer_function (float v)
{
if (v >= 0.04045)
return powf (((v + 0.055)/(1 + 0.055)), 2.4);
else
return v / 12.92;
}
static inline void
gsk_gpu_rgba_to_float (const GdkRGBA *rgba,
float values[4])
{
values[0] = rgba->red;
values[1] = rgba->green;
values[2] = rgba->blue;
values[0] = srgb_inverse_transfer_function (rgba->red);
values[1] = srgb_inverse_transfer_function (rgba->green);
values[2] = srgb_inverse_transfer_function (rgba->blue);
values[3] = rgba->alpha;
}

View File

@@ -29,6 +29,7 @@ typedef enum {
GSK_GPU_IMAGE_MIPMAP = (1 << 5),
GSK_GPU_IMAGE_FILTERABLE = (1 << 6),
GSK_GPU_IMAGE_RENDERABLE = (1 << 7),
GSK_GPU_IMAGE_SRGB = (1 << 8),
} GskGpuImageFlags;
typedef enum {

View File

@@ -14,6 +14,15 @@
#include "gdk/gdkglcontextprivate.h"
#include "gsk/gskdebugprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#ifdef HAVE_PANGOFT
#include <pango/pangofc-font.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_PARAMETER_TAGS_H
#endif
static GskGpuOp *
gsk_gpu_upload_op_gl_command_with_area (GskGpuOp *op,
@@ -304,6 +313,7 @@ gsk_gpu_upload_texture_op_try (GskGpuFrame *frame,
image = gsk_gpu_device_create_upload_image (gsk_gpu_frame_get_device (frame),
with_mipmap,
gdk_texture_get_format (texture),
gdk_texture_get_color_state (texture),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
if (image == NULL)
@@ -470,6 +480,7 @@ gsk_gpu_upload_cairo_op (GskGpuFrame *frame,
self->image = gsk_gpu_device_create_upload_image (gsk_gpu_frame_get_device (frame),
FALSE,
GDK_MEMORY_DEFAULT,
GDK_COLOR_STATE_SRGB,
ceil (graphene_vec2_get_x (scale) * viewport->size.width),
ceil (graphene_vec2_get_y (scale) * viewport->size.height));
self->viewport = *viewport;
@@ -537,6 +548,16 @@ gsk_gpu_upload_glyph_op_draw (GskGpuOp *op,
cairo_surface_t *surface;
cairo_t *cr;
PangoRectangle ink_rect = { 0, };
#ifdef HAVE_PANGOFT
FT_Face face;
FT_Bool darken = 1;
FT_Parameter property = { FT_PARAM_TAG_STEM_DARKENING, &darken };
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
face = pango_fc_font_lock_face (PANGO_FC_FONT (self->font));
G_GNUC_END_IGNORE_DEPRECATIONS
FT_Face_Properties (face, 1, &property);
#endif
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
@@ -578,6 +599,12 @@ gsk_gpu_upload_glyph_op_draw (GskGpuOp *op,
cairo_surface_finish (surface);
cairo_surface_destroy (surface);
#ifdef HAVE_PANGOFT
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
pango_fc_font_unlock_face (PANGO_FC_FONT (self->font));
G_GNUC_END_IGNORE_DEPRECATIONS
#endif
}
#ifdef GDK_RENDERING_VULKAN

View File

@@ -117,7 +117,8 @@ gsk_ngl_renderer_get_backbuffer (GskGpuRenderer *renderer)
GDK_GL_CONTEXT (context),
GDK_MEMORY_DEFAULT /* FIXME */,
ceil (gdk_surface_get_width (surface) * scale),
ceil (gdk_surface_get_height (surface) * scale));
ceil (gdk_surface_get_height (surface) * scale),
gdk_surface_get_gl_is_srgb (surface));
}
return self->backbuffer;

View File

@@ -391,6 +391,7 @@ static GskGpuImage *
gsk_vulkan_device_create_upload_image (GskGpuDevice *device,
gboolean with_mipmap,
GdkMemoryFormat format,
GdkColorState *color_state,
gsize width,
gsize height)
{
@@ -399,6 +400,7 @@ gsk_vulkan_device_create_upload_image (GskGpuDevice *device,
return gsk_vulkan_image_new_for_upload (self,
with_mipmap,
format,
color_state,
width,
height);
}

View File

@@ -11,6 +11,7 @@
#include "gdk/gdkvulkancontextprivate.h"
#include "gdk/gdkmemoryformatprivate.h"
#include "gdk/gdkvulkancontextprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#include <fcntl.h>
#include <string.h>
@@ -243,6 +244,7 @@ gsk_vulkan_device_check_format (GskVulkanDevice *device,
static GskVulkanImage *
gsk_vulkan_image_new (GskVulkanDevice *device,
GdkMemoryFormat format,
GdkColorState *color_state,
GskGpuImageFlags required_flags,
gsize width,
gsize height,
@@ -305,6 +307,13 @@ gsk_vulkan_image_new (GskVulkanDevice *device,
(required_flags & GSK_GPU_IMAGE_CAN_MIPMAP))
flags |= GSK_GPU_IMAGE_CAN_MIPMAP;
if (gdk_memory_format_vk_srgb_format (format) != VK_FORMAT_UNDEFINED &&
gdk_color_state_equal (color_state, GDK_COLOR_STATE_SRGB))
{
vk_format = gdk_memory_format_vk_srgb_format (format);
flags |= GSK_GPU_IMAGE_SRGB;
}
vk_device = gsk_vulkan_device_get_vk_device (device);
self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
@@ -366,6 +375,7 @@ GskGpuImage *
gsk_vulkan_image_new_for_upload (GskVulkanDevice *device,
gboolean with_mipmap,
GdkMemoryFormat format,
GdkColorState *color_state,
gsize width,
gsize height)
{
@@ -373,6 +383,7 @@ gsk_vulkan_image_new_for_upload (GskVulkanDevice *device,
self = gsk_vulkan_image_new (device,
format,
color_state,
with_mipmap ? (GSK_GPU_IMAGE_CAN_MIPMAP | GSK_GPU_IMAGE_RENDERABLE | GSK_GPU_IMAGE_FILTERABLE) : 0,
width,
height,
@@ -438,6 +449,7 @@ gsk_vulkan_image_new_for_swapchain (GskVulkanDevice *device,
gsize height)
{
GskVulkanImage *self;
GskGpuImageFlags flags = 0;
self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
@@ -450,9 +462,11 @@ gsk_vulkan_image_new_for_swapchain (GskVulkanDevice *device,
self->vk_image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
self->vk_access = 0;
/* FIXME: The flags here are very suboptimal */
gsk_gpu_image_setup (GSK_GPU_IMAGE (self), 0, memory_format, width, height);
if (format == gdk_memory_format_vk_srgb_format (memory_format))
flags |= GSK_GPU_IMAGE_SRGB;
/* FIXME: The flags here are very suboptimal */
gsk_gpu_image_setup (GSK_GPU_IMAGE (self), flags, memory_format, width, height);
gsk_vulkan_image_create_view (self,
format,
&(VkComponentMapping) {
@@ -475,6 +489,7 @@ gsk_vulkan_image_new_for_atlas (GskVulkanDevice *device,
self = gsk_vulkan_image_new (device,
GDK_MEMORY_DEFAULT,
GDK_COLOR_STATE_SRGB_LINEAR,
GSK_GPU_IMAGE_FILTERABLE | GSK_GPU_IMAGE_RENDERABLE,
width,
height,
@@ -499,6 +514,7 @@ gsk_vulkan_image_new_for_offscreen (GskVulkanDevice *device,
self = gsk_vulkan_image_new (device,
preferred_format,
GDK_COLOR_STATE_SRGB_LINEAR,
GSK_GPU_IMAGE_RENDERABLE |
(with_mipmap ? GSK_GPU_IMAGE_CAN_MIPMAP | GSK_GPU_IMAGE_FILTERABLE : 0),
width,

View File

@@ -29,6 +29,7 @@ GskGpuImage * gsk_vulkan_image_new_for_offscreen (GskVulk
GskGpuImage * gsk_vulkan_image_new_for_upload (GskVulkanDevice *device,
gboolean with_mipmap,
GdkMemoryFormat format,
GdkColorState *color_state,
gsize width,
gsize height);
#ifdef HAVE_DMABUF

View File

@@ -19,4 +19,4 @@ luminance (vec3 color)
return dot (vec3 (0.2126, 0.7152, 0.0722), color);
}
#endif /* _COLOR_ */
#endif

View File

@@ -0,0 +1,116 @@
#include "common.glsl"
PASS(0) vec2 _pos;
PASS_FLAT(1) Rect _rect;
PASS(2) vec2 _tex_coord;
PASS_FLAT(3) uint _tex_id;
#ifdef GSK_VERTEX_SHADER
IN(0) vec4 in_rect;
IN(1) vec4 in_tex_rect;
IN(2) uint in_tex_id;
void
run (out vec2 pos)
{
Rect r = rect_from_gsk (in_rect);
pos = rect_get_position (r);
_pos = pos;
_rect = r;
_tex_coord = rect_get_coord (rect_from_gsk (in_tex_rect), pos);
_tex_id = in_tex_id;
}
#endif
#ifdef GSK_FRAGMENT_SHADER
float
srgb_transfer_function (float v)
{
if (v >= 0.04045)
return pow (((v + 0.055)/(1.0 + 0.055)), 2.4);
else
return v / 12.92;
}
float
srgb_inverse_transfer_function (float v)
{
if (v > 0.0031308)
return 1.055 * pow (v, 1.0/2.4) - 0.055;
else
return 12.92 * v;
}
vec4
srgb_to_linear_srgb (vec4 color)
{
return vec4 (srgb_transfer_function (color.r),
srgb_transfer_function (color.g),
srgb_transfer_function (color.b),
color.a);
}
vec4
linear_srgb_to_srgb (vec4 color)
{
return vec4 (srgb_inverse_transfer_function (color.r),
srgb_inverse_transfer_function (color.g),
srgb_inverse_transfer_function (color.b),
color.a);
}
#define RGB 0u
#define LINRGB 1u
#define pair(u,v) ((u)|((v) << 16))
#define first(p) ((p) & 0xffffu)
#define second(p) ((p) >> 16)
bool
do_conversion (in vec4 color, in uint f, out vec4 result)
{
switch (f)
{
case pair (RGB, LINRGB): result = srgb_to_linear_srgb (color); break;
case pair (LINRGB, RGB): result = linear_srgb_to_srgb (color); break;
default: return false;
}
return true;
}
vec4
color_convert (in vec4 color, in uint f)
{
vec4 result;
if (f == 0u)
return color;
do_conversion (color, f, result);
return result;
}
void
run (out vec4 color,
out vec2 position)
{
vec4 pixel = gsk_texture (_tex_id, _tex_coord);
pixel = color_unpremultiply (pixel);
pixel = color_convert (pixel, GSK_VARIATION);
color = color_premultiply (pixel) * rect_coverage (_rect, _pos);
position = _pos;
}
#endif

View File

@@ -18,6 +18,7 @@ gsk_private_gpu_shaders = files([
'gskgpuborder.glsl',
'gskgpuboxshadow.glsl',
'gskgpucolor.glsl',
'gskgpucolorconvert.glsl',
'gskgpucolorize.glsl',
'gskgpucolormatrix.glsl',
'gskgpuconicgradient.glsl',

View File

@@ -26,6 +26,7 @@
#include "gskrendererprivate.h"
#include "gskrendernodeprivate.h"
#include "gdk/gdktextureprivate.h"
#include "gdk/gdkcolorstateprivate.h"
typedef struct {
GQuark cpu_time;
@@ -90,6 +91,19 @@ gsk_cairo_renderer_do_render (GskRenderer *renderer,
gsk_profiler_push_samples (profiler);
}
static void
surface_linear_srgb_to_srgb (cairo_surface_t *s)
{
gdk_memory_convert_color_state (cairo_image_surface_get_data (s),
cairo_image_surface_get_stride (s),
GDK_MEMORY_DEFAULT,
GDK_COLOR_STATE_SRGB_LINEAR,
GDK_COLOR_STATE_SRGB,
cairo_image_surface_get_width (s),
cairo_image_surface_get_height (s));
cairo_surface_mark_dirty (s);
}
static GdkTexture *
gsk_cairo_renderer_render_texture (GskRenderer *renderer,
GskRenderNode *root,
@@ -144,6 +158,7 @@ gsk_cairo_renderer_render_texture (GskRenderer *renderer,
cairo_destroy (cr);
surface_linear_srgb_to_srgb (surface);
texture = gdk_texture_new_for_surface (surface);
cairo_surface_destroy (surface);
@@ -156,18 +171,17 @@ gsk_cairo_renderer_render (GskRenderer *renderer,
const cairo_region_t *region)
{
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
cairo_t *cr;
cairo_t *cr, *cr2;
GdkSurface *surface = gsk_renderer_get_surface (renderer);
cairo_surface_t *s;
gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->cairo_context),
region);
gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->cairo_context), region);
cr = gdk_cairo_context_cairo_create (self->cairo_context);
g_return_if_fail (cr != NULL);
if (GSK_RENDERER_DEBUG_CHECK (renderer, GEOMETRY))
{
GdkSurface *surface = gsk_renderer_get_surface (renderer);
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_rectangle (cr,
@@ -178,8 +192,21 @@ gsk_cairo_renderer_render (GskRenderer *renderer,
cairo_restore (cr);
}
gsk_cairo_renderer_do_render (renderer, cr, root);
s = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
gdk_surface_get_width (surface),
gdk_surface_get_height (surface));
cr2 = cairo_create (s);
gdk_cairo_region (cr2, gdk_draw_context_get_frame_region (GDK_DRAW_CONTEXT (self->cairo_context)));
cairo_clip (cr2);
gsk_cairo_renderer_do_render (renderer, cr2, root);
surface_linear_srgb_to_srgb (s);
cairo_set_source_surface (cr, s, 0, 0);
cairo_paint (cr);
cairo_destroy (cr2);
cairo_surface_destroy (s);
cairo_destroy (cr);
gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->cairo_context));

View File

@@ -40,6 +40,7 @@
#include "gdk/gdktextureprivate.h"
#include "gdk/gdktexturedownloaderprivate.h"
#include "gdk/gdkrgbaprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#include <cairo.h>
#ifdef CAIRO_HAS_SVG_SURFACE
@@ -47,6 +48,13 @@
#endif
#include <hb-ot.h>
#ifdef HAVE_PANGOFT
#include <pango/pangofc-font.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_PARAMETER_TAGS_H
#endif
/* for oversized image fallback - we use a smaller size than Cairo actually
* allows to avoid rounding errors in Cairo */
#define MAX_CAIRO_IMAGE_WIDTH 16384
@@ -139,6 +147,39 @@ region_union_region_affine (cairo_region_t *region,
}
}
static inline float
srgb_inverse_transfer_function (float v)
{
if (v >= 0.04045)
return powf (((v + 0.055)/(1 + 0.055)), 2.4);
else
return v / 12.92;
}
static void
gsk_cairo_set_source_rgba (cairo_t *cr,
const GdkRGBA *rgba)
{
cairo_set_source_rgba (cr,
srgb_inverse_transfer_function (rgba->red),
srgb_inverse_transfer_function (rgba->green),
srgb_inverse_transfer_function (rgba->blue),
rgba->alpha);
}
static void
surface_srgb_to_linear_srgb (cairo_surface_t *s)
{
gdk_memory_convert_color_state (cairo_image_surface_get_data (s),
cairo_image_surface_get_stride (s),
GDK_MEMORY_DEFAULT,
GDK_COLOR_STATE_SRGB,
GDK_COLOR_STATE_SRGB_LINEAR,
cairo_image_surface_get_width (s),
cairo_image_surface_get_height (s));
cairo_surface_mark_dirty (s);
}
/* {{{ GSK_COLOR_NODE */
/**
@@ -159,7 +200,7 @@ gsk_color_node_draw (GskRenderNode *node,
{
GskColorNode *self = (GskColorNode *) node;
gdk_cairo_set_source_rgba (cr, &self->color);
gsk_cairo_set_source_rgba (cr, &self->color);
gsk_cairo_rectangle (cr, &node->bounds);
cairo_fill (cr);
@@ -294,25 +335,25 @@ gsk_linear_gradient_node_draw (GskRenderNode *node,
if (self->stops[0].offset > 0.0)
cairo_pattern_add_color_stop_rgba (pattern,
0.0,
self->stops[0].color.red,
self->stops[0].color.green,
self->stops[0].color.blue,
srgb_inverse_transfer_function (self->stops[0].color.red),
srgb_inverse_transfer_function (self->stops[0].color.green),
srgb_inverse_transfer_function (self->stops[0].color.blue),
self->stops[0].color.alpha);
for (i = 0; i < self->n_stops; i++)
{
cairo_pattern_add_color_stop_rgba (pattern,
self->stops[i].offset,
self->stops[i].color.red,
self->stops[i].color.green,
self->stops[i].color.blue,
srgb_inverse_transfer_function (self->stops[i].color.red),
srgb_inverse_transfer_function (self->stops[i].color.green),
srgb_inverse_transfer_function (self->stops[i].color.blue),
self->stops[i].color.alpha);
}
if (self->stops[self->n_stops-1].offset < 1.0)
cairo_pattern_add_color_stop_rgba (pattern,
1.0,
self->stops[self->n_stops-1].color.red,
self->stops[self->n_stops-1].color.green,
self->stops[self->n_stops-1].color.blue,
srgb_inverse_transfer_function (self->stops[self->n_stops-1].color.red),
srgb_inverse_transfer_function (self->stops[self->n_stops-1].color.green),
srgb_inverse_transfer_function (self->stops[self->n_stops-1].color.blue),
self->stops[self->n_stops-1].color.alpha);
cairo_set_source (cr, pattern);
@@ -624,25 +665,25 @@ gsk_radial_gradient_node_draw (GskRenderNode *node,
if (self->stops[0].offset > 0.0)
cairo_pattern_add_color_stop_rgba (pattern,
0.0,
self->stops[0].color.red,
self->stops[0].color.green,
self->stops[0].color.blue,
srgb_inverse_transfer_function (self->stops[0].color.red),
srgb_inverse_transfer_function (self->stops[0].color.green),
srgb_inverse_transfer_function (self->stops[0].color.blue),
self->stops[0].color.alpha);
for (i = 0; i < self->n_stops; i++)
{
cairo_pattern_add_color_stop_rgba (pattern,
self->stops[i].offset,
self->stops[i].color.red,
self->stops[i].color.green,
self->stops[i].color.blue,
srgb_inverse_transfer_function (self->stops[i].color.red),
srgb_inverse_transfer_function (self->stops[i].color.green),
srgb_inverse_transfer_function (self->stops[i].color.blue),
self->stops[i].color.alpha);
}
if (self->stops[self->n_stops-1].offset < 1.0)
cairo_pattern_add_color_stop_rgba (pattern,
1.0,
self->stops[self->n_stops-1].color.red,
self->stops[self->n_stops-1].color.green,
self->stops[self->n_stops-1].color.blue,
srgb_inverse_transfer_function (self->stops[self->n_stops-1].color.red),
srgb_inverse_transfer_function (self->stops[self->n_stops-1].color.green),
srgb_inverse_transfer_function (self->stops[self->n_stops-1].color.blue),
self->stops[self->n_stops-1].color.alpha);
gsk_cairo_rectangle (cr, &node->bounds);
@@ -1011,7 +1052,12 @@ _cairo_mesh_pattern_set_corner_rgba (cairo_pattern_t *pattern,
guint corner_num,
const GdkRGBA *rgba)
{
cairo_mesh_pattern_set_corner_color_rgba (pattern, corner_num, rgba->red, rgba->green, rgba->blue, rgba->alpha);
cairo_mesh_pattern_set_corner_color_rgba (pattern,
corner_num,
srgb_inverse_transfer_function (rgba->red),
srgb_inverse_transfer_function (rgba->green),
srgb_inverse_transfer_function (rgba->blue),
rgba->alpha);
}
static void
@@ -1409,7 +1455,7 @@ gsk_border_node_draw (GskRenderNode *node,
gdk_rgba_equal (&self->border_color[0], &self->border_color[2]) &&
gdk_rgba_equal (&self->border_color[0], &self->border_color[3]))
{
gdk_cairo_set_source_rgba (cr, &self->border_color[0]);
gsk_cairo_set_source_rgba (cr, &self->border_color[0]);
}
else
{
@@ -1771,6 +1817,7 @@ gsk_texture_node_draw (GskRenderNode *node,
}
surface = gdk_texture_download_surface (self->texture);
surface_srgb_to_linear_srgb (surface);
pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
@@ -1947,6 +1994,7 @@ gsk_texture_scale_node_draw (GskRenderNode *node,
cr2 = cairo_create (surface2);
surface = gdk_texture_download_surface (self->texture);
surface_srgb_to_linear_srgb (surface);
pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
@@ -2149,7 +2197,7 @@ draw_shadow (cairo_t *cr,
if (has_empty_clip (cr))
return;
gdk_cairo_set_source_rgba (cr, color);
gsk_cairo_set_source_rgba (cr, color);
shadow_cr = gsk_cairo_blur_start_drawing (cr, radius, blur_flags);
cairo_set_fill_rule (shadow_cr, CAIRO_FILL_RULE_EVEN_ODD);
@@ -2322,7 +2370,7 @@ draw_shadow_corner (cairo_t *cr,
g_hash_table_insert (corner_mask_cache, g_memdup2 (&key, sizeof (key)), mask);
}
gdk_cairo_set_source_rgba (cr, color);
gsk_cairo_set_source_rgba (cr, color);
pattern = cairo_pattern_create_for_surface (mask);
cairo_matrix_init_identity (&matrix);
cairo_matrix_scale (&matrix, sx, sy);
@@ -4693,7 +4741,7 @@ gsk_fill_node_draw (GskRenderNode *node,
if (gsk_render_node_get_node_type (self->child) == GSK_COLOR_NODE &&
gsk_rect_contains_rect (&self->child->bounds, &node->bounds))
{
gdk_cairo_set_source_rgba (cr, gsk_color_node_get_color (self->child));
gsk_cairo_set_source_rgba (cr, gsk_color_node_get_color (self->child));
cairo_fill (cr);
}
else
@@ -4886,7 +4934,7 @@ gsk_stroke_node_draw (GskRenderNode *node,
if (gsk_render_node_get_node_type (self->child) == GSK_COLOR_NODE &&
gsk_rect_contains_rect (&self->child->bounds, &node->bounds))
{
gdk_cairo_set_source_rgba (cr, gsk_color_node_get_color (self->child));
gsk_cairo_set_source_rgba (cr, gsk_color_node_get_color (self->child));
}
else
{
@@ -5111,7 +5159,7 @@ gsk_shadow_node_draw (GskRenderNode *node,
gsk_render_node_draw (self->child, cr);
pattern = cairo_pop_group (cr);
cairo_reset_clip (cr);
gdk_cairo_set_source_rgba (cr, &shadow->color);
gsk_cairo_set_source_rgba (cr, &shadow->color);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
cairo_restore (cr);
@@ -5728,6 +5776,16 @@ gsk_text_node_draw (GskRenderNode *node,
{
GskTextNode *self = (GskTextNode *) node;
PangoGlyphString glyphs;
#ifdef HAVE_PANGOFT
FT_Face face;
FT_Bool darken = 1;
FT_Parameter property = { FT_PARAM_TAG_STEM_DARKENING, &darken };
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
face = pango_fc_font_lock_face (PANGO_FC_FONT (self->font));
G_GNUC_END_IGNORE_DEPRECATIONS
FT_Face_Properties (face, 1, &property);
#endif
glyphs.num_glyphs = self->num_glyphs;
glyphs.glyphs = self->glyphs;
@@ -5735,11 +5793,17 @@ gsk_text_node_draw (GskRenderNode *node,
cairo_save (cr);
gdk_cairo_set_source_rgba (cr, &self->color);
gsk_cairo_set_source_rgba (cr, &self->color);
cairo_translate (cr, self->offset.x, self->offset.y);
pango_cairo_show_glyph_string (cr, self->font, &glyphs);
cairo_restore (cr);
#ifdef HAVE_PANGOFT
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
pango_fc_font_unlock_face (PANGO_FC_FONT (self->font));
G_GNUC_END_IGNORE_DEPRECATIONS
#endif
}
static void

View File

@@ -4,6 +4,7 @@ gsk_private_gl_shaders = [
'gl/resources/preamble.vs.glsl',
'gl/resources/border.glsl',
'gl/resources/blit.glsl',
'gl/resources/colorconvert.glsl',
'gl/resources/coloring.glsl',
'gl/resources/color.glsl',
'gl/resources/linear_gradient.glsl',
@@ -105,6 +106,7 @@ gsk_private_sources = files([
'gpu/gskgpushaderop.c',
'gpu/gskgpuscissorop.c',
'gpu/gskgpustraightalphaop.c',
'gpu/gskgpucolorconvertop.c',
'gpu/gskgputextureop.c',
'gpu/gskgpuuberop.c',
'gpu/gskgpuuploadop.c',

183
testsuite/gdk/colorstate.c Normal file
View File

@@ -0,0 +1,183 @@
#include <gtk.h>
static void
test_srgb (void)
{
GdkColorState *srgb;
GdkColorState *srgb_linear;
srgb = gdk_color_state_get_srgb ();
srgb_linear = gdk_color_state_get_srgb_linear ();
g_assert_true (gdk_color_state_equal (srgb, srgb));
g_assert_true (gdk_color_state_equal (srgb_linear, srgb_linear));
g_assert_false (gdk_color_state_equal (srgb, srgb_linear));
}
typedef enum
{
PNG,
TIFF,
} ImageFormat;
static const char *
image_format_name (ImageFormat image_format)
{
const char *names[] = { "png", "tiff" };
return names[image_format];
}
static const char *
color_state_name (GdkColorState *color_state)
{
if (color_state == gdk_color_state_get_srgb ())
return "srgb";
else if (color_state == gdk_color_state_get_srgb_linear ())
return "srgb-linear";
else
return "unknown";
}
static const char *
memory_format_name (GdkMemoryFormat format)
{
if (format == GDK_MEMORY_R8G8B8A8)
return "RGBA8";
else if (format == GDK_MEMORY_R16G16B16A16)
return "RGBA16";
else
return "unknown";
}
typedef struct
{
GdkMemoryFormat format;
GdkColorState *color_state;
ImageFormat image_format;
} ImageTest;
static GBytes *
get_image_data (GdkMemoryFormat format)
{
guchar *data;
gsize size;
switch ((int) format)
{
case GDK_MEMORY_R8G8B8A8:
data = g_new (guchar, 4);
size = 4;
data[0] = 128;
data[1] = 10;
data[2] = 245;
data[3] = 255;
break;
case GDK_MEMORY_R16G16B16A16:
{
guint16 *data16;
data16 = g_new (guint16, 4);
data16[0] = (128 << 8) + 10;
data16[1] = (10 << 8) + 120;
data16[2] = (245 << 8) + 140;
data16[3] = (255 << 8) + 245;
data = (guchar *) data16;
size = 8;
}
break;
default:
g_assert_not_reached ();
}
return g_bytes_new (data, size);
}
static void
test_image_roundtrip (gconstpointer data)
{
const ImageTest *test = data;
gsize bpp;
GBytes *bytes;
GdkTexture *texture;
GBytes *saved;
GdkTexture *texture2;
GError *error = NULL;
bytes = get_image_data (test->format);
bpp = g_bytes_get_size (bytes);
texture = gdk_memory_texture_new_with_color_state (1, 1, test->format, test->color_state, bytes, bpp);
switch (test->image_format)
{
case PNG:
saved = gdk_texture_save_to_png_bytes (texture);
texture2 = gdk_texture_new_from_bytes (saved, &error);
g_assert_no_error (error);
g_bytes_unref (saved);
break;
case TIFF:
saved = gdk_texture_save_to_tiff_bytes (texture);
texture2 = gdk_texture_new_from_bytes (saved, &error);
g_assert_no_error (error);
g_bytes_unref (saved);
break;
default:
g_assert_not_reached ();
}
g_assert_true (gdk_color_state_equal (gdk_texture_get_color_state (texture),
gdk_texture_get_color_state (texture2)));
g_assert_true (gdk_texture_get_format (texture) == gdk_texture_get_format (texture2));
g_object_unref (texture2);
g_object_unref (texture);
g_bytes_unref (bytes);
}
static void
add_image_roundtrip_tests (void)
{
ImageFormat image_formats[] = { PNG, TIFF };
GdkColorState *color_states[2];
GdkMemoryFormat formats[] = { GDK_MEMORY_R8G8B8A8, GDK_MEMORY_R16G16B16A16 };
color_states[0] = gdk_color_state_get_srgb ();
color_states[1] = gdk_color_state_get_srgb_linear ();
for (int i = 0; i < G_N_ELEMENTS (image_formats); i++)
for (int j = 0; j < G_N_ELEMENTS (color_states); j++)
for (int k = 0; k < G_N_ELEMENTS (formats); k++)
{
char *path = g_strdup_printf ("/colorstate/image/%s/%s/%s",
image_format_name (image_formats[i]),
color_state_name (color_states[j]),
memory_format_name (formats[k]));
ImageTest *data = g_new (ImageTest, 1);
data->image_format = image_formats[i];
data->color_state = color_states[j];
data->format = formats[k];
g_test_add_data_func_full (path, data, test_image_roundtrip, g_free);
g_free (path);
}
}
int
main (int argc, char *argv[])
{
gtk_init ();
(g_test_init) (&argc, &argv, NULL);
g_test_add_func ("/colorstate/srgb", test_srgb);
add_image_roundtrip_tests ();
return g_test_run ();
}

View File

@@ -57,6 +57,7 @@ foreach t : tests
endforeach
internal_tests = [
{ 'name': 'colorstate' },
{ 'name': 'image' },
{ 'name': 'texture' },
{ 'name': 'gltexture' },

View File

@@ -212,13 +212,13 @@ compare_xfails_small_texture = [
variants = {
'plain': '--plain',
'flipped': '--flip',
'rotated': '--rotate',
'repeated': '--repeat',
'masked': '--mask',
'replayed': '--replay',
'clipped': '--clip',
'colorflipped': '--colorflip',
#'flipped': '--flip',
#'rotated': '--rotate',
#'repeated': '--repeat',
#'masked': '--mask',
#'replayed': '--replay',
#'clipped': '--clip',
#'colorflipped': '--colorflip',
}
compare_xfails = {

141
tools/gtk-image-tool-info.c Normal file
View File

@@ -0,0 +1,141 @@
/* Copyright 2024 Red Hat, Inc.
*
* GTK is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* GTK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GTK; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <glib/gi18n-lib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include "gtk-image-tool.h"
static const char *
get_format_name (GdkMemoryFormat format)
{
const char *names[] = {
"*BGRA8",
"*ARGB8",
"*RGBA8",
"BGRA8",
"ARGB8",
"RGBA8",
"ABGR8",
"RGB8",
"BGR8",
"RGB16",
"*RGBA16",
"RGBA16",
"RGB16f",
"*RGBA16f",
"RGBA16f",
"RGB32f",
"*RGBA32f",
"RGBA32f"
"*GA8",
"GA8",
"G8",
"*GA16",
"GA16",
"G16",
"A8",
"A16",
"A16f",
"A32f",
"*ABGR8",
"BGRX8",
"XRGB8",
"RGBX8",
"XBGR8",
};
return names[format];
}
static const char *
get_color_state_name (GdkColorState *color_state)
{
if (color_state == gdk_color_state_get_srgb ())
return "srgb";
else if (color_state == gdk_color_state_get_srgb_linear ())
return "srgb-linear";
else
return "unknown";
}
static void
file_info (const char *filename)
{
GdkTexture *texture;
texture = load_image_file (filename);
g_print (_("Size: %dx%d\n"), gdk_texture_get_width (texture), gdk_texture_get_height (texture));
g_print (_("Format: %s\n"), get_format_name (gdk_texture_get_format (texture)));
g_print (_("Colorstate: %s\n"), get_color_state_name (gdk_texture_get_color_state (texture)));
g_object_unref (texture);
}
void
do_info (int *argc,
const char ***argv)
{
GOptionContext *context;
char **filenames = NULL;
const GOptionEntry entries[] = {
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE") },
{ NULL, }
};
GError *error = NULL;
g_set_prgname ("gtk4-image-tool info");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Provide information about the image."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
g_option_context_free (context);
if (filenames == NULL)
{
g_printerr (_("No image file specified\n"));
exit (1);
}
if (g_strv_length (filenames) > 1)
{
g_printerr (_("Can only accept a single image file\n"));
exit (1);
}
file_info (filenames[0]);
g_strfreev (filenames);
}

170
tools/gtk-image-tool-save.c Normal file
View File

@@ -0,0 +1,170 @@
/* Copyright 2024 Red Hat, Inc.
*
* GTK is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* GTK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GTK; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <glib/gi18n-lib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include "gtk-image-tool.h"
static GdkMemoryFormat
format_from_name (const char *name)
{
const char *names[] = {
"*BGRA8", "*ARGB8", "*RGBA8", "BGRA8", "ARGB8", "RGBA8", "ABGR8", "RGB8", "BGR8", "RGB16",
"*RGBA16", "RGBA16", "RGB16f", "*RGBA16f", "RGBA16f", "RGB32f", "*RGBA32f", "RGBA32f", "*GA8",
"GA8", "G8", "*GA16", "GA16", "G16", "A8", "A16", "A16f", "A32f", "*ABGR8", "BGRX8", "XRGB8",
"RGBX8", "XBGR8",
};
for (int i = 0; i < G_N_ELEMENTS (names); i++)
{
if (g_strcmp0 (name, names[i]) == 0)
return (GdkMemoryFormat) i;
}
g_printerr ("Unknown memory format\n");
exit (1);
return 0;
}
static GdkColorState *
color_state_from_name (const char *name)
{
if (g_strcmp0 (name, "srgb-linear") == 0)
return gdk_color_state_get_srgb_linear ();
else if (g_strcmp0 (name, "srgb") == 0)
return gdk_color_state_get_srgb ();
g_printerr ("Unknown color state\n");
exit (1);
return gdk_color_state_get_srgb ();
}
static void
save_image (const char *filename,
const char *output,
GdkMemoryFormat format,
GdkColorState *color_state)
{
GdkTexture *orig;
GdkTextureDownloader *downloader;
GBytes *bytes;
gsize stride;
GdkTexture *texture;
orig = load_image_file (filename);
downloader = gdk_texture_downloader_new (orig);
gdk_texture_downloader_set_format (downloader, format);
#if 0
gdk_texture_downloader_set_color_state (downloader, color_state);
#endif
bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
#if 0
texture = gdk_memory_texture_new_with_color_state (gdk_texture_get_width (orig),
gdk_texture_get_height (orig),
format,
color_state,
bytes,
stride);
#else
texture = gdk_memory_texture_new (gdk_texture_get_width (orig),
gdk_texture_get_height (orig),
format,
bytes,
stride);
#endif
if (g_str_has_suffix (output, ".tiff"))
gdk_texture_save_to_tiff (texture, output);
else
gdk_texture_save_to_png (texture, output);
g_object_unref (texture);
g_bytes_unref (bytes);
gdk_texture_downloader_free (downloader);
g_object_unref (orig);
}
void
do_save (int *argc,
const char ***argv)
{
GOptionContext *context;
char **filenames = NULL;
char *format_name = NULL;
char *colorstate_name = NULL;
const GOptionEntry entries[] = {
{ "format", 0, 0, G_OPTION_ARG_STRING, &format_name, N_("Format to use"), N_("FORMAT") },
{ "colorstate", 0, 0, G_OPTION_ARG_STRING, &colorstate_name, N_("Colorstate to use"), N_("COLORSTATE") },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE") },
{ NULL, }
};
GError *error = NULL;
GdkMemoryFormat format = GDK_MEMORY_DEFAULT;
GdkColorState *color_state = gdk_color_state_get_srgb ();
g_set_prgname ("gtk4-image-tool save");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Save theimage as a new file."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
g_option_context_free (context);
if (filenames == NULL)
{
g_printerr (_("No image file specified\n"));
exit (1);
}
if (g_strv_length (filenames) != 2)
{
g_printerr (_("Can only accept a single image file and output file\n"));
exit (1);
}
if (format_name)
format = format_from_name (format_name);
if (colorstate_name)
color_state = color_state_from_name (colorstate_name);
save_image (filenames[0], filenames[1], format, color_state);
g_strfreev (filenames);
}

129
tools/gtk-image-tool-show.c Normal file
View File

@@ -0,0 +1,129 @@
/* Copyright 2024 Red Hat, Inc.
*
* GTK is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* GTK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GTK; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <glib/gi18n-lib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include "gtk-image-tool.h"
static void
set_window_title (GtkWindow *window,
const char *filename)
{
char *name;
name = g_path_get_basename (filename);
gtk_window_set_title (window, name);
g_free (name);
}
static void
quit_cb (GtkWidget *widget,
gpointer user_data)
{
gboolean *is_done = user_data;
*is_done = TRUE;
g_main_context_wakeup (NULL);
}
static void
show_file (const char *filename)
{
GdkTexture *texture;
GtkWidget *sw;
GtkWidget *window;
gboolean done = FALSE;
GtkWidget *picture;
texture = load_image_file (filename);
picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (texture));
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
gtk_picture_set_content_fit (GTK_PICTURE (picture), GTK_CONTENT_FIT_SCALE_DOWN);
sw = gtk_scrolled_window_new ();
gtk_scrolled_window_set_propagate_natural_width (GTK_SCROLLED_WINDOW (sw), TRUE);
gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (sw), TRUE);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), picture);
window = gtk_window_new ();
set_window_title (GTK_WINDOW (window), filename);
gtk_window_set_child (GTK_WINDOW (window), sw);
gtk_window_present (GTK_WINDOW (window));
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
while (!done)
g_main_context_iteration (NULL, TRUE);
g_object_unref (texture);
}
void
do_show (int *argc,
const char ***argv)
{
GOptionContext *context;
char **filenames = NULL;
const GOptionEntry entries[] = {
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, N_("FILE") },
{ NULL, }
};
GError *error = NULL;
g_set_prgname ("gtk4-image-tool show");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Show the image."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
g_option_context_free (context);
if (filenames == NULL)
{
g_printerr (_("No image file specified\n"));
exit (1);
}
if (g_strv_length (filenames) > 1)
{
g_printerr (_("Can only accept a single image file\n"));
exit (1);
}
show_file (filenames[0]);
g_strfreev (filenames);
}

View File

@@ -0,0 +1,48 @@
/* Copyright 2024 Red Hat, Inc.
*
* GTK is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* GTK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GTK; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <glib/gi18n-lib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include "gtk-image-tool.h"
GdkTexture *
load_image_file (const char *filename)
{
GError *error = NULL;
GdkTexture *texture;
texture = gdk_texture_new_from_filename (filename, &error);
if (!texture)
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
return texture;
}

120
tools/gtk-image-tool.c Normal file
View File

@@ -0,0 +1,120 @@
/* Copyright 2024 Red Hat, Inc.
*
* GTK is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* GTK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GTK; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <glib/gi18n-lib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include "gtk-image-tool.h"
static void G_GNUC_NORETURN
usage (void)
{
g_print (_("Usage:\n"
" gtk4-image-tool [COMMAND] [OPTION…] FILE\n"
"\n"
"Perform various tasks on images.\n"
"\n"
"Commands:\n"
" info Show general information about the image\n"
" save Save the image as a new file\n"
" show Show the image\n"
"\n"));
exit (1);
}
static GLogWriterOutput
log_writer_func (GLogLevelFlags level,
const GLogField *fields,
gsize n_fields,
gpointer user_data)
{
gsize i;
const char *domain = NULL;
const char *message = NULL;
for (i = 0; i < n_fields; i++)
{
if (g_strcmp0 (fields[i].key, "GLIB_DOMAIN") == 0)
domain = fields[i].value;
else if (g_strcmp0 (fields[i].key, "MESSAGE") == 0)
message = fields[i].value;
}
if (message != NULL && !g_log_writer_default_would_drop (level, domain))
{
const char *prefix;
switch (level & G_LOG_LEVEL_MASK)
{
case G_LOG_LEVEL_ERROR:
prefix = "ERROR";
break;
case G_LOG_LEVEL_CRITICAL:
prefix = "CRITICAL";
break;
case G_LOG_LEVEL_WARNING:
prefix = "WARNING";
break;
default:
prefix = "INFO";
break;
}
g_printerr ("%s-%s: %s\n", domain, prefix, message);
}
return G_LOG_WRITER_HANDLED;
}
int
main (int argc, const char *argv[])
{
g_set_prgname ("gtk-image-tool");
g_log_set_writer_func (log_writer_func, NULL, NULL);
gtk_init_check ();
gtk_test_register_all_types ();
if (argc < 2)
usage ();
if (strcmp (argv[1], "--help") == 0)
usage ();
argv++;
argc--;
if (strcmp (argv[0], "info") == 0)
do_info (&argc, &argv);
else if (strcmp (argv[0], "save") == 0)
do_save (&argc, &argv);
else if (strcmp (argv[0], "show") == 0)
do_show (&argc, &argv);
else
usage ();
return 0;
}

8
tools/gtk-image-tool.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
void do_info (int *argc, const char ***argv);
void do_save (int *argc, const char ***argv);
void do_show (int *argc, const char ***argv);
GdkTexture * load_image_file (const char *filename);

View File

@@ -49,6 +49,11 @@ gtk_tools = [
'gtk-rendernode-tool-show.c',
'gtk-rendernode-tool-utils.c',
'../testsuite/reftests/reftest-compare.c'], [libgtk_dep] ],
['gtk4-image-tool', ['gtk-image-tool.c',
'gtk-image-tool-info.c',
'gtk-image-tool-save.c',
'gtk-image-tool-show.c',
'gtk-image-tool-utils.c'], [libgtk_dep] ],
['gtk4-update-icon-cache', ['updateiconcache.c', '../gtk/gtkiconcachevalidator.c' ] + extra_update_icon_cache_objs, [ libgtk_dep ] ],
['gtk4-encode-symbolic-svg', ['encodesymbolic.c'], [ libgtk_static_dep ] ],
]