Compare commits
68 Commits
main
...
matthiasc/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b2c9130a9 | ||
|
|
27361bf136 | ||
|
|
be2aaae7a9 | ||
|
|
be17bf29e1 | ||
|
|
3ef4e0b16c | ||
|
|
2dc0c6b380 | ||
|
|
7bb503128e | ||
|
|
b4bf26868a | ||
|
|
72ac0d0288 | ||
|
|
5898e922a1 | ||
|
|
c425d318f0 | ||
|
|
fc929b8282 | ||
|
|
b939184006 | ||
|
|
73589ef038 | ||
|
|
90fb6c2729 | ||
|
|
c79fd43cec | ||
|
|
b432d690ef | ||
|
|
d800c1db6b | ||
|
|
3b93225fc7 | ||
|
|
e4e1b7c451 | ||
|
|
f80ef35dc0 | ||
|
|
fe5e81757d | ||
|
|
a532b3dca5 | ||
|
|
a6f8367c0a | ||
|
|
da21a87de8 | ||
|
|
97c11ffc23 | ||
|
|
26dd0536f0 | ||
|
|
33c739b0f9 | ||
|
|
e4ba83ad4f | ||
|
|
17521e26f8 | ||
|
|
5a389874da | ||
|
|
ce344b9267 | ||
|
|
66e6d6728f | ||
|
|
4670c90312 | ||
|
|
b02cc7878a | ||
|
|
5ada992ac9 | ||
|
|
ba6c03e902 | ||
|
|
9ae493c86e | ||
|
|
023ecbf028 | ||
|
|
809c4d9ec1 | ||
|
|
a6fd0d0487 | ||
|
|
afb755a148 | ||
|
|
3f2d0dbb27 | ||
|
|
b819b928ea | ||
|
|
72b78d2da1 | ||
|
|
03ea3fd10b | ||
|
|
1b9243fed5 | ||
|
|
422340a1e3 | ||
|
|
60ebac2c71 | ||
|
|
3424f25a1f | ||
|
|
3fef469797 | ||
|
|
1dd812a858 | ||
|
|
38730808a5 | ||
|
|
0dedbb5b17 | ||
|
|
a433828f1a | ||
|
|
9624b67fdd | ||
|
|
0df63b0286 | ||
|
|
34f2fc9203 | ||
|
|
f90c0a30df | ||
|
|
3b6ce78400 | ||
|
|
e7ba7d5540 | ||
|
|
0ac0a5914c | ||
|
|
d976bf910c | ||
|
|
db2aab289c | ||
|
|
85e4e47d30 | ||
|
|
32740934b4 | ||
|
|
8acf1b78cf | ||
|
|
957a6505ca |
@@ -31,7 +31,11 @@ pacman --noconfirm -S --needed \
|
||||
mingw-w64-$MSYS2_ARCH-pango \
|
||||
mingw-w64-$MSYS2_ARCH-fribidi \
|
||||
mingw-w64-$MSYS2_ARCH-gst-plugins-bad \
|
||||
mingw-w64-$MSYS2_ARCH-shared-mime-info
|
||||
mingw-w64-$MSYS2_ARCH-shared-mime-info \
|
||||
mingw-w64-$MSYS2_ARCH-libpng \
|
||||
mingw-w64-$MSYS2_ARCH-libjpeg-turbo \
|
||||
mingw-w64-$MSYS2_ARCH-libtiff \
|
||||
mingw-w64-$MSYS2_ARCH-lcms2
|
||||
|
||||
mkdir -p _ccache
|
||||
export CCACHE_BASEDIR="$(pwd)"
|
||||
|
||||
|
After Width: | Height: | Size: 24 KiB |
BIN
demos/gtk-demo/ICC-Rendering-Intent-Test.jpg
Normal file
|
After Width: | Height: | Size: 290 KiB |
BIN
demos/gtk-demo/ICC-Rendering-Intent-Test.png
Normal file
|
After Width: | Height: | Size: 120 KiB |
BIN
demos/gtk-demo/ICC-Rendering-Intent-Test.tif
Normal file
86
demos/gtk-demo/colorprofiles.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/* Color Profiles
|
||||
*
|
||||
* Demonstrates support for color profiles.
|
||||
*
|
||||
* The test images used here are taken from http://displaycal.net/icc-color-management-test/
|
||||
* and are licensed under the Creative Commons BY-SA 4.0 International License
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkWidget *jpeg;
|
||||
static GtkWidget *png;
|
||||
static GtkWidget *tiff;
|
||||
static GtkWidget *noprofile;
|
||||
static GtkWidget *test1;
|
||||
static GtkWidget *test2;
|
||||
|
||||
static void
|
||||
on_changed (GtkCheckButton *button,
|
||||
gpointer user_data)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
const char *extension = NULL;
|
||||
char *path;
|
||||
|
||||
if (!gtk_check_button_get_active (GTK_CHECK_BUTTON (button)))
|
||||
return;
|
||||
|
||||
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (jpeg)))
|
||||
extension = ".jpg";
|
||||
else if (gtk_check_button_get_active (GTK_CHECK_BUTTON (png)))
|
||||
extension = ".png";
|
||||
else if (gtk_check_button_get_active (GTK_CHECK_BUTTON (tiff)))
|
||||
extension = ".tif";
|
||||
else if (gtk_check_button_get_active (GTK_CHECK_BUTTON (noprofile)))
|
||||
extension = "-expected-result-no-cm.png";
|
||||
|
||||
path = g_strconcat ("/colorprofiles/sRGB_Gray", extension, NULL);
|
||||
texture = gdk_texture_new_from_resource (path);
|
||||
gtk_picture_set_paintable (GTK_PICTURE (test1), GDK_PAINTABLE (texture));
|
||||
g_object_unref (texture);
|
||||
|
||||
path = g_strconcat ("/colorprofiles/ICC-Rendering-Intent-Test", extension, NULL);
|
||||
texture = gdk_texture_new_from_resource (path);
|
||||
gtk_picture_set_paintable (GTK_PICTURE (test2), GDK_PAINTABLE (texture));
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
do_colorprofiles (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GtkBuilderScope *scope;
|
||||
|
||||
scope = gtk_builder_cscope_new ();
|
||||
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope),
|
||||
"on_changed", G_CALLBACK (on_changed));
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_set_scope (builder, scope);
|
||||
gtk_builder_add_from_resource (builder, "/colorprofiles/colorprofiles.ui", NULL);
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
jpeg = GTK_WIDGET (gtk_builder_get_object (builder, "jpeg"));
|
||||
png = GTK_WIDGET (gtk_builder_get_object (builder, "png"));
|
||||
tiff = GTK_WIDGET (gtk_builder_get_object (builder, "tiff"));
|
||||
noprofile = GTK_WIDGET (gtk_builder_get_object (builder, "noprofile"));
|
||||
test1 = GTK_WIDGET (gtk_builder_get_object (builder, "test1"));
|
||||
test2 = GTK_WIDGET (gtk_builder_get_object (builder, "test2"));
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_object_unref (builder);
|
||||
g_object_unref (scope);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
94
demos/gtk-demo/colorprofiles.ui
Normal file
@@ -0,0 +1,94 @@
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="default-width">660</property>
|
||||
<property name="default-height">660</property>
|
||||
<property name="resizable">false</property>
|
||||
<property name="title">Color Profiles</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">File format:</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="jpeg">
|
||||
<property name="label">JPEG</property>
|
||||
<property name="active">1</property>
|
||||
<signal name="notify::active" handler="on_changed"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="png">
|
||||
<property name="label">PNG</property>
|
||||
<property name="group">jpeg</property>
|
||||
<signal name="notify::active" handler="on_changed"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="tiff">
|
||||
<property name="label">TIFF</property>
|
||||
<property name="group">png</property>
|
||||
<signal name="notify::active" handler="on_changed"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="noprofile">
|
||||
<property name="label">No profile</property>
|
||||
<property name="group">tiff</property>
|
||||
<signal name="notify::active" handler="on_changed"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Test 1: Matrix-based profile</property>
|
||||
<style>
|
||||
<class name="title-3"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPicture" id="test1">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="can-shrink">1</property>
|
||||
<property name="keep-aspect-ratio">1</property>
|
||||
<property name="file">resource:///colorprofiles/sRGB_Gray.jpg</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Test 2: Lookup table-based profile</property>
|
||||
<style>
|
||||
<class name="title-3"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPicture" id="test2">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="can-shrink">1</property>
|
||||
<property name="keep-aspect-ratio">1</property>
|
||||
<property name="file">resource:///colorprofiles/ICC-Rendering-Intent-Test.jpg</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -18,6 +18,17 @@
|
||||
<file>demoimage.c</file>
|
||||
<file>demoimage.h</file>
|
||||
</gresource>
|
||||
<gresource prefix="/colorprofiles">
|
||||
<file>colorprofiles.ui</file>
|
||||
<file>sRGB_Gray.jpg</file>
|
||||
<file>sRGB_Gray.png</file>
|
||||
<file>sRGB_Gray.tif</file>
|
||||
<file>sRGB_Gray-expected-result-no-cm.png</file>
|
||||
<file>ICC-Rendering-Intent-Test.png</file>
|
||||
<file>ICC-Rendering-Intent-Test.jpg</file>
|
||||
<file>ICC-Rendering-Intent-Test.tif</file>
|
||||
<file>ICC-Rendering-Intent-Test-expected-result-no-cm.png</file>
|
||||
</gresource>
|
||||
<gresource prefix="/constraints_builder">
|
||||
<file>constraints_builder.ui</file>
|
||||
</gresource>
|
||||
@@ -254,6 +265,7 @@
|
||||
<file>assistant.c</file>
|
||||
<file>builder.c</file>
|
||||
<file>clipboard.c</file>
|
||||
<file>colorprofiles.c</file>
|
||||
<file>combobox.c</file>
|
||||
<file>constraints.c</file>
|
||||
<file>constraints_interactive.c</file>
|
||||
|
||||
@@ -5,6 +5,7 @@ demos = files([
|
||||
'assistant.c',
|
||||
'builder.c',
|
||||
'clipboard.c',
|
||||
'colorprofiles.c',
|
||||
'combobox.c',
|
||||
'constraints.c',
|
||||
'constraints_interactive.c',
|
||||
|
||||
BIN
demos/gtk-demo/sRGB_Gray-expected-result-no-cm.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
demos/gtk-demo/sRGB_Gray.jpg
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
demos/gtk-demo/sRGB_Gray.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
demos/gtk-demo/sRGB_Gray.tif
Normal file
BIN
demos/widget-factory/color-profile-check.jpeg
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
demos/widget-factory/color-profile-check.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
demos/widget-factory/color-profile-check.tiff
Normal file
BIN
demos/widget-factory/linear-gradient-color.png
Normal file
|
After Width: | Height: | Size: 213 B |
BIN
demos/widget-factory/linear-gradient-monochrome.png
Normal file
|
After Width: | Height: | Size: 220 B |
BIN
demos/widget-factory/srgb-gradient-color.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
demos/widget-factory/srgb-gradient-monochrome.png
Normal file
|
After Width: | Height: | Size: 164 B |
@@ -6,3 +6,10 @@
|
||||
.toolbar {
|
||||
-gtk-icon-style: symbolic;
|
||||
}
|
||||
|
||||
.gtk-gradient-color {
|
||||
background: linear-gradient(to right, lime, red);
|
||||
}
|
||||
.gtk-gradient-monochrome {
|
||||
background: linear-gradient(to right, black, white);
|
||||
}
|
||||
|
||||
@@ -118,5 +118,12 @@
|
||||
<file>portland-rose.jpg</file>
|
||||
<file>nyc.jpg</file>
|
||||
<file>beach.jpg</file>
|
||||
<file>linear-gradient-color.png</file>
|
||||
<file>linear-gradient-monochrome.png</file>
|
||||
<file>srgb-gradient-color.png</file>
|
||||
<file>srgb-gradient-monochrome.png</file>
|
||||
<file>color-profile-check.png</file>
|
||||
<file>color-profile-check.jpeg</file>
|
||||
<file>color-profile-check.tiff</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
||||
@@ -1342,13 +1342,173 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
|
||||
<child>
|
||||
<object class="GtkNotebookPage">
|
||||
<property name="child">
|
||||
<object class="GtkBox" id="box8">
|
||||
<property name="orientation">1</property>
|
||||
<object class="GtkGrid">
|
||||
<property name="hexpand">0</property>
|
||||
<property name="row-spacing">6</property>
|
||||
<property name="column-spacing">6</property>
|
||||
<property name="margin-start">6</property>
|
||||
<property name="margin-end">6</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<property name="row-homogeneous">1</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">color</property>
|
||||
<style>
|
||||
<class name="caption-heading"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">0</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">sRGB</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPicture">
|
||||
<property name="file">resource:///org/gtk/WidgetFactory4/srgb-gradient-color.png</property>
|
||||
<property name="can-shrink">0</property>
|
||||
<property name="keep-aspect-ratio">0</property>
|
||||
<property name="hexpand">1</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">GTK</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPicture">
|
||||
<property name="width-request">128</property>
|
||||
<property name="keep-aspect-ratio">0</property>
|
||||
<style>
|
||||
<class name="gtk-gradient-color"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">linear</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPicture">
|
||||
<property name="file">resource:///org/gtk/WidgetFactory4/linear-gradient-color.png</property>
|
||||
<property name="can-shrink">0</property>
|
||||
<property name="keep-aspect-ratio">0</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">monochrome</property>
|
||||
<style>
|
||||
<class name="caption-heading"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">4</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">sRGB</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">5</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPicture">
|
||||
<property name="file">resource:///org/gtk/WidgetFactory4/srgb-gradient-monochrome.png</property>
|
||||
<property name="can-shrink">0</property>
|
||||
<property name="keep-aspect-ratio">0</property>
|
||||
<property name="hexpand">1</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">5</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">GTK</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">6</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPicture">
|
||||
<property name="width-request">128</property>
|
||||
<property name="keep-aspect-ratio">0</property>
|
||||
<style>
|
||||
<class name="gtk-gradient-monochrome"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">6</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">linear</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">7</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPicture">
|
||||
<property name="file">resource:///org/gtk/WidgetFactory4/linear-gradient-monochrome.png</property>
|
||||
<property name="can-shrink">0</property>
|
||||
<property name="keep-aspect-ratio">0</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">7</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
<property name="tab">
|
||||
<object class="GtkLabel" id="label8">
|
||||
<property name="label" translatable="1">page 1</property>
|
||||
<property name="label" translatable="1">Gradients</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
@@ -1357,13 +1517,91 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
|
||||
<object class="GtkNotebookPage">
|
||||
<property name="position">1</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox" id="box10">
|
||||
<property name="orientation">1</property>
|
||||
<object class="GtkGrid">
|
||||
<property name="hexpand">0</property>
|
||||
<property name="row-spacing">6</property>
|
||||
<property name="column-spacing">6</property>
|
||||
<property name="margin-start">6</property>
|
||||
<property name="margin-end">6</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<property name="row-homogeneous">1</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">image loading</property>
|
||||
<style>
|
||||
<class name="caption-heading"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">0</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.png</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">PNG</property>
|
||||
<property name="hexpand">1</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.jpeg</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">JPEG</property>
|
||||
<property name="hexpand">1</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.tiff</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">TIFF</property>
|
||||
<property name="hexpand">1</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
<property name="tab">
|
||||
<object class="GtkLabel" id="label9">
|
||||
<property name="label" translatable="1">page 2</property>
|
||||
<property name="label" translatable="1">Images</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
@@ -609,56 +609,39 @@ open_shared_memory (void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
gsize size;
|
||||
} PngData;
|
||||
|
||||
static cairo_status_t
|
||||
write_png_cb (void *closure,
|
||||
const guchar *data,
|
||||
unsigned int length)
|
||||
{
|
||||
PngData *png_data = closure;
|
||||
int fd = png_data->fd;
|
||||
|
||||
while (length)
|
||||
{
|
||||
gssize ret = write (fd, data, length);
|
||||
|
||||
if (ret <= 0)
|
||||
return CAIRO_STATUS_WRITE_ERROR;
|
||||
|
||||
png_data->size += ret;
|
||||
length -= ret;
|
||||
data += ret;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
guint32
|
||||
gdk_broadway_server_upload_texture (GdkBroadwayServer *server,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
guint32 id;
|
||||
cairo_surface_t *surface = gdk_texture_download_surface (texture);
|
||||
BroadwayRequestUploadTexture msg;
|
||||
PngData data;
|
||||
GBytes *bytes;
|
||||
const guchar *data;
|
||||
gsize size;
|
||||
int fd;
|
||||
|
||||
id = server->next_texture_id++;
|
||||
|
||||
data.fd = open_shared_memory ();
|
||||
data.size = 0;
|
||||
cairo_surface_write_to_png_stream (surface, write_png_cb, &data);
|
||||
bytes = gdk_texture_save_to_png_bytes (texture);
|
||||
fd = open_shared_memory ();
|
||||
data = g_bytes_get_data (bytes, &size);
|
||||
|
||||
msg.id = id;
|
||||
msg.offset = 0;
|
||||
msg.size = data.size;
|
||||
while (size)
|
||||
{
|
||||
gssize ret = write (fd, data, size);
|
||||
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
size -= ret;
|
||||
data += ret;
|
||||
}
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
/* This passes ownership of fd */
|
||||
gdk_broadway_server_send_fd_message (server, msg,
|
||||
BROADWAY_REQUEST_UPLOAD_TEXTURE, data.fd);
|
||||
BROADWAY_REQUEST_UPLOAD_TEXTURE, fd);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -39,26 +39,19 @@ gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context,
|
||||
{
|
||||
GdkBroadwayCairoContext *self = GDK_BROADWAY_CAIRO_CONTEXT (draw_context);
|
||||
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self));
|
||||
cairo_t *cr;
|
||||
cairo_region_t *repaint_region;
|
||||
int width, height, scale;
|
||||
int width, height;
|
||||
|
||||
width = gdk_surface_get_width (surface);
|
||||
height = gdk_surface_get_height (surface);
|
||||
scale = gdk_surface_get_scale_factor (surface);
|
||||
self->paint_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
width * scale, height * scale);
|
||||
cairo_surface_set_device_scale (self->paint_surface, scale, scale);
|
||||
self->paint_surface = gdk_surface_create_similar_surface (surface,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
width,
|
||||
height);
|
||||
|
||||
repaint_region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { 0, 0, width, height });
|
||||
cairo_region_union (region, repaint_region);
|
||||
cairo_region_destroy (repaint_region);
|
||||
|
||||
/* clear the repaint area */
|
||||
cr = cairo_create (self->paint_surface);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_fill (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -130,6 +130,7 @@ static const GdkDebugKey gdk_debug_keys[] = {
|
||||
{ "vulkan-validate", GDK_DEBUG_VULKAN_VALIDATE, "Load the Vulkan validation layer" },
|
||||
{ "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings", TRUE },
|
||||
{ "hdr", GDK_DEBUG_HDR, "Use HDR rendering if possible", TRUE },
|
||||
{ "srgb", GDK_DEBUG_SRGB, "Force sRRGB rendering and turn off color profiles" },
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <gdk/gdkcairo.h>
|
||||
#include <gdk/gdkcairocontext.h>
|
||||
#include <gdk/gdkclipboard.h>
|
||||
#include <gdk/gdkcolorprofile.h>
|
||||
#include <gdk/gdkconfig.h>
|
||||
#include <gdk/gdkcontentdeserializer.h>
|
||||
#include <gdk/gdkcontentformats.h>
|
||||
@@ -38,6 +39,7 @@
|
||||
#include <gdk/gdkcontentproviderimpl.h>
|
||||
#include <gdk/gdkcontentserializer.h>
|
||||
#include <gdk/gdkcursor.h>
|
||||
#include <gdk/gdkderivedprofile.h>
|
||||
#include <gdk/gdkdevice.h>
|
||||
#include <gdk/gdkdevicepad.h>
|
||||
#include <gdk/gdkdevicetool.h>
|
||||
@@ -53,6 +55,7 @@
|
||||
#include <gdk/gdkframetimings.h>
|
||||
#include <gdk/gdkglcontext.h>
|
||||
#include <gdk/gdkgltexture.h>
|
||||
#include <gdk/gdkiccprofile.h>
|
||||
#include <gdk/gdkkeys.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gdk/gdkmemorytexture.h>
|
||||
|
||||
112
gdk/gdkcairo.c
@@ -19,6 +19,10 @@
|
||||
|
||||
#include "gdkcairoprivate.h"
|
||||
|
||||
#include "gdkcolorprivate.h"
|
||||
#include "gdkcolorprofile.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/**
|
||||
@@ -32,14 +36,20 @@ void
|
||||
gdk_cairo_set_source_rgba (cairo_t *cr,
|
||||
const GdkRGBA *rgba)
|
||||
{
|
||||
GdkColor color;
|
||||
const float *components;
|
||||
|
||||
g_return_if_fail (cr != NULL);
|
||||
g_return_if_fail (rgba != NULL);
|
||||
|
||||
gdk_color_convert_rgba (&color, gdk_cairo_get_color_profile (cr), rgba);
|
||||
components = gdk_color_get_components (&color);
|
||||
cairo_set_source_rgba (cr,
|
||||
rgba->red,
|
||||
rgba->green,
|
||||
rgba->blue,
|
||||
rgba->alpha);
|
||||
components[0],
|
||||
components[1],
|
||||
components[2],
|
||||
gdk_color_get_alpha (&color));
|
||||
gdk_color_finish (&color);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -399,3 +409,97 @@ gdk_cairo_region_from_clip (cairo_t *cr)
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
static cairo_user_data_key_t color_profile_key;
|
||||
|
||||
/**
|
||||
* gdk_cairo_surface_set_color_profile:
|
||||
* @surface: a surface
|
||||
* @profile: the profile to attach to the surface
|
||||
*
|
||||
* Attaches a `GdkColorProfile` to the Cairo surface.
|
||||
*
|
||||
* This is just auxiliary data for use by GTK, no Cairo functions
|
||||
* do interact with this information.
|
||||
*
|
||||
* Note that all Cairo compositing operations are assumed to happen
|
||||
* in a linear RGB color space, so if you want to use the surface
|
||||
* as a target for rendering in a color managed way, you should use
|
||||
* such a color profile.
|
||||
*
|
||||
* The default color profile is assumed to be sRGB, which is not
|
||||
* linear.
|
||||
*
|
||||
* Since: 4.6
|
||||
**/
|
||||
void
|
||||
gdk_cairo_surface_set_color_profile (cairo_surface_t *surface,
|
||||
GdkColorProfile *profile)
|
||||
{
|
||||
g_return_if_fail (surface != NULL);
|
||||
g_return_if_fail (GDK_IS_COLOR_PROFILE (profile));
|
||||
|
||||
cairo_surface_set_user_data (surface,
|
||||
&color_profile_key,
|
||||
g_object_ref (profile),
|
||||
g_object_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_cairo_surface_get_color_profile:
|
||||
* @surface: a surface
|
||||
*
|
||||
* Gets the color profile GTK assumes for the surface. See
|
||||
* gdk_cairo_surface_set_color_profile() for details.
|
||||
*
|
||||
* Returns: (transfer none): the assumed profile
|
||||
*
|
||||
* Since: 4.6
|
||||
**/
|
||||
GdkColorProfile *
|
||||
gdk_cairo_surface_get_color_profile (cairo_surface_t *surface)
|
||||
{
|
||||
GdkColorProfile *profile;
|
||||
|
||||
g_return_val_if_fail (surface != NULL, gdk_color_profile_get_srgb ());
|
||||
|
||||
profile = cairo_surface_get_user_data (surface, &color_profile_key);
|
||||
if (profile == NULL)
|
||||
profile = gdk_color_profile_get_srgb ();
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_cairo_get_color_profile:
|
||||
* @cr: a cairo context
|
||||
*
|
||||
* Gets the color profile GTK assumes for the cairo context.
|
||||
*
|
||||
* Returns: (transfer none): the assumed profile
|
||||
*
|
||||
* Since: 4.6
|
||||
**/
|
||||
GdkColorProfile *
|
||||
gdk_cairo_get_color_profile (cairo_t *cr)
|
||||
{
|
||||
GdkColorProfile *profile;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
g_return_val_if_fail (cr != NULL, gdk_color_profile_get_srgb ());
|
||||
|
||||
surface = cairo_get_group_target (cr);
|
||||
profile = cairo_surface_get_user_data (surface, &color_profile_key);
|
||||
if (profile != NULL)
|
||||
return profile;
|
||||
|
||||
/* theoretically, we should walk the whole group stack, but I don't
|
||||
* think Cairo lets us do that
|
||||
*/
|
||||
surface = cairo_get_target (cr);
|
||||
profile = cairo_surface_get_user_data (surface, &color_profile_key);
|
||||
if (profile != NULL)
|
||||
return profile;
|
||||
|
||||
return gdk_color_profile_get_srgb ();
|
||||
}
|
||||
|
||||
@@ -46,9 +46,15 @@ void gdk_cairo_region (cairo_t *cr,
|
||||
const cairo_region_t *region);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
cairo_region_t *
|
||||
gdk_cairo_region_create_from_surface
|
||||
(cairo_surface_t *surface);
|
||||
cairo_region_t * gdk_cairo_region_create_from_surface (cairo_surface_t *surface);
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
void gdk_cairo_surface_set_color_profile (cairo_surface_t *surface,
|
||||
GdkColorProfile *profile);
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkColorProfile * gdk_cairo_surface_get_color_profile (cairo_surface_t *surface);
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkColorProfile * gdk_cairo_get_color_profile (cairo_t *cr);
|
||||
|
||||
GDK_DEPRECATED_IN_4_6_FOR(gdk_gl_texture_new)
|
||||
void gdk_cairo_draw_from_gl (cairo_t *cr,
|
||||
|
||||
160
gdk/gdkcolor.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* Copyright (C) 2021 Benjamin Otte
|
||||
*
|
||||
* 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 "gdkcolorprivate.h"
|
||||
#include "gdkiccprofileprivate.h"
|
||||
#include "gdkderivedprofile.h"
|
||||
|
||||
static inline cmsHTRANSFORM *
|
||||
gdk_color_get_transform (GdkICCProfile *src,
|
||||
GdkICCProfile *dest)
|
||||
{
|
||||
cmsHPROFILE *src_profile, *dest_profile;
|
||||
|
||||
src_profile = gdk_icc_profile_get_lcms_profile (GDK_ICC_PROFILE (src));
|
||||
dest_profile = gdk_icc_profile_get_lcms_profile (GDK_ICC_PROFILE (dest));
|
||||
|
||||
return gdk_icc_profile_lookup_transform (src,
|
||||
cmsFormatterForColorspaceOfProfile (src_profile, 4, 1),
|
||||
dest,
|
||||
cmsFormatterForColorspaceOfProfile (dest_profile, 4, 1));
|
||||
}
|
||||
|
||||
void
|
||||
gdk_color_convert (GdkColor *self,
|
||||
GdkColorProfile *profile,
|
||||
const GdkColor *other)
|
||||
{
|
||||
GdkColorProfile *src_profile, *dest_profile;
|
||||
gsize n_components;
|
||||
float *in;
|
||||
|
||||
n_components = gdk_color_profile_get_n_components (profile);
|
||||
|
||||
gdk_color_init (self, profile, other->alpha, NULL, n_components);
|
||||
|
||||
if (GDK_IS_DERIVED_PROFILE (other->profile))
|
||||
{
|
||||
in = g_alloca (sizeof (float) * n_components);
|
||||
gdk_derived_profile_convert_to_base_profile (GDK_DERIVED_PROFILE (other->profile),
|
||||
gdk_color_get_components (other),
|
||||
in);
|
||||
src_profile = gdk_derived_profile_get_base_profile (GDK_DERIVED_PROFILE (other->profile));
|
||||
}
|
||||
else
|
||||
{
|
||||
in = (float *)gdk_color_get_components (other);
|
||||
src_profile = other->profile;
|
||||
}
|
||||
|
||||
if (GDK_IS_DERIVED_PROFILE (profile))
|
||||
dest_profile = gdk_derived_profile_get_base_profile (GDK_DERIVED_PROFILE (profile));
|
||||
else
|
||||
dest_profile = profile;
|
||||
|
||||
cmsDoTransform (gdk_color_get_transform (GDK_ICC_PROFILE (src_profile),
|
||||
GDK_ICC_PROFILE (dest_profile)),
|
||||
in,
|
||||
(float *) gdk_color_get_components (self),
|
||||
1);
|
||||
|
||||
if (GDK_IS_DERIVED_PROFILE (profile))
|
||||
gdk_derived_profile_convert_from_base_profile (GDK_DERIVED_PROFILE (profile),
|
||||
gdk_color_get_components (self),
|
||||
(float *)gdk_color_get_components (self));
|
||||
}
|
||||
|
||||
void
|
||||
gdk_color_convert_rgba (GdkColor *self,
|
||||
GdkColorProfile *profile,
|
||||
const GdkRGBA *rgba)
|
||||
{
|
||||
GdkColorProfile *dest_profile;
|
||||
gsize n_components;
|
||||
|
||||
n_components = gdk_color_profile_get_n_components (profile);
|
||||
gdk_color_init (self, profile, rgba->alpha, NULL, n_components);
|
||||
|
||||
if (GDK_IS_DERIVED_PROFILE (profile))
|
||||
dest_profile = gdk_derived_profile_get_base_profile (GDK_DERIVED_PROFILE (profile));
|
||||
else
|
||||
dest_profile = profile;
|
||||
|
||||
cmsDoTransform (gdk_color_get_transform (GDK_ICC_PROFILE (gdk_color_profile_get_srgb ()),
|
||||
GDK_ICC_PROFILE (dest_profile)),
|
||||
(float[3]) { rgba->red, rgba->green, rgba->blue },
|
||||
(float *) gdk_color_get_components (self),
|
||||
1);
|
||||
|
||||
if (GDK_IS_DERIVED_PROFILE (profile))
|
||||
gdk_derived_profile_convert_from_base_profile (GDK_DERIVED_PROFILE (profile),
|
||||
gdk_color_get_components (self),
|
||||
(float *)gdk_color_get_components (self));
|
||||
}
|
||||
|
||||
void
|
||||
gdk_color_mix (GdkColor *self,
|
||||
GdkColorProfile *color_profile,
|
||||
const GdkColor *src1,
|
||||
const GdkColor *src2,
|
||||
double progress)
|
||||
{
|
||||
if (src1->profile != color_profile)
|
||||
{
|
||||
GdkColor tmp;
|
||||
gdk_color_convert (&tmp, color_profile, src1);
|
||||
gdk_color_mix (self, color_profile, &tmp, src2, progress);
|
||||
}
|
||||
else if (src2->profile != color_profile)
|
||||
{
|
||||
GdkColor tmp;
|
||||
gdk_color_convert (&tmp, color_profile, src2);
|
||||
gdk_color_mix (self, color_profile, src1, &tmp, progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsize i, n;
|
||||
const float *s1, *s2;
|
||||
float *d;
|
||||
|
||||
n = gdk_color_profile_get_n_components (color_profile);
|
||||
|
||||
gdk_color_init (self,
|
||||
color_profile,
|
||||
src1->alpha * (1.0 - progress) + src2->alpha * progress,
|
||||
NULL, n);
|
||||
|
||||
d = (float *) gdk_color_get_components (self);
|
||||
s1 = gdk_color_get_components (src1);
|
||||
s2 = gdk_color_get_components (src2);
|
||||
|
||||
if (self->alpha == 0)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
d[i] = s1[i] * (1.0 - progress) + s2[i] * progress;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
d[i] = (s1[i] * src1->alpha * (1.0 - progress) + s2[i] * src2->alpha * progress) / self->alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
73
gdk/gdkcolorprivate.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* Copyright (C) 2021 Benjamin Otte
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_COLOR_PRIVATE_H__
|
||||
#define __GDK_COLOR_PRIVATE_H__
|
||||
|
||||
#include <gdk/gdkcolorprofile.h>
|
||||
#include <gdk/gdkrgba.h>
|
||||
|
||||
/* RGB - and it makes the struct size a multiple of 8 bytes, ie pointer-aligned */
|
||||
#define GDK_COLOR_MAX_NATIVE_COMPONENTS 3
|
||||
|
||||
typedef struct _GdkColor GdkColor;
|
||||
|
||||
struct _GdkColor
|
||||
{
|
||||
GdkColorProfile *profile;
|
||||
float alpha;
|
||||
union {
|
||||
float values[GDK_COLOR_MAX_NATIVE_COMPONENTS];
|
||||
float *components;
|
||||
};
|
||||
};
|
||||
|
||||
G_STATIC_ASSERT (sizeof (GdkColor) % sizeof (gpointer) == 0);
|
||||
|
||||
static inline void gdk_color_init (GdkColor *self,
|
||||
GdkColorProfile *profile,
|
||||
float alpha,
|
||||
float *components,
|
||||
gsize n_components);
|
||||
static inline void gdk_color_init_from_rgba (GdkColor *self,
|
||||
const GdkRGBA *rgba);
|
||||
static inline void gdk_color_finish (GdkColor *self);
|
||||
|
||||
void gdk_color_convert (GdkColor *self,
|
||||
GdkColorProfile *profile,
|
||||
const GdkColor *other);
|
||||
void gdk_color_convert_rgba (GdkColor *self,
|
||||
GdkColorProfile *profile,
|
||||
const GdkRGBA *rgba);
|
||||
|
||||
void gdk_color_mix (GdkColor *self,
|
||||
GdkColorProfile *color_profile,
|
||||
const GdkColor *src1,
|
||||
const GdkColor *src2,
|
||||
double progress);
|
||||
|
||||
static inline GdkColorProfile * gdk_color_get_color_profile (const GdkColor *self);
|
||||
static inline float gdk_color_get_alpha (const GdkColor *self);
|
||||
static inline const float * gdk_color_get_components (const GdkColor *self);
|
||||
static inline gsize gdk_color_get_n_components (const GdkColor *self);
|
||||
|
||||
#include "gdkcolorprivateimpl.h"
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
97
gdk/gdkcolorprivateimpl.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
*
|
||||
* Copyright (C) 2021 Benjamin Otte
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
static inline gboolean
|
||||
gdk_color_is_allocated (const GdkColor *self)
|
||||
{
|
||||
return GPOINTER_TO_SIZE (self->profile) & 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gdk_color_init (GdkColor *self,
|
||||
GdkColorProfile *profile,
|
||||
float alpha,
|
||||
float *components,
|
||||
gsize n_components)
|
||||
{
|
||||
gboolean allocated = n_components > GDK_COLOR_MAX_NATIVE_COMPONENTS;
|
||||
|
||||
g_assert (n_components == gdk_color_profile_get_n_components (profile));
|
||||
|
||||
self->profile = GSIZE_TO_POINTER (GPOINTER_TO_SIZE (g_object_ref (profile)) | allocated);
|
||||
self->alpha = alpha;
|
||||
if (allocated)
|
||||
{
|
||||
if (components)
|
||||
self->components = g_memdup (components, sizeof (float) * n_components);
|
||||
else
|
||||
self->components = g_new (float, n_components);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (components)
|
||||
memcpy (self->values, components, sizeof (float) * n_components);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
gdk_color_init_from_rgba (GdkColor *self,
|
||||
const GdkRGBA *rgba)
|
||||
{
|
||||
gdk_color_init (self,
|
||||
gdk_color_profile_get_srgb(),
|
||||
rgba->alpha,
|
||||
(float[3]) { rgba->red, rgba->green, rgba->blue },
|
||||
3);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gdk_color_finish (GdkColor *self)
|
||||
{
|
||||
if (gdk_color_is_allocated (self))
|
||||
g_free (self->components);
|
||||
|
||||
g_object_unref (gdk_color_get_color_profile (self));
|
||||
}
|
||||
|
||||
static inline GdkColorProfile *
|
||||
gdk_color_get_color_profile (const GdkColor *self)
|
||||
{
|
||||
return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (self->profile) & ~1);
|
||||
}
|
||||
|
||||
static inline float
|
||||
gdk_color_get_alpha (const GdkColor *self)
|
||||
{
|
||||
return self->alpha;
|
||||
}
|
||||
|
||||
static inline const float *
|
||||
gdk_color_get_components (const GdkColor *self)
|
||||
{
|
||||
if (gdk_color_is_allocated (self))
|
||||
return self->components;
|
||||
else
|
||||
return self->values;
|
||||
}
|
||||
|
||||
static inline gsize
|
||||
gdk_color_get_n_components (const GdkColor *self)
|
||||
{
|
||||
return gdk_color_profile_get_n_components (gdk_color_get_color_profile (self));
|
||||
}
|
||||
146
gdk/gdkcolorprofile.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* gdkcolor_profile.c
|
||||
*
|
||||
* Copyright 2021 (c) Benjamin Otte
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GdkColorProfile:
|
||||
*
|
||||
* `GdkColorProfile` is used to describe color spaces.
|
||||
*
|
||||
* It is used to associate color profiles defined by the [International
|
||||
* Color Consortium (ICC)](https://color.org/) with texture and color data.
|
||||
*
|
||||
* Each `GdkColorProfile` encapsulates an
|
||||
* [ICC profile](https://en.wikipedia.org/wiki/ICC_profile). That profile
|
||||
* can be queried via the using [property@Gdk.ColorProfile:icc-profile]
|
||||
* property.
|
||||
*
|
||||
* `GdkColorProfile` objects are immutable and therefore threadsafe.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkcolorprofileprivate.h"
|
||||
|
||||
#include "gdkintl.h"
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GdkColorProfile, gdk_color_profile, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gdk_color_profile_init (GdkColorProfile *profile)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_color_profile_real_is_linear (GdkColorProfile *profile)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gsize
|
||||
gdk_color_profile_real_get_n_components (GdkColorProfile *profile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_color_profile_real_equal (gconstpointer profile1,
|
||||
gconstpointer profile2)
|
||||
{
|
||||
return profile1 == profile2;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_color_profile_class_init (GdkColorProfileClass *klass)
|
||||
{
|
||||
klass->is_linear = gdk_color_profile_real_is_linear;
|
||||
klass->get_n_components = gdk_color_profile_real_get_n_components;
|
||||
klass->equal = gdk_color_profile_real_equal;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_profile_is_linear:
|
||||
* @self: a `GdkColorProfile`
|
||||
*
|
||||
* Checks if the given profile is linear.
|
||||
*
|
||||
* GTK tries to do compositing in a linear profile.
|
||||
*
|
||||
* Some profiles may be linear, but it is not possible to
|
||||
* determine this easily. In those cases %FALSE will be returned.
|
||||
*
|
||||
* Returns: %TRUE if the profile can be proven linear
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
gboolean
|
||||
gdk_color_profile_is_linear (GdkColorProfile *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_COLOR_PROFILE (self), FALSE);
|
||||
|
||||
return GDK_COLOR_PROFILE_GET_CLASS (self)->is_linear (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_profile_get_n_components:
|
||||
* @self: a `GdkColorProfile
|
||||
*
|
||||
* Gets the number of color components - also called channels - for
|
||||
* the given profile. Note that this does not consider an alpha
|
||||
* channel because color profiles have no alpha information. So
|
||||
* for any form of RGB profile, this returned number will be 3.
|
||||
*
|
||||
* Returns: The number of components
|
||||
**/
|
||||
gsize
|
||||
gdk_color_profile_get_n_components (GdkColorProfile *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_COLOR_PROFILE (self), 3);
|
||||
|
||||
return GDK_COLOR_PROFILE_GET_CLASS (self)->get_n_components (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_profile_equal:
|
||||
* @profile1: (type GdkColorProfile): a `GdkColorProfile`
|
||||
* @profile2: (type GdkColorProfile): another `GdkColorProfile`
|
||||
*
|
||||
* Compares two `GdkColorProfile`s for equality.
|
||||
*
|
||||
* Note that this function is not guaranteed to be perfect and two equal
|
||||
* profiles may compare not equal. However, different profiles will
|
||||
* never compare equal.
|
||||
*
|
||||
* Returns: %TRUE if the two color profiles compare equal
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
gboolean
|
||||
gdk_color_profile_equal (gconstpointer profile1,
|
||||
gconstpointer profile2)
|
||||
{
|
||||
if (profile1 == profile2)
|
||||
return TRUE;
|
||||
|
||||
if (G_OBJECT_TYPE (profile1) != G_OBJECT_TYPE (profile2))
|
||||
return FALSE;
|
||||
|
||||
return GDK_COLOR_PROFILE_GET_CLASS (profile1)->equal (profile1, profile2);
|
||||
}
|
||||
69
gdk/gdkcolorprofile.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* gdkcolor_profile.h
|
||||
*
|
||||
* Copyright 2021 (c) Benjamin Otte
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_COLOR_PROFILE_H__
|
||||
#define __GDK_COLOR_PROFILE_H__
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdkversionmacros.h>
|
||||
#include <gdk/gdktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_COLOR_PROFILE (gdk_color_profile_get_type ())
|
||||
|
||||
#define GDK_COLOR_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_COLOR_PROFILE, GdkColorProfile))
|
||||
#define GDK_IS_COLOR_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_COLOR_PROFILE))
|
||||
#define GDK_COLOR_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_COLOR_PROFILE, GdkColorProfileClass))
|
||||
#define GDK_IS_COLOR_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_COLOR_PROFILE))
|
||||
#define GDK_COLOR_PROFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_COLOR_PROFILE, GdkColorProfileClass))
|
||||
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkColorProfile, g_object_unref)
|
||||
|
||||
typedef struct _GdkColorProfileClass GdkColorProfileClass;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GType gdk_color_profile_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkColorProfile * gdk_color_profile_get_srgb (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkColorProfile * gdk_color_profile_new_from_icc_bytes (GBytes *bytes,
|
||||
GError **error);
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GBytes * gdk_color_profile_get_icc_profile (GdkColorProfile *self);
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
gboolean gdk_color_profile_is_linear (GdkColorProfile *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
gsize gdk_color_profile_get_n_components (GdkColorProfile *self) G_GNUC_PURE;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
gboolean gdk_color_profile_equal (gconstpointer profile1,
|
||||
gconstpointer profile2);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_COLOR_PROFILE_H__ */
|
||||
32
gdk/gdkcolorprofileprivate.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef __GDK_COLOR_PROFILE_PRIVATE_H__
|
||||
#define __GDK_COLOR_PROFILE_PRIVATE_H__
|
||||
|
||||
#include "gdkcolorprofile.h"
|
||||
#include "gdkmemorytexture.h"
|
||||
|
||||
#include <lcms2.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct _GdkColorProfile
|
||||
{
|
||||
GObject parent_instance;
|
||||
};
|
||||
|
||||
struct _GdkColorProfileClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
gboolean (* is_linear) (GdkColorProfile *profile);
|
||||
gsize (* get_n_components) (GdkColorProfile *profile);
|
||||
gboolean (* equal) (gconstpointer profile1,
|
||||
gconstpointer profile2);
|
||||
};
|
||||
|
||||
GdkColorProfile * gdk_color_profile_get_srgb_linear (void) G_GNUC_CONST;
|
||||
GdkColorProfile * gdk_color_profile_get_hsl (void) G_GNUC_CONST;
|
||||
GdkColorProfile * gdk_color_profile_get_hwb (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_COLOR_PROFILE_PRIVATE_H__ */
|
||||
@@ -641,11 +641,7 @@ pixbuf_serializer (GdkContentSerializer *serializer)
|
||||
else if (G_VALUE_HOLDS (value, GDK_TYPE_TEXTURE))
|
||||
{
|
||||
GdkTexture *texture = g_value_get_object (value);
|
||||
cairo_surface_t *surface = gdk_texture_download_surface (texture);
|
||||
pixbuf = gdk_pixbuf_get_from_surface (surface,
|
||||
0, 0,
|
||||
gdk_texture_get_width (texture), gdk_texture_get_height (texture));
|
||||
cairo_surface_destroy (surface);
|
||||
pixbuf = gdk_pixbuf_get_from_texture (texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -51,6 +51,7 @@ typedef enum {
|
||||
GDK_DEBUG_VULKAN_VALIDATE = 1 << 22,
|
||||
GDK_DEBUG_DEFAULT_SETTINGS= 1 << 23,
|
||||
GDK_DEBUG_HDR = 1 << 24,
|
||||
GDK_DEBUG_SRGB = 1 << 25,
|
||||
} GdkDebugFlags;
|
||||
|
||||
extern guint _gdk_debug_flags;
|
||||
|
||||
513
gdk/gdkderivedprofile.c
Normal file
@@ -0,0 +1,513 @@
|
||||
/* gdkderivedprofile.c
|
||||
*
|
||||
* Copyright 2021 (c) 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GdkDerivedProfile:
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkderivedprofile.h"
|
||||
#include "gdkcolorprofileprivate.h"
|
||||
#include "gdkenumtypes.h"
|
||||
|
||||
#include "gdkintl.h"
|
||||
|
||||
struct _GdkDerivedProfile
|
||||
{
|
||||
GdkColorProfile parent_instance;
|
||||
|
||||
GdkColorSpace color_space;
|
||||
GdkColorProfile *base_profile;
|
||||
};
|
||||
|
||||
struct _GdkDerivedProfileClass
|
||||
{
|
||||
GdkColorProfileClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_BASE_PROFILE,
|
||||
PROP_COLOR_SPACE,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
|
||||
G_DEFINE_TYPE (GdkDerivedProfile, gdk_derived_profile, GDK_TYPE_COLOR_PROFILE)
|
||||
|
||||
static void
|
||||
gdk_derived_profile_init (GdkDerivedProfile *profile)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_derived_profile_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdkDerivedProfile *self = GDK_DERIVED_PROFILE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BASE_PROFILE:
|
||||
self->base_profile = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_COLOR_SPACE:
|
||||
self->color_space = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_derived_profile_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdkDerivedProfile *self = GDK_DERIVED_PROFILE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BASE_PROFILE:
|
||||
g_value_set_object (value, self->base_profile);
|
||||
break;
|
||||
|
||||
case PROP_COLOR_SPACE:
|
||||
g_value_set_enum (value, self->color_space);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_derived_profile_dispose (GObject *object)
|
||||
{
|
||||
GdkDerivedProfile *self = GDK_DERIVED_PROFILE (object);
|
||||
|
||||
g_clear_object (&self->base_profile);
|
||||
|
||||
G_OBJECT_CLASS (gdk_derived_profile_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_derived_profile_is_linear (GdkColorProfile *profile)
|
||||
{
|
||||
GdkDerivedProfile *self = GDK_DERIVED_PROFILE (profile);
|
||||
|
||||
return self->base_profile == gdk_color_profile_get_srgb_linear ();
|
||||
}
|
||||
|
||||
static gsize
|
||||
gdk_derived_profile_get_n_components (GdkColorProfile *profile)
|
||||
{
|
||||
GdkDerivedProfile *self = GDK_DERIVED_PROFILE (profile);
|
||||
|
||||
return gdk_color_profile_get_n_components (self->base_profile);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_derived_profile_equal (gconstpointer profile1,
|
||||
gconstpointer profile2)
|
||||
{
|
||||
GdkDerivedProfile *p1 = GDK_DERIVED_PROFILE (profile1);
|
||||
GdkDerivedProfile *p2 = GDK_DERIVED_PROFILE (profile2);
|
||||
|
||||
return p1->color_space == p2->color_space &&
|
||||
gdk_color_profile_equal (p1->base_profile, p2->base_profile);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_derived_profile_class_init (GdkDerivedProfileClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GdkColorProfileClass *profile_class = GDK_COLOR_PROFILE_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gdk_derived_profile_set_property;
|
||||
gobject_class->get_property = gdk_derived_profile_get_property;
|
||||
gobject_class->dispose = gdk_derived_profile_dispose;
|
||||
|
||||
profile_class->is_linear = gdk_derived_profile_is_linear;
|
||||
profile_class->get_n_components = gdk_derived_profile_get_n_components;
|
||||
profile_class->equal = gdk_derived_profile_equal;
|
||||
|
||||
/**
|
||||
* GdkDerivedProfile:base-profile: (attributes org.gtk.Property.get=gdk_derived_profile_get_base_profile)
|
||||
*
|
||||
* The base profile for this color profile.
|
||||
*/
|
||||
properties[PROP_BASE_PROFILE] =
|
||||
g_param_spec_object ("base-profile",
|
||||
P_("Base profile"),
|
||||
P_("Base profile for this color profile"),
|
||||
GDK_TYPE_ICC_PROFILE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GdkDerivedProfile:color-space: (attributes org.gtk.Property.get=gdk_derived_profile_get_color_space)
|
||||
*
|
||||
* The color space for this color profile.
|
||||
*/
|
||||
properties[PROP_COLOR_SPACE] =
|
||||
g_param_spec_enum ("color-space",
|
||||
P_("Color space"),
|
||||
P_("Color space for this color profile"),
|
||||
GDK_TYPE_COLOR_SPACE,
|
||||
GDK_COLOR_SPACE_HSL,
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_derived_profile_get_base_profile:
|
||||
* @profile: a `GdkDerivedProfile`
|
||||
*
|
||||
* Returns the base profile for this profile.
|
||||
*
|
||||
* Returns: (transfer none): the base profile
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
GdkColorProfile *
|
||||
gdk_derived_profile_get_base_profile (GdkDerivedProfile *self)
|
||||
{
|
||||
return self->base_profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_derived_profile_get_color_space:
|
||||
* @profile: a `GdkDerivedProfile`
|
||||
*
|
||||
* Returns the color space for this profile.
|
||||
*
|
||||
* Returns: the color space
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
GdkColorSpace
|
||||
gdk_derived_profile_get_color_space (GdkDerivedProfile *self)
|
||||
{
|
||||
return self->color_space;
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gdk_color_profile_get_hsl:
|
||||
*
|
||||
* Returns the color profile corresponding to the HSL
|
||||
* color space.
|
||||
*
|
||||
* It can display the same colors as sRGB, but it encodes
|
||||
* the coordinates differently.
|
||||
*
|
||||
* Returns: (transfer none): the color profile for the HSL
|
||||
* color space.
|
||||
*/
|
||||
GdkColorProfile *
|
||||
gdk_color_profile_get_hsl (void)
|
||||
{
|
||||
static GdkColorProfile *hsl_profile;
|
||||
|
||||
if (g_once_init_enter (&hsl_profile))
|
||||
{
|
||||
GdkColorProfile *new_profile;
|
||||
|
||||
new_profile = g_object_new (GDK_TYPE_DERIVED_PROFILE,
|
||||
"base-profile", gdk_color_profile_get_srgb (),
|
||||
"color-space", GDK_COLOR_SPACE_HSL,
|
||||
NULL);
|
||||
|
||||
g_assert (new_profile);
|
||||
|
||||
g_once_init_leave (&hsl_profile, new_profile);
|
||||
}
|
||||
|
||||
return hsl_profile;
|
||||
}
|
||||
|
||||
GdkColorProfile *
|
||||
gdk_color_profile_get_hwb (void)
|
||||
{
|
||||
static GdkColorProfile *hwb_profile;
|
||||
|
||||
if (g_once_init_enter (&hwb_profile))
|
||||
{
|
||||
GdkColorProfile *new_profile;
|
||||
|
||||
new_profile = g_object_new (GDK_TYPE_DERIVED_PROFILE,
|
||||
"base-profile", gdk_color_profile_get_srgb (),
|
||||
"color-space", GDK_COLOR_SPACE_HWB,
|
||||
NULL);
|
||||
|
||||
g_assert (new_profile);
|
||||
|
||||
g_once_init_leave (&hwb_profile, new_profile);
|
||||
}
|
||||
|
||||
return hwb_profile;
|
||||
}
|
||||
|
||||
static void
|
||||
hsl_to_rgb (const float *in,
|
||||
float *out)
|
||||
{
|
||||
float lightness;
|
||||
float saturation;
|
||||
float m1, m2;
|
||||
float orig_hue, hue;
|
||||
|
||||
lightness = in[2];
|
||||
saturation = in[1];
|
||||
orig_hue = in[0];
|
||||
|
||||
if (lightness <= 0.5)
|
||||
m2 = lightness * (1 + saturation);
|
||||
else
|
||||
m2 = lightness + saturation - lightness * saturation;
|
||||
m1 = 2 * lightness - m2;
|
||||
|
||||
if (saturation == 0)
|
||||
{
|
||||
out[0] = out[1] = out[2] = lightness;
|
||||
}
|
||||
else
|
||||
{
|
||||
hue = orig_hue + 120;
|
||||
while (hue > 360)
|
||||
hue -= 360;
|
||||
while (hue < 0)
|
||||
hue += 360;
|
||||
|
||||
if (hue < 60)
|
||||
out[0] = m1 + (m2 - m1) * hue / 60;
|
||||
else if (hue < 180)
|
||||
out[0] = m2;
|
||||
else if (hue < 240)
|
||||
out[0] = m1 + (m2 - m1) * (240 - hue) / 60;
|
||||
else
|
||||
out[0] = m1;
|
||||
|
||||
hue = orig_hue;
|
||||
while (hue > 360)
|
||||
hue -= 360;
|
||||
while (hue < 0)
|
||||
hue += 360;
|
||||
|
||||
if (hue < 60)
|
||||
out[1] = m1 + (m2 - m1) * hue / 60;
|
||||
else if (hue < 180)
|
||||
out[1] = m2;
|
||||
else if (hue < 240)
|
||||
out[1] = m1 + (m2 - m1) * (240 - hue) / 60;
|
||||
else
|
||||
out[1] = m1;
|
||||
|
||||
hue = orig_hue - 120;
|
||||
while (hue > 360)
|
||||
hue -= 360;
|
||||
while (hue < 0)
|
||||
hue += 360;
|
||||
|
||||
if (hue < 60)
|
||||
out[2] = m1 + (m2 - m1) * hue / 60;
|
||||
else if (hue < 180)
|
||||
out[2] = m2;
|
||||
else if (hue < 240)
|
||||
out[2] = m1 + (m2 - m1) * (240 - hue) / 60;
|
||||
else
|
||||
out[2] = m1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rgb_to_hsl (const float *in,
|
||||
float *out)
|
||||
{
|
||||
float min;
|
||||
float max;
|
||||
float red;
|
||||
float green;
|
||||
float blue;
|
||||
float delta;
|
||||
float hue;
|
||||
float saturation;
|
||||
float lightness;
|
||||
|
||||
red = in[0];
|
||||
green = in[1];
|
||||
blue = in[2];
|
||||
|
||||
if (red > green)
|
||||
{
|
||||
if (red > blue)
|
||||
max = red;
|
||||
else
|
||||
max = blue;
|
||||
|
||||
if (green < blue)
|
||||
min = green;
|
||||
else
|
||||
min = blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (green > blue)
|
||||
max = green;
|
||||
else
|
||||
max = blue;
|
||||
|
||||
if (red < blue)
|
||||
min = red;
|
||||
else
|
||||
min = blue;
|
||||
}
|
||||
|
||||
lightness = (max + min) / 2;
|
||||
saturation = 0;
|
||||
hue = 0;
|
||||
|
||||
if (max != min)
|
||||
{
|
||||
if (lightness <= 0.5)
|
||||
saturation = (max - min) / (max + min);
|
||||
else
|
||||
saturation = (max - min) / (2 - max - min);
|
||||
|
||||
delta = max -min;
|
||||
if (red == max)
|
||||
hue = (green - blue) / delta;
|
||||
else if (green == max)
|
||||
hue = 2 + (blue - red) / delta;
|
||||
else if (blue == max)
|
||||
hue = 4 + (red - green) / delta;
|
||||
|
||||
hue *= 60;
|
||||
if (hue < 0.0)
|
||||
hue += 360;
|
||||
}
|
||||
|
||||
out[0] = hue;
|
||||
out[1] = saturation;
|
||||
out[2] = lightness;
|
||||
}
|
||||
|
||||
static void
|
||||
hwb_to_rgb (const float *in,
|
||||
float *out)
|
||||
{
|
||||
float hue;
|
||||
float white;
|
||||
float black;
|
||||
float m[3];
|
||||
|
||||
hue = in[0];
|
||||
white = in[1];
|
||||
black = in[2];
|
||||
|
||||
white /= 100;
|
||||
black /= 100;
|
||||
|
||||
if (white + black >= 1)
|
||||
{
|
||||
out[0] = out[1] = out[2] = white / (white + black);
|
||||
return;
|
||||
}
|
||||
|
||||
m[0] = hue;
|
||||
m[1] = 1;
|
||||
m[2] = 0.5;
|
||||
|
||||
hsl_to_rgb (m, out);
|
||||
|
||||
out[0] = out[0] * (1 - white - black) + white;
|
||||
out[1] = out[1] * (1 - white - black) + white;
|
||||
out[2] = out[2] * (1 - white - black) + white;
|
||||
}
|
||||
|
||||
static void
|
||||
rgb_to_hwb (const float *in,
|
||||
float *out)
|
||||
{
|
||||
float white;
|
||||
float black;
|
||||
|
||||
rgb_to_hsl (in, out);
|
||||
|
||||
white = MIN (MIN (out[0], out[1]), out[2]);
|
||||
black = 1 - MAX (MAX (out[0], out[1]), out[2]);
|
||||
|
||||
out[1] = white * 100;
|
||||
out[2] = black * 100;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_derived_profile_convert_to_base_profile (GdkDerivedProfile *profile,
|
||||
const float *in,
|
||||
float *out)
|
||||
{
|
||||
switch (gdk_derived_profile_get_color_space (profile))
|
||||
{
|
||||
case GDK_COLOR_SPACE_HSL:
|
||||
hsl_to_rgb (in, out);
|
||||
break;
|
||||
case GDK_COLOR_SPACE_HWB:
|
||||
hwb_to_rgb (in, out);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gdk_derived_profile_convert_from_base_profile (GdkDerivedProfile *profile,
|
||||
const float *in,
|
||||
float *out)
|
||||
{
|
||||
switch (gdk_derived_profile_get_color_space (profile))
|
||||
{
|
||||
case GDK_COLOR_SPACE_HSL:
|
||||
rgb_to_hsl (in, out);
|
||||
break;
|
||||
case GDK_COLOR_SPACE_HWB:
|
||||
rgb_to_hwb (in, out);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
71
gdk/gdkderivedprofile.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* gdkderivedprofile.h
|
||||
*
|
||||
* Copyright 2021 (c) 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_DERIVED_PROFILE_H__
|
||||
#define __GDK_DERIVED_PROFILE_H__
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdkversionmacros.h>
|
||||
#include <gdk/gdkcolorprofile.h>
|
||||
#include <gdk/gdkiccprofile.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_DERIVED_PROFILE (gdk_derived_profile_get_type ())
|
||||
|
||||
#define GDK_DERIVED_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_DERIVED_PROFILE, GdkDerivedProfile))
|
||||
#define GDK_IS_DERIVED_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_DERIVED_PROFILE))
|
||||
#define GDK_DERIVED_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DERIVED_PROFILE, GdkDerivedProfileClass))
|
||||
#define GDK_IS_DERIVED_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DERIVED_PROFILE))
|
||||
#define GDK_DERIVED_PROFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DERIVED_PROFILE, GdkDerivedProfileClass))
|
||||
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDerivedProfile, g_object_unref)
|
||||
|
||||
typedef struct _GdkDerivedProfileClass GdkDerivedProfileClass;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GType gdk_derived_profile_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkColorProfile * gdk_derived_profile_get_base_profile (GdkDerivedProfile *profile);
|
||||
|
||||
typedef enum {
|
||||
GDK_COLOR_SPACE_HSL,
|
||||
GDK_COLOR_SPACE_HWB,
|
||||
} GdkColorSpace;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkColorSpace gdk_derived_profile_get_color_space (GdkDerivedProfile *profile);
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
void gdk_derived_profile_convert_to_base_profile (GdkDerivedProfile *profile,
|
||||
const float *in,
|
||||
float *out);
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
void gdk_derived_profile_convert_from_base_profile (GdkDerivedProfile *profile,
|
||||
const float *in,
|
||||
float *out);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_DERIVED_PROFILE_H__ */
|
||||
@@ -76,9 +76,11 @@
|
||||
|
||||
#include "gdkglcontextprivate.h"
|
||||
|
||||
#include "gdkcolorprofile.h"
|
||||
#include "gdkdebug.h"
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdkprofilerprivate.h"
|
||||
|
||||
@@ -227,125 +229,6 @@ gdk_gl_context_get_property (GObject *gobject,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdk_gl_context_upload_texture (GdkGLContext *context,
|
||||
const guchar *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride,
|
||||
GdkMemoryFormat data_format,
|
||||
guint texture_target)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
guchar *copy = NULL;
|
||||
GLint gl_internalformat;
|
||||
GLint gl_format;
|
||||
GLint gl_type;
|
||||
gsize bpp;
|
||||
|
||||
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
||||
|
||||
if (!priv->use_es && data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
|
||||
{
|
||||
gl_internalformat = GL_RGBA8;
|
||||
gl_format = GL_BGRA;
|
||||
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
}
|
||||
else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
|
||||
{
|
||||
gl_internalformat = GL_RGBA8;
|
||||
gl_format = GL_RGB;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
else if (priv->use_es && data_format == GDK_MEMORY_B8G8R8)
|
||||
{
|
||||
gl_internalformat = GL_RGBA8;
|
||||
gl_format = GL_BGR;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
else if (data_format == GDK_MEMORY_R16G16B16)
|
||||
{
|
||||
gl_internalformat = GL_RGBA16;
|
||||
gl_format = GL_RGB;
|
||||
gl_type = GL_UNSIGNED_SHORT;
|
||||
}
|
||||
else if (data_format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED)
|
||||
{
|
||||
gl_internalformat = GL_RGBA16;
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_SHORT;
|
||||
}
|
||||
else if (data_format == GDK_MEMORY_R16G16B16_FLOAT)
|
||||
{
|
||||
gl_internalformat = GL_RGB16F;
|
||||
gl_format = GL_RGB;
|
||||
gl_type = GL_HALF_FLOAT;
|
||||
}
|
||||
else if (data_format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED)
|
||||
{
|
||||
gl_internalformat = GL_RGBA16F;
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_HALF_FLOAT;
|
||||
}
|
||||
else if (data_format == GDK_MEMORY_R32G32B32_FLOAT)
|
||||
{
|
||||
gl_internalformat = GL_RGB32F;
|
||||
gl_format = GL_RGB;
|
||||
gl_type = GL_FLOAT;
|
||||
}
|
||||
else if (data_format == GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED)
|
||||
{
|
||||
gl_internalformat = GL_RGBA32F;
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_FLOAT;
|
||||
}
|
||||
else /* Fall-back, convert to GLES format */
|
||||
{
|
||||
copy = g_malloc (width * height * 4);
|
||||
gdk_memory_convert (copy, width * 4,
|
||||
GDK_MEMORY_CONVERT_GLES_RGBA,
|
||||
data, stride, data_format,
|
||||
width, height);
|
||||
data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
stride = width * 4;
|
||||
data = copy;
|
||||
gl_internalformat = GL_RGBA8;
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
bpp = gdk_memory_format_bytes_per_pixel (data_format);
|
||||
|
||||
/* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
|
||||
* the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
|
||||
*/
|
||||
if (stride == width * bpp)
|
||||
{
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
|
||||
}
|
||||
else if ((!priv->use_es ||
|
||||
(priv->use_es && (priv->gl_version >= 30 || priv->has_unpack_subimage))))
|
||||
{
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
|
||||
|
||||
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
|
||||
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL);
|
||||
for (i = 0; i < height; i++)
|
||||
glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
|
||||
}
|
||||
|
||||
g_free (copy);
|
||||
}
|
||||
|
||||
#define N_EGL_ATTRS 16
|
||||
|
||||
static gboolean
|
||||
@@ -1558,6 +1441,19 @@ gdk_gl_context_get_version (GdkGLContext *context,
|
||||
*minor = priv->gl_version % 10;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_gl_context_has_version (GdkGLContext *context,
|
||||
int major,
|
||||
int minor)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
|
||||
g_return_val_if_fail (minor < 10, FALSE);
|
||||
|
||||
return priv->gl_version >= major * 10 + minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_clear_current:
|
||||
*
|
||||
|
||||
@@ -105,13 +105,6 @@ GdkGLContext * gdk_gl_context_new_for_surface (GdkSurface
|
||||
void gdk_gl_context_set_is_legacy (GdkGLContext *context,
|
||||
gboolean is_legacy);
|
||||
|
||||
void gdk_gl_context_upload_texture (GdkGLContext *context,
|
||||
const guchar *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride,
|
||||
GdkMemoryFormat data_format,
|
||||
guint texture_target);
|
||||
gboolean gdk_gl_context_has_unpack_subimage (GdkGLContext *context);
|
||||
void gdk_gl_context_push_debug_group (GdkGLContext *context,
|
||||
const char *message);
|
||||
@@ -129,6 +122,9 @@ void gdk_gl_context_label_object_printf (GdkGLContext
|
||||
const char *format,
|
||||
...) G_GNUC_PRINTF (4, 5);
|
||||
|
||||
gboolean gdk_gl_context_has_version (GdkGLContext *context,
|
||||
int major,
|
||||
int minor);
|
||||
gboolean gdk_gl_context_has_debug (GdkGLContext *self) G_GNUC_PURE;
|
||||
|
||||
gboolean gdk_gl_context_use_es_bgra (GdkGLContext *context);
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
#include "gdkgltextureprivate.h"
|
||||
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdktextureprivate.h"
|
||||
#include "gdkcolorprofile.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
@@ -36,6 +38,7 @@ struct _GdkGLTexture {
|
||||
GdkTexture parent_instance;
|
||||
|
||||
GdkGLContext *context;
|
||||
GdkGLTextureFlags flags;
|
||||
guint id;
|
||||
|
||||
GdkTexture *saved;
|
||||
@@ -139,17 +142,20 @@ gdk_gl_texture_get_tex_image (GdkGLTexture *self,
|
||||
data);
|
||||
}
|
||||
}
|
||||
static void
|
||||
gdk_gl_texture_do_download_texture (gpointer texture_,
|
||||
gpointer result_)
|
||||
{
|
||||
GdkTexture *texture = texture_;
|
||||
GdkTexture **result = result_;
|
||||
|
||||
typedef struct {
|
||||
GdkMemoryFormat format;
|
||||
GLint gl_format;
|
||||
GLint gl_type;
|
||||
} GdkGLTextureFormat;
|
||||
|
||||
static void
|
||||
gdk_gl_texture_get_format (gpointer texture_,
|
||||
gpointer result_)
|
||||
{
|
||||
GdkGLTextureFormat *result = result_;
|
||||
GLint internal_format, gl_format, gl_type;
|
||||
guchar *data;
|
||||
gsize stride;
|
||||
GBytes *bytes;
|
||||
GdkMemoryFormat format;
|
||||
|
||||
glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
|
||||
|
||||
@@ -213,18 +219,36 @@ gdk_gl_texture_do_download_texture (gpointer texture_,
|
||||
break;
|
||||
}
|
||||
|
||||
stride = gdk_memory_format_bytes_per_pixel (format) * texture->width;
|
||||
result->format = format;
|
||||
result->gl_format = gl_format;
|
||||
result->gl_type = gl_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_texture_do_download_texture (gpointer texture_,
|
||||
gpointer result_)
|
||||
{
|
||||
GdkTexture *texture = texture_;
|
||||
GdkTexture **result = result_;
|
||||
GdkGLTextureFormat format;
|
||||
gsize stride;
|
||||
guchar *data;
|
||||
GBytes *bytes;
|
||||
|
||||
gdk_gl_texture_get_format (texture, &format);
|
||||
|
||||
stride = gdk_memory_format_bytes_per_pixel (format.format) * texture->width;
|
||||
data = g_malloc (stride * texture->height);
|
||||
|
||||
gdk_gl_texture_get_tex_image (texture_,
|
||||
gl_format,
|
||||
gl_type,
|
||||
format.gl_format,
|
||||
format.gl_type,
|
||||
data);
|
||||
|
||||
bytes = g_bytes_new_take (data, stride * texture->height);
|
||||
*result = gdk_memory_texture_new (texture->width,
|
||||
texture->height,
|
||||
format,
|
||||
format.format,
|
||||
bytes,
|
||||
stride);
|
||||
|
||||
@@ -319,6 +343,17 @@ gdk_gl_texture_download_float (GdkTexture *texture,
|
||||
gdk_gl_texture_run (self, gdk_gl_texture_do_download_float, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_gl_texture_is_hdr (GdkTexture *texture)
|
||||
{
|
||||
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
|
||||
GdkGLTextureFormat result;
|
||||
|
||||
gdk_gl_texture_run (self, gdk_gl_texture_get_format, &result);
|
||||
|
||||
return gdk_memory_format_is_hdr (result.format);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_texture_class_init (GdkGLTextureClass *klass)
|
||||
{
|
||||
@@ -328,6 +363,7 @@ gdk_gl_texture_class_init (GdkGLTextureClass *klass)
|
||||
texture_class->download_texture = gdk_gl_texture_download_texture;
|
||||
texture_class->download = gdk_gl_texture_download;
|
||||
texture_class->download_float = gdk_gl_texture_download_float;
|
||||
texture_class->is_hdr = gdk_gl_texture_is_hdr;
|
||||
gobject_class->dispose = gdk_gl_texture_dispose;
|
||||
}
|
||||
|
||||
@@ -348,6 +384,12 @@ gdk_gl_texture_get_id (GdkGLTexture *self)
|
||||
return self->id;
|
||||
}
|
||||
|
||||
GdkGLTextureFlags
|
||||
gdk_gl_texture_get_flags (GdkGLTexture *self)
|
||||
{
|
||||
return self->flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_texture_release:
|
||||
* @self: a `GdkTexture` wrapping a GL texture
|
||||
@@ -402,6 +444,45 @@ gdk_gl_texture_new (GdkGLContext *context,
|
||||
int height,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data)
|
||||
{
|
||||
return gdk_gl_texture_new_with_color_profile (context, id,
|
||||
width, height,
|
||||
GDK_GL_TEXTURE_PREMULTIPLIED,
|
||||
gdk_color_profile_get_srgb (),
|
||||
destroy, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_texture_new_with_color_profile:
|
||||
* @context: a `GdkGLContext`
|
||||
* @id: the ID of a texture that was created with @context
|
||||
* @width: the nominal width of the texture
|
||||
* @height: the nominal height of the texture
|
||||
* @flags: flags that describe the content of the texture
|
||||
* @color_profile: the `GdkColorProfile` for the content of the texture
|
||||
* @destroy: a destroy notify that will be called when the GL resources
|
||||
* are released
|
||||
* @data: data that gets passed to @destroy
|
||||
*
|
||||
* Creates a new texture for an existing GL texture with a given color profile.
|
||||
*
|
||||
* Note that the GL texture must not be modified until @destroy is called,
|
||||
* which will happen when the GdkTexture object is finalized, or due to
|
||||
* an explicit call of [method@Gdk.GLTexture.release].
|
||||
*
|
||||
* Return value: (transfer full): A newly-created `GdkTexture`
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
GdkTexture *
|
||||
gdk_gl_texture_new_with_color_profile (GdkGLContext *context,
|
||||
guint id,
|
||||
int width,
|
||||
int height,
|
||||
GdkGLTextureFlags flags,
|
||||
GdkColorProfile *color_profile,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data)
|
||||
{
|
||||
GdkGLTexture *self;
|
||||
|
||||
@@ -413,10 +494,12 @@ gdk_gl_texture_new (GdkGLContext *context,
|
||||
self = g_object_new (GDK_TYPE_GL_TEXTURE,
|
||||
"width", width,
|
||||
"height", height,
|
||||
"color-profile", color_profile,
|
||||
NULL);
|
||||
|
||||
self->context = g_object_ref (context);
|
||||
self->id = id;
|
||||
self->flags = flags;
|
||||
self->destroy = destroy;
|
||||
self->data = data;
|
||||
|
||||
|
||||
@@ -49,6 +49,28 @@ GdkTexture * gdk_gl_texture_new (GdkGLContext
|
||||
GDestroyNotify destroy,
|
||||
gpointer data);
|
||||
|
||||
/**
|
||||
* GdkGLTextureFlags:
|
||||
* @GDK_GL_TEXTURE_FLAGS_PREMULTIPLIED: The alpha in the data is not premultiplied
|
||||
* @GDK_GL_TEXTURE_FLAGS_FLIPPED: The data has the origin at the bottom
|
||||
*
|
||||
* Flags that describe the content of a GL texture.
|
||||
*/
|
||||
typedef enum {
|
||||
GDK_GL_TEXTURE_PREMULTIPLIED = 1 << 0,
|
||||
GDK_GL_TEXTURE_FLIPPED = 1 << 1,
|
||||
} GdkGLTextureFlags;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkTexture * gdk_gl_texture_new_with_color_profile (GdkGLContext *context,
|
||||
guint id,
|
||||
int width,
|
||||
int height,
|
||||
GdkGLTextureFlags flags,
|
||||
GdkColorProfile *color_profile,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_gl_texture_release (GdkGLTexture *self);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ G_BEGIN_DECLS
|
||||
|
||||
GdkGLContext * gdk_gl_texture_get_context (GdkGLTexture *self);
|
||||
guint gdk_gl_texture_get_id (GdkGLTexture *self);
|
||||
GdkGLTextureFlags gdk_gl_texture_get_flags (GdkGLTexture *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
451
gdk/gdkiccprofile.c
Normal file
@@ -0,0 +1,451 @@
|
||||
/* gdkiccprofile.c
|
||||
*
|
||||
* Copyright 2021 (c) Benjamin Otte
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GdkICCProfile:
|
||||
*
|
||||
* `GdkICCProfile` is used to describe ICC color profiles.
|
||||
*
|
||||
* It is used to associate color profiles defined by the [International
|
||||
* Color Consortium (ICC)](https://color.org/) with texture and color data.
|
||||
*
|
||||
* Each `GdkColorProfile` encapsulates an
|
||||
* [ICC profile](https://en.wikipedia.org/wiki/ICC_profile). That profile
|
||||
* can be queried via the using [property@Gdk.ColorProfile:icc-profile]
|
||||
* property.
|
||||
*
|
||||
* `GdkICCProfile` objects are immutable and therefore threadsafe.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkiccprofileprivate.h"
|
||||
#include "gdkcolorprofileprivate.h"
|
||||
|
||||
#include "gdkintl.h"
|
||||
|
||||
struct _GdkICCProfile
|
||||
{
|
||||
GdkColorProfile parent_instance;
|
||||
|
||||
GBytes *icc_profile;
|
||||
cmsHPROFILE lcms_profile;
|
||||
};
|
||||
|
||||
struct _GdkICCProfileClass
|
||||
{
|
||||
GdkColorProfileClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ICC_PROFILE,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
|
||||
static gboolean
|
||||
gdk_icc_profile_real_init (GInitable *initable,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GdkICCProfile *self = GDK_ICC_PROFILE (initable);
|
||||
|
||||
if (self->lcms_profile == NULL)
|
||||
{
|
||||
const guchar *data;
|
||||
gsize size;
|
||||
|
||||
if (self->icc_profile == NULL)
|
||||
self->icc_profile = g_bytes_new (NULL, 0);
|
||||
|
||||
data = g_bytes_get_data (self->icc_profile, &size);
|
||||
|
||||
self->lcms_profile = cmsOpenProfileFromMem (data, size);
|
||||
if (self->lcms_profile == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to load ICC profile"));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_icc_profile_initable_init (GInitableIface *iface)
|
||||
{
|
||||
iface->init = gdk_icc_profile_real_init;
|
||||
}
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GdkICCProfile, gdk_icc_profile, GDK_TYPE_COLOR_PROFILE,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gdk_icc_profile_initable_init))
|
||||
|
||||
static void
|
||||
gdk_icc_profile_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdkICCProfile *self = GDK_ICC_PROFILE (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ICC_PROFILE:
|
||||
self->icc_profile = g_value_dup_boxed (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_icc_profile_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdkICCProfile *self = GDK_ICC_PROFILE (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ICC_PROFILE:
|
||||
g_value_set_boxed (value, self->icc_profile);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_icc_profile_dispose (GObject *object)
|
||||
{
|
||||
GdkICCProfile *self = GDK_ICC_PROFILE (object);
|
||||
|
||||
g_clear_pointer (&self->icc_profile, g_bytes_unref);
|
||||
g_clear_pointer (&self->lcms_profile, cmsCloseProfile);
|
||||
|
||||
G_OBJECT_CLASS (gdk_icc_profile_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_icc_profile_is_linear (GdkColorProfile *profile)
|
||||
{
|
||||
return profile == gdk_color_profile_get_srgb_linear ();
|
||||
}
|
||||
|
||||
static gsize
|
||||
gdk_icc_profile_get_n_components (GdkColorProfile *profile)
|
||||
{
|
||||
GdkICCProfile *self = GDK_ICC_PROFILE (profile);
|
||||
|
||||
return cmsChannelsOf (cmsGetColorSpace (self->lcms_profile));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_icc_profile_equal (gconstpointer profile1,
|
||||
gconstpointer profile2)
|
||||
{
|
||||
return g_bytes_equal (GDK_ICC_PROFILE (profile1)->icc_profile,
|
||||
GDK_ICC_PROFILE (profile2)->icc_profile);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_icc_profile_class_init (GdkICCProfileClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GdkColorProfileClass *profile_class = GDK_COLOR_PROFILE_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gdk_icc_profile_set_property;
|
||||
gobject_class->get_property = gdk_icc_profile_get_property;
|
||||
gobject_class->dispose = gdk_icc_profile_dispose;
|
||||
|
||||
profile_class->is_linear = gdk_icc_profile_is_linear;
|
||||
profile_class->get_n_components = gdk_icc_profile_get_n_components;
|
||||
profile_class->equal = gdk_icc_profile_equal;
|
||||
|
||||
/**
|
||||
* GdkICCProfile:icc-profile: (attributes org.gtk.Property.get=gdk_icc_profile_get_icc_profile)
|
||||
*
|
||||
* the ICC profile for this color profile
|
||||
*/
|
||||
properties[PROP_ICC_PROFILE] =
|
||||
g_param_spec_boxed ("icc-profile",
|
||||
P_("ICC profile"),
|
||||
P_("ICC profile for this color profile"),
|
||||
G_TYPE_BYTES,
|
||||
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_icc_profile_init (GdkICCProfile *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_profile_get_srgb:
|
||||
*
|
||||
* Returns the color profile representing the sRGB color space.
|
||||
*
|
||||
* If you don't know anything about color profiles but need one for
|
||||
* use with some function, this one is most likely the right one.
|
||||
*
|
||||
* Returns: (transfer none): the color profile for the sRGB
|
||||
* color space.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
GdkColorProfile *
|
||||
gdk_color_profile_get_srgb (void)
|
||||
{
|
||||
static GdkColorProfile *srgb_profile;
|
||||
|
||||
if (g_once_init_enter (&srgb_profile))
|
||||
{
|
||||
GdkColorProfile *new_profile;
|
||||
|
||||
new_profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_lcms_profile (cmsCreate_sRGBProfile (), NULL));
|
||||
g_assert (new_profile);
|
||||
|
||||
g_once_init_leave (&srgb_profile, new_profile);
|
||||
}
|
||||
|
||||
return srgb_profile;
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gdk_color_profile_get_srgb_linear:
|
||||
*
|
||||
* Returns the linear color profile corresponding to the sRGB
|
||||
* color space.
|
||||
*
|
||||
* It can display the same colors, but it does not have a gamma curve.
|
||||
*
|
||||
* Returns: (transfer none): the color profile for the linear sRGB
|
||||
* color space.
|
||||
*/
|
||||
GdkColorProfile *
|
||||
gdk_color_profile_get_srgb_linear (void)
|
||||
{
|
||||
static GdkColorProfile *srgb_linear_profile;
|
||||
|
||||
if (g_once_init_enter (&srgb_linear_profile))
|
||||
{
|
||||
cmsToneCurve *curve;
|
||||
cmsHPROFILE lcms_profile;
|
||||
GdkColorProfile *new_profile;
|
||||
|
||||
curve = cmsBuildGamma (NULL, 1.0);
|
||||
lcms_profile = cmsCreateRGBProfile (&(cmsCIExyY) {
|
||||
0.3127, 0.3290, 1.0
|
||||
},
|
||||
&(cmsCIExyYTRIPLE) {
|
||||
{ 0.6400, 0.3300, 1.0 },
|
||||
{ 0.3000, 0.6000, 1.0 },
|
||||
{ 0.1500, 0.0600, 1.0 }
|
||||
},
|
||||
(cmsToneCurve*[3]) { curve, curve, curve });
|
||||
cmsFreeToneCurve (curve);
|
||||
|
||||
new_profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_lcms_profile (lcms_profile, NULL));
|
||||
g_assert (new_profile);
|
||||
|
||||
g_once_init_leave (&srgb_linear_profile, new_profile);
|
||||
}
|
||||
|
||||
return srgb_linear_profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_icc_profile_new_from_icc_bytes:
|
||||
* @bytes: The ICC profiles given as a `GBytes`
|
||||
* @error: Return location for an error
|
||||
*
|
||||
* Creates a new color profile for the given ICC profile data.
|
||||
*
|
||||
* if the profile is not valid, %NULL is returned and an error
|
||||
* is raised.
|
||||
*
|
||||
* Returns: a new `GdkColorProfile` or %NULL on error
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
GdkICCProfile *
|
||||
gdk_icc_profile_new_from_icc_bytes (GBytes *bytes,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (bytes != NULL, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
return g_initable_new (GDK_TYPE_ICC_PROFILE,
|
||||
NULL,
|
||||
error,
|
||||
"icc-profile", bytes,
|
||||
NULL);
|
||||
}
|
||||
|
||||
GdkICCProfile *
|
||||
gdk_icc_profile_new_from_lcms_profile (cmsHPROFILE lcms_profile,
|
||||
GError **error)
|
||||
{
|
||||
GdkICCProfile *result;
|
||||
cmsUInt32Number size;
|
||||
guchar *data;
|
||||
|
||||
size = 0;
|
||||
if (!cmsSaveProfileToMem (lcms_profile, NULL, &size))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Could not prepare ICC profile"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = g_malloc (size);
|
||||
if (!cmsSaveProfileToMem (lcms_profile, data, &size))
|
||||
{
|
||||
g_free (data);
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to save ICC profile"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = g_object_new (GDK_TYPE_ICC_PROFILE, NULL);
|
||||
result->lcms_profile = lcms_profile;
|
||||
result->icc_profile = g_bytes_new_take (data, size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_icc_profile_get_icc_profile: (attributes org.gtk.Method.get_property=icc-profile)
|
||||
* @self: a `GdkICCProfile`
|
||||
*
|
||||
* Returns the serialized ICC profile of @self as %GBytes.
|
||||
*
|
||||
* Returns: (transfer none): the ICC profile
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
GBytes *
|
||||
gdk_icc_profile_get_icc_profile (GdkICCProfile *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_ICC_PROFILE (self), NULL);
|
||||
|
||||
return self->icc_profile;
|
||||
}
|
||||
|
||||
cmsHPROFILE *
|
||||
gdk_icc_profile_get_lcms_profile (GdkICCProfile *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_ICC_PROFILE (self), NULL);
|
||||
|
||||
return self->lcms_profile;
|
||||
}
|
||||
|
||||
|
||||
typedef struct _GdkICCTransformCache GdkICCTransformCache;
|
||||
|
||||
struct _GdkICCTransformCache
|
||||
{
|
||||
GdkICCProfile *source;
|
||||
guint source_type;
|
||||
GdkICCProfile *dest;
|
||||
guint dest_type;
|
||||
};
|
||||
|
||||
static void
|
||||
gdk_icc_transform_cache_free (gpointer data)
|
||||
{
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static guint
|
||||
gdk_icc_transform_cache_hash (gconstpointer data)
|
||||
{
|
||||
const GdkICCTransformCache *cache = data;
|
||||
|
||||
return g_direct_hash (cache->source) ^
|
||||
(g_direct_hash (cache->dest) >> 2) ^
|
||||
((cache->source_type << 16) | (cache->source_type >> 16)) ^
|
||||
cache->dest_type;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_icc_transform_cache_equal (gconstpointer data1,
|
||||
gconstpointer data2)
|
||||
{
|
||||
const GdkICCTransformCache *cache1 = data1;
|
||||
const GdkICCTransformCache *cache2 = data2;
|
||||
|
||||
return cache1->source == cache2->source &&
|
||||
cache1->source_type == cache2->source_type &&
|
||||
cache1->dest == cache2->dest &&
|
||||
cache1->dest_type == cache2->dest_type;
|
||||
}
|
||||
|
||||
cmsHTRANSFORM *
|
||||
gdk_icc_profile_lookup_transform (GdkICCProfile *source,
|
||||
guint source_type,
|
||||
GdkICCProfile *dest,
|
||||
guint dest_type)
|
||||
{
|
||||
GdkICCTransformCache *entry;
|
||||
static GHashTable *cache = NULL;
|
||||
cmsHTRANSFORM *transform;
|
||||
|
||||
if (cache == NULL)
|
||||
cache = g_hash_table_new_full (gdk_icc_transform_cache_hash,
|
||||
gdk_icc_transform_cache_equal,
|
||||
gdk_icc_transform_cache_free,
|
||||
cmsDeleteTransform);
|
||||
|
||||
transform = g_hash_table_lookup (cache,
|
||||
&(GdkICCTransformCache) {
|
||||
source, source_type,
|
||||
dest, dest_type
|
||||
});
|
||||
if (G_UNLIKELY (transform == NULL))
|
||||
{
|
||||
transform = cmsCreateTransform (gdk_icc_profile_get_lcms_profile (source),
|
||||
source_type,
|
||||
gdk_icc_profile_get_lcms_profile (dest),
|
||||
dest_type,
|
||||
INTENT_PERCEPTUAL,
|
||||
cmsFLAGS_COPY_ALPHA);
|
||||
entry = g_new (GdkICCTransformCache, 1);
|
||||
*entry = (GdkICCTransformCache) {
|
||||
source, source_type,
|
||||
dest, dest_type
|
||||
};
|
||||
g_hash_table_insert (cache, entry, transform);
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
56
gdk/gdkiccprofile.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* gdkiccprofile.h
|
||||
*
|
||||
* Copyright 2021 (c) Benjamin Otte
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_ICC_PROFILE_H__
|
||||
#define __GDK_ICC_PROFILE_H__
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdkversionmacros.h>
|
||||
#include <gdk/gdkcolorprofile.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_ICC_PROFILE (gdk_icc_profile_get_type ())
|
||||
|
||||
#define GDK_ICC_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_ICC_PROFILE, GdkICCProfile))
|
||||
#define GDK_IS_ICC_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_ICC_PROFILE))
|
||||
#define GDK_ICC_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_ICC_PROFILE, GdkICCProfileClass))
|
||||
#define GDK_IS_ICC_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_ICC_PROFILE))
|
||||
#define GDK_ICC_PROFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_ICC_PROFILE, GdkICCProfileClass))
|
||||
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkICCProfile, g_object_unref)
|
||||
|
||||
typedef struct _GdkICCProfileClass GdkICCProfileClass;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GType gdk_icc_profile_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkICCProfile * gdk_icc_profile_new_from_icc_bytes (GBytes *bytes,
|
||||
GError **error);
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GBytes * gdk_icc_profile_get_icc_profile (GdkICCProfile *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_ICC_PROFILE_H__ */
|
||||
24
gdk/gdkiccprofileprivate.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef __GDK_ICC_PROFILE_PRIVATE_H__
|
||||
#define __GDK_ICC_PROFILE_PRIVATE_H__
|
||||
|
||||
#include "gdkiccprofile.h"
|
||||
#include "gdkmemorytexture.h"
|
||||
|
||||
#include <lcms2.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
GdkICCProfile * gdk_icc_profile_new_from_lcms_profile (cmsHPROFILE lcms_profile,
|
||||
GError **error);
|
||||
|
||||
cmsHPROFILE * gdk_icc_profile_get_lcms_profile (GdkICCProfile *self);
|
||||
|
||||
cmsHTRANSFORM * gdk_icc_profile_lookup_transform (GdkICCProfile *source,
|
||||
guint source_type,
|
||||
GdkICCProfile *dest,
|
||||
guint dest_type);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_COLOR_PROFILE_PRIVATE_H__ */
|
||||
900
gdk/gdkmemoryformat.c
Normal file
@@ -0,0 +1,900 @@
|
||||
/*
|
||||
* Copyright © 2021 Benjamin Otte
|
||||
*
|
||||
* 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.1 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/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
|
||||
#include "gdkiccprofileprivate.h"
|
||||
#include "gdkprofilerprivate.h"
|
||||
#include "gsk/ngl/fp16private.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription;
|
||||
|
||||
#define TYPED_FUNCS(name, T, R, G, B, A, bpp, scale) \
|
||||
static void \
|
||||
name ## _to_float (float *dest, \
|
||||
const guchar *src_data, \
|
||||
gsize n) \
|
||||
{ \
|
||||
for (gsize i = 0; i < n; i++) \
|
||||
{ \
|
||||
T *src = (T *) (src_data + i * bpp); \
|
||||
dest[0] = (float) src[R] / scale; \
|
||||
dest[1] = (float) src[G] / scale; \
|
||||
dest[2] = (float) src[B] / scale; \
|
||||
if (A >= 0) dest[3] = (float) src[A] / scale; else dest[3] = 1.0; \
|
||||
dest += 4; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static void \
|
||||
name ## _from_float (guchar *dest_data, \
|
||||
const float *src, \
|
||||
gsize n) \
|
||||
{ \
|
||||
for (gsize i = 0; i < n; i++) \
|
||||
{ \
|
||||
T *dest = (T *) (dest_data + i * bpp); \
|
||||
dest[R] = CLAMP (src[0] * (scale + 1), 0, scale); \
|
||||
dest[G] = CLAMP (src[1] * (scale + 1), 0, scale); \
|
||||
dest[B] = CLAMP (src[2] * (scale + 1), 0, scale); \
|
||||
if (A >= 0) dest[A] = CLAMP (src[3] * (scale + 1), 0, scale); \
|
||||
src += 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
TYPED_FUNCS (b8g8r8a8_premultiplied, guchar, 2, 1, 0, 3, 4, 255)
|
||||
TYPED_FUNCS (a8r8g8b8_premultiplied, guchar, 1, 2, 3, 0, 4, 255)
|
||||
TYPED_FUNCS (r8g8b8a8_premultiplied, guchar, 0, 1, 2, 3, 4, 255)
|
||||
TYPED_FUNCS (b8g8r8a8, guchar, 2, 1, 0, 3, 4, 255)
|
||||
TYPED_FUNCS (a8r8g8b8, guchar, 1, 2, 3, 0, 4, 255)
|
||||
TYPED_FUNCS (r8g8b8a8, guchar, 0, 1, 2, 3, 4, 255)
|
||||
TYPED_FUNCS (a8b8g8r8, guchar, 3, 2, 1, 0, 4, 255)
|
||||
TYPED_FUNCS (r8g8b8, guchar, 0, 1, 2, -1, 3, 255)
|
||||
TYPED_FUNCS (b8g8r8, guchar, 2, 1, 0, -1, 3, 255)
|
||||
TYPED_FUNCS (r16g16b16, guint16, 0, 1, 2, -1, 6, 65535)
|
||||
TYPED_FUNCS (r16g16b16a16, guint16, 0, 1, 2, 3, 8, 65535)
|
||||
|
||||
#define PREMULTIPLY_FUNCS(type, A, scale) \
|
||||
static void \
|
||||
type ## _premultiply_ ## A (guchar *dest_data, \
|
||||
const guchar *src_data, \
|
||||
gsize n) \
|
||||
{ \
|
||||
type *dest = (type *) dest_data; \
|
||||
const type *src = (const type *) src_data; \
|
||||
for (gsize i = 0; i < n; i++) \
|
||||
{ \
|
||||
unsigned a = src[A]; \
|
||||
if (A != 0) dest[0] = src[0] * a / scale; \
|
||||
if (A != 1) dest[1] = src[1] * a / scale; \
|
||||
if (A != 2) dest[2] = src[2] * a / scale; \
|
||||
if (A != 3) dest[3] = src[3] * a / scale; \
|
||||
dest[A] = a; \
|
||||
src += 4; \
|
||||
dest += 4; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static void \
|
||||
type ## _unpremultiply_ ## A (guchar *dest_data, \
|
||||
const guchar *src_data, \
|
||||
gsize n) \
|
||||
{ \
|
||||
type *dest = (type *) dest_data; \
|
||||
const type *src = (const type *) src_data; \
|
||||
for (gsize i = 0; i < n; i++) \
|
||||
{ \
|
||||
unsigned a = src[A]; \
|
||||
if (a == 0) \
|
||||
{ \
|
||||
dest[0] = dest[1] = dest[2] = dest[3] = 0; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (A != 0) dest[0] = (src[0] * scale + a / 2) / a; \
|
||||
if (A != 1) dest[1] = (src[1] * scale + a / 2) / a; \
|
||||
if (A != 2) dest[2] = (src[2] * scale + a / 2) / a; \
|
||||
if (A != 3) dest[3] = (src[3] * scale + a / 2) / a; \
|
||||
dest[A] = a; \
|
||||
} \
|
||||
src += 4; \
|
||||
dest += 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
PREMULTIPLY_FUNCS (guint8, 0, G_MAXUINT8)
|
||||
PREMULTIPLY_FUNCS (guint8, 3, G_MAXUINT8)
|
||||
PREMULTIPLY_FUNCS (guint16, 3, G_MAXUINT16)
|
||||
|
||||
static void
|
||||
half_float_premultiply (guchar *dest_data,
|
||||
const guchar *src_data,
|
||||
gsize n)
|
||||
{
|
||||
guint16 *dest = (guint16 *) dest_data;
|
||||
const float *src = (const float *) src_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
float tmp[4];
|
||||
tmp[0] = src[0] * src[3];
|
||||
tmp[1] = src[1] * src[3];
|
||||
tmp[2] = src[2] * src[3];
|
||||
tmp[3] = src[3];
|
||||
float_to_half4 (tmp, dest);
|
||||
dest += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
half_float_unpremultiply (guchar *dest_data,
|
||||
const guchar *src_data,
|
||||
gsize n)
|
||||
{
|
||||
float *dest = (float *) dest_data;
|
||||
const guint16 *src = (const guint16 *) src_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
half_to_float4 (src, dest);
|
||||
if (dest[3] <= 1/255.0)
|
||||
{
|
||||
memset (dest, 0, sizeof (guint) * 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[0] = dest[0] / dest[3];
|
||||
dest[1] = dest[1] / dest[3];
|
||||
dest[2] = dest[2] / dest[3];
|
||||
}
|
||||
dest += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
float_premultiply (guchar *dest_data,
|
||||
const guchar *src_data,
|
||||
gsize n)
|
||||
{
|
||||
float *dest = (float *) dest_data;
|
||||
const float *src = (const float *) src_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
float a = src[3];
|
||||
dest[0] = src[0] * a;
|
||||
dest[1] = src[1] * a;
|
||||
dest[2] = src[2] * a;
|
||||
dest[3] = a;
|
||||
dest += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
float_unpremultiply (guchar *dest_data,
|
||||
const guchar *src_data,
|
||||
gsize n)
|
||||
{
|
||||
float *dest = (float *) dest_data;
|
||||
const float *src = (const float *) src_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
float a = src[3];
|
||||
if (a <= 1/255.0)
|
||||
{
|
||||
memset (dest, 0, sizeof (float) * 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[0] = src[0] / a;
|
||||
dest[1] = src[1] / a;
|
||||
dest[2] = src[2] / a;
|
||||
dest[3] = a;
|
||||
}
|
||||
dest += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
#define COMPRESS_FUNCS(type, scale) \
|
||||
static void \
|
||||
type ## _expand (guchar *dest_data, \
|
||||
const guchar *src_data, \
|
||||
gsize n) \
|
||||
{ \
|
||||
type *dest = (type *) dest_data; \
|
||||
const type *src = (const type *) src_data; \
|
||||
for (gsize i = 0; i < n; i++) \
|
||||
{ \
|
||||
dest[0] = src[0]; \
|
||||
dest[1] = src[1]; \
|
||||
dest[2] = src[2]; \
|
||||
dest[3] = scale; \
|
||||
dest += 4; \
|
||||
src += 3; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static void \
|
||||
type ## _compress (guchar *dest_data, \
|
||||
const guchar *src_data, \
|
||||
gsize n) \
|
||||
{ \
|
||||
type *dest = (type *) dest_data; \
|
||||
const type *src = (const type *) src_data; \
|
||||
for (gsize i = 0; i < n; i++) \
|
||||
{ \
|
||||
dest[0] = src[0] * src[3] / scale; \
|
||||
dest[1] = src[1] * src[3] / scale; \
|
||||
dest[2] = src[2] * src[3] / scale; \
|
||||
dest += 3; \
|
||||
src += 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
COMPRESS_FUNCS (guint8, G_MAXUINT8)
|
||||
COMPRESS_FUNCS (guint16, G_MAXUINT16)
|
||||
COMPRESS_FUNCS (float, 1.0f)
|
||||
|
||||
static void
|
||||
half_float_expand (guchar *dest_data,
|
||||
const guchar *src_data,
|
||||
gsize n)
|
||||
{
|
||||
float *dest = (float *) dest_data;
|
||||
const guint16 *src = (const guint16 *) src_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
half_to_float (src, dest, 3);
|
||||
dest[3] = 1.0;
|
||||
dest += 4;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
half_float_compress (guchar *dest_data,
|
||||
const guchar *src_data,
|
||||
gsize n)
|
||||
{
|
||||
guint16 *dest = (guint16 *) dest_data;
|
||||
const float *src = (const float *) src_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
float tmp[3];
|
||||
tmp[0] = src[0] * src[3];
|
||||
tmp[1] = src[1] * src[3];
|
||||
tmp[2] = src[2] * src[3];
|
||||
float_to_half (tmp, dest, 3);
|
||||
dest += 3;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
r16g16b16_float_to_float (float *dest,
|
||||
const guchar *src_data,
|
||||
gsize n)
|
||||
{
|
||||
guint16 *src = (guint16 *) src_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
half_to_float (src, dest, 3);
|
||||
dest[3] = 1.0;
|
||||
dest += 4;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
r16g16b16_float_from_float (guchar *dest_data,
|
||||
const float *src,
|
||||
gsize n)
|
||||
{
|
||||
guint16 *dest = (guint16 *) dest_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
float_to_half (src, dest, 3);
|
||||
dest += 3;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
r16g16b16a16_float_to_float (float *dest,
|
||||
const guchar *src,
|
||||
gsize n)
|
||||
{
|
||||
half_to_float ((const guint16 *) src, dest, 4 * n);
|
||||
}
|
||||
|
||||
static void
|
||||
r16g16b16a16_float_from_float (guchar *dest,
|
||||
const float *src,
|
||||
gsize n)
|
||||
{
|
||||
float_to_half (src, (guint16 *) dest, 4 * n);
|
||||
}
|
||||
|
||||
static void
|
||||
r32g32b32_float_to_float (float *dest,
|
||||
const guchar *src_data,
|
||||
gsize n)
|
||||
{
|
||||
float *src = (float *) src_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
dest[0] = src[0];
|
||||
dest[1] = src[1];
|
||||
dest[2] = src[2];
|
||||
dest[3] = 1.0;
|
||||
dest += 4;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
r32g32b32_float_from_float (guchar *dest_data,
|
||||
const float *src,
|
||||
gsize n)
|
||||
{
|
||||
float *dest = (float *) dest_data;
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
dest[0] = src[0];
|
||||
dest[1] = src[1];
|
||||
dest[2] = src[2];
|
||||
dest += 3;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
r32g32b32a32_float_to_float (float *dest,
|
||||
const guchar *src,
|
||||
gsize n)
|
||||
{
|
||||
memcpy (dest, src, sizeof (float) * n * 4);
|
||||
}
|
||||
|
||||
static void
|
||||
r32g32b32a32_float_from_float (guchar *dest,
|
||||
const float *src,
|
||||
gsize n)
|
||||
{
|
||||
memcpy (dest, src, sizeof (float) * n * 4);
|
||||
}
|
||||
|
||||
struct _GdkMemoryFormatDescription
|
||||
{
|
||||
const char *name;
|
||||
GdkMemoryAlpha alpha;
|
||||
gsize bytes_per_pixel;
|
||||
gsize alignment;
|
||||
gboolean supports_gles;
|
||||
struct {
|
||||
guint internal_format;
|
||||
guint format;
|
||||
guint type;
|
||||
} gl;
|
||||
/* no premultiplication going on here */
|
||||
void (* to_float) (float *, const guchar*, gsize);
|
||||
void (* from_float) (guchar *, const float *, gsize);
|
||||
struct {
|
||||
guint type;
|
||||
gsize bpp;
|
||||
} lcms;
|
||||
void (* to_lcms) (guchar *, const guchar *, gsize);
|
||||
void (* from_lcms) (guchar *, const guchar *, gsize);
|
||||
};
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
# define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
# define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8_REV
|
||||
#else
|
||||
# error "Define the right GL flags here"
|
||||
#endif
|
||||
|
||||
static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
[GDK_MEMORY_B8G8R8A8_PREMULTIPLIED] = {
|
||||
"B8G8R8A8_PREMULTIPLIED",
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
FALSE,
|
||||
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE },
|
||||
b8g8r8a8_premultiplied_to_float,
|
||||
b8g8r8a8_premultiplied_from_float,
|
||||
{ TYPE_BGRA_8, 4 },
|
||||
guint8_unpremultiply_3,
|
||||
guint8_premultiply_3,
|
||||
},
|
||||
[GDK_MEMORY_A8R8G8B8_PREMULTIPLIED] = {
|
||||
"A8R8G8B8_PREMULTIPLIED",
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
FALSE,
|
||||
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED },
|
||||
a8r8g8b8_premultiplied_to_float,
|
||||
a8r8g8b8_premultiplied_from_float,
|
||||
{ TYPE_ARGB_8, 4 },
|
||||
guint8_unpremultiply_0,
|
||||
guint8_premultiply_0,
|
||||
},
|
||||
[GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] = {
|
||||
"R8G8B8A8_PREMULTIPLIED",
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
TRUE,
|
||||
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
|
||||
r8g8b8a8_premultiplied_to_float,
|
||||
r8g8b8a8_premultiplied_from_float,
|
||||
{ TYPE_RGBA_8, 4 },
|
||||
guint8_unpremultiply_3,
|
||||
guint8_premultiply_3,
|
||||
},
|
||||
[GDK_MEMORY_B8G8R8A8] = {
|
||||
"B8G8R8A8",
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
FALSE,
|
||||
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE },
|
||||
b8g8r8a8_to_float,
|
||||
b8g8r8a8_from_float,
|
||||
{ TYPE_BGRA_8, 4 },
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GDK_MEMORY_A8R8G8B8] = {
|
||||
"A8R8G8B8",
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
FALSE,
|
||||
{ GL_RGBA8, GL_RGBA, GDK_GL_UNSIGNED_BYTE_FLIPPED },
|
||||
a8r8g8b8_to_float,
|
||||
a8r8g8b8_from_float,
|
||||
{ TYPE_ARGB_8, 4 },
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GDK_MEMORY_R8G8B8A8] = {
|
||||
"R8G8B8A8",
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
TRUE,
|
||||
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
|
||||
r8g8b8a8_to_float,
|
||||
r8g8b8a8_from_float,
|
||||
{ TYPE_RGBA_8, 4 },
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GDK_MEMORY_A8B8G8R8] = {
|
||||
"A8B8G8R8",
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
4,
|
||||
G_ALIGNOF (guchar),
|
||||
FALSE,
|
||||
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED },
|
||||
a8b8g8r8_to_float,
|
||||
a8b8g8r8_from_float,
|
||||
{ TYPE_ABGR_8, 4 },
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GDK_MEMORY_R8G8B8] = {
|
||||
"R8G8B8",
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
3,
|
||||
G_ALIGNOF (guchar),
|
||||
TRUE,
|
||||
{ GL_RGBA8, GL_RGB, GL_UNSIGNED_BYTE },
|
||||
r8g8b8_to_float,
|
||||
r8g8b8_from_float,
|
||||
{ TYPE_RGBA_8, 4 },
|
||||
guint8_expand,
|
||||
guint8_compress,
|
||||
},
|
||||
[GDK_MEMORY_B8G8R8] = {
|
||||
"B8G8R8",
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
3,
|
||||
G_ALIGNOF (guchar),
|
||||
FALSE,
|
||||
{ GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE },
|
||||
b8g8r8_to_float,
|
||||
b8g8r8_from_float,
|
||||
{ TYPE_BGRA_8, 4 },
|
||||
guint8_expand,
|
||||
guint8_compress,
|
||||
},
|
||||
[GDK_MEMORY_R16G16B16] = {
|
||||
"R16G16B16",
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
6,
|
||||
G_ALIGNOF (guint16),
|
||||
TRUE,
|
||||
{ GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT },
|
||||
r16g16b16_to_float,
|
||||
r16g16b16_from_float,
|
||||
{ TYPE_RGBA_16, 8 },
|
||||
guint16_expand,
|
||||
guint16_compress,
|
||||
},
|
||||
[GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = {
|
||||
"R16G16B16A16_PREMULTIPLIED",
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
TRUE,
|
||||
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT },
|
||||
r16g16b16a16_to_float,
|
||||
r16g16b16a16_from_float,
|
||||
{ TYPE_RGBA_16, 8 },
|
||||
guint16_unpremultiply_3,
|
||||
guint16_premultiply_3,
|
||||
},
|
||||
[GDK_MEMORY_R16G16B16_FLOAT] = {
|
||||
"R16G16B16_FLOAT",
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
6,
|
||||
G_ALIGNOF (guint16),
|
||||
TRUE,
|
||||
{ GL_RGB16F, GL_RGB, GL_HALF_FLOAT },
|
||||
r16g16b16_float_to_float,
|
||||
r16g16b16_float_from_float,
|
||||
{ TYPE_RGBA_FLT, 16 },
|
||||
half_float_expand,
|
||||
half_float_compress,
|
||||
},
|
||||
[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = {
|
||||
"R16G16B16A16_FLOAT_PREMULTIPLIED",
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
TRUE,
|
||||
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT },
|
||||
r16g16b16a16_float_to_float,
|
||||
r16g16b16a16_float_from_float,
|
||||
{ TYPE_RGBA_FLT, 16 },
|
||||
half_float_unpremultiply,
|
||||
half_float_premultiply,
|
||||
},
|
||||
[GDK_MEMORY_R32G32B32_FLOAT] = {
|
||||
"R32G32B32_FLOAT",
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
12,
|
||||
G_ALIGNOF (float),
|
||||
TRUE,
|
||||
{ GL_RGB32F, GL_RGB, GL_FLOAT },
|
||||
r32g32b32_float_to_float,
|
||||
r32g32b32_float_from_float,
|
||||
{ TYPE_RGBA_FLT, 16 },
|
||||
float_expand,
|
||||
float_compress,
|
||||
},
|
||||
[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = {
|
||||
"R32G32B32A32_FLOAT_PREMULTIPLIED",
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
16,
|
||||
G_ALIGNOF (float),
|
||||
TRUE,
|
||||
{ GL_RGBA32F, GL_RGBA, GL_FLOAT },
|
||||
r32g32b32a32_float_to_float,
|
||||
r32g32b32a32_float_from_float,
|
||||
{ TYPE_RGBA_FLT, 16 },
|
||||
float_unpremultiply,
|
||||
float_premultiply,
|
||||
},
|
||||
[GDK_MEMORY_R16G16B16A16] = {
|
||||
"R16G16B16A16",
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
TRUE,
|
||||
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT },
|
||||
r16g16b16a16_to_float,
|
||||
r16g16b16a16_from_float,
|
||||
{ TYPE_RGBA_16, 8 },
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GDK_MEMORY_R16G16B16A16_FLOAT] = {
|
||||
"R16G16B16A16_FLOAT",
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
TRUE,
|
||||
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT },
|
||||
r16g16b16a16_float_to_float,
|
||||
r16g16b16a16_float_from_float,
|
||||
{ TYPE_RGBA_HALF_FLT, 8 },
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
[GDK_MEMORY_R32G32B32A32_FLOAT] = {
|
||||
"R32G32B32A32_FLOAT",
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
16,
|
||||
G_ALIGNOF (float),
|
||||
TRUE,
|
||||
{ GL_RGBA32F, GL_RGBA, GL_FLOAT },
|
||||
r32g32b32a32_float_to_float,
|
||||
r32g32b32a32_float_from_float,
|
||||
{ TYPE_RGBA_FLT, 16 },
|
||||
NULL,
|
||||
NULL,
|
||||
}
|
||||
};
|
||||
|
||||
gsize
|
||||
gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
|
||||
{
|
||||
return memory_formats[format].bytes_per_pixel;
|
||||
}
|
||||
|
||||
GdkMemoryAlpha
|
||||
gdk_memory_format_alpha (GdkMemoryFormat format)
|
||||
{
|
||||
return memory_formats[format].alpha;
|
||||
}
|
||||
|
||||
gsize
|
||||
gdk_memory_format_alignment (GdkMemoryFormat format)
|
||||
{
|
||||
return memory_formats[format].alignment;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_memory_format_gl_format (GdkMemoryFormat format,
|
||||
gboolean gles,
|
||||
guint *out_internal_format,
|
||||
guint *out_format,
|
||||
guint *out_type)
|
||||
{
|
||||
*out_internal_format = memory_formats[format].gl.internal_format;
|
||||
*out_format = memory_formats[format].gl.format;
|
||||
*out_type = memory_formats[format].gl.type;
|
||||
|
||||
if (memory_formats[format].alpha == GDK_MEMORY_ALPHA_STRAIGHT)
|
||||
return FALSE;
|
||||
|
||||
if (gles && !memory_formats[format].supports_gles)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_memory_format_is_hdr (GdkMemoryFormat format)
|
||||
{
|
||||
switch (memory_formats[format].gl.type)
|
||||
{
|
||||
case GL_FLOAT:
|
||||
case GL_HALF_FLOAT:
|
||||
case GL_UNSIGNED_SHORT:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
premultiply (float *rgba,
|
||||
gsize n)
|
||||
{
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
rgba[0] *= rgba[3];
|
||||
rgba[1] *= rgba[3];
|
||||
rgba[2] *= rgba[3];
|
||||
rgba += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unpremultiply (float *rgba,
|
||||
gsize n)
|
||||
{
|
||||
for (gsize i = 0; i < n; i++)
|
||||
{
|
||||
if (rgba[3] > 1/255.0)
|
||||
{
|
||||
rgba[0] /= rgba[3];
|
||||
rgba[1] /= rgba[3];
|
||||
rgba[2] /= rgba[3];
|
||||
}
|
||||
rgba += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_memory_convert_same_format (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
gsize width,
|
||||
gsize height,
|
||||
GdkMemoryFormat format)
|
||||
{
|
||||
const GdkMemoryFormatDescription *desc = &memory_formats[format];
|
||||
gsize y, stride;
|
||||
|
||||
stride = desc->bytes_per_pixel * width;
|
||||
if (stride == src_stride && stride == dest_stride)
|
||||
{
|
||||
memcpy (dest_data, src_data, stride * height);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
memcpy (dest_data + y * dest_stride,
|
||||
src_data + y * src_stride,
|
||||
stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_memory_convert_no_transform (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
GdkMemoryFormat dest_format,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
GdkMemoryFormat src_format,
|
||||
gsize width,
|
||||
gsize height)
|
||||
{
|
||||
if (dest_format == src_format)
|
||||
{
|
||||
gdk_memory_convert_same_format (dest_data, dest_stride,
|
||||
src_data, src_stride,
|
||||
width, height,
|
||||
dest_format);
|
||||
}
|
||||
else
|
||||
{
|
||||
const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format];
|
||||
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
|
||||
float *tmp;
|
||||
gsize y;
|
||||
|
||||
tmp = g_new (float, width * 4);
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
src_desc->to_float (tmp, src_data, width);
|
||||
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT)
|
||||
unpremultiply (tmp, width);
|
||||
else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
|
||||
premultiply (tmp, width);
|
||||
dest_desc->from_float (dest_data, tmp, width);
|
||||
src_data += src_stride;
|
||||
dest_data += dest_stride;
|
||||
}
|
||||
|
||||
g_free (tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_memory_convert_transform (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
GdkMemoryFormat dest_format,
|
||||
GdkColorProfile *dest_profile,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
GdkMemoryFormat src_format,
|
||||
GdkColorProfile *src_profile,
|
||||
gsize width,
|
||||
gsize height)
|
||||
{
|
||||
const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format];
|
||||
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
|
||||
cmsHTRANSFORM transform;
|
||||
guchar *src_tmp, *dest_tmp;
|
||||
gsize y;
|
||||
|
||||
g_assert (GDK_IS_ICC_PROFILE (src_profile));
|
||||
g_assert (GDK_IS_ICC_PROFILE (dest_profile));
|
||||
|
||||
transform = gdk_icc_profile_lookup_transform (GDK_ICC_PROFILE (src_profile),
|
||||
src_desc->lcms.type,
|
||||
GDK_ICC_PROFILE (dest_profile),
|
||||
dest_desc->lcms.type);
|
||||
|
||||
if (src_desc->to_lcms)
|
||||
src_tmp = g_malloc_n (src_desc->lcms.bpp, width);
|
||||
else
|
||||
src_tmp = NULL;
|
||||
if (dest_desc->from_lcms)
|
||||
dest_tmp = g_malloc_n (dest_desc->lcms.bpp, width);
|
||||
else
|
||||
dest_tmp = NULL;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
if (src_desc->to_lcms)
|
||||
src_desc->to_lcms (src_tmp, src_data, width);
|
||||
|
||||
cmsDoTransform (transform,
|
||||
src_tmp ? src_tmp : src_data,
|
||||
dest_tmp ? dest_tmp : dest_data,
|
||||
width);
|
||||
|
||||
if (dest_desc->from_lcms)
|
||||
dest_desc->from_lcms (dest_data, dest_tmp, width);
|
||||
|
||||
src_data += src_stride;
|
||||
dest_data += dest_stride;
|
||||
}
|
||||
|
||||
g_free (src_tmp);
|
||||
g_free (dest_tmp);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_memory_convert (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
GdkMemoryFormat dest_format,
|
||||
GdkColorProfile *dest_profile,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
GdkMemoryFormat src_format,
|
||||
GdkColorProfile *src_profile,
|
||||
gsize width,
|
||||
gsize height)
|
||||
{
|
||||
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
|
||||
gboolean need_transform;
|
||||
|
||||
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
|
||||
g_assert (src_format < GDK_MEMORY_N_FORMATS);
|
||||
|
||||
need_transform = !gdk_color_profile_equal (src_profile, dest_profile);
|
||||
if (!need_transform)
|
||||
{
|
||||
gdk_memory_convert_no_transform (dest_data, dest_stride, dest_format,
|
||||
src_data, src_stride, src_format,
|
||||
width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdk_memory_convert_transform (dest_data, dest_stride, dest_format, dest_profile,
|
||||
src_data, src_stride, src_format, src_profile,
|
||||
width, height);
|
||||
}
|
||||
|
||||
gdk_profiler_end_markf (start_time, "memory convert", "%zu pixels %s => %s%s",
|
||||
width * height,
|
||||
memory_formats[src_format].name,
|
||||
memory_formats[dest_format].name,
|
||||
need_transform ? "transformed" : "");
|
||||
}
|
||||
57
gdk/gdkmemoryformatprivate.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright © 2021 Benjamin Otte
|
||||
*
|
||||
* 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.1 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/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GDK_MEMORY_CONVERT_PRIVATE_H__
|
||||
#define __GDK_MEMORY_CONVERT_PRIVATE_H__
|
||||
|
||||
#include "gdkmemorytexture.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
GDK_MEMORY_ALPHA_OPAQUE
|
||||
} GdkMemoryAlpha;
|
||||
|
||||
gsize gdk_memory_format_alignment (GdkMemoryFormat format) G_GNUC_CONST;
|
||||
GdkMemoryAlpha gdk_memory_format_alpha (GdkMemoryFormat format) G_GNUC_CONST;
|
||||
gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) G_GNUC_CONST;
|
||||
gboolean gdk_memory_format_gl_format (GdkMemoryFormat format,
|
||||
gboolean gles,
|
||||
guint *out_internal_format,
|
||||
guint *out_format,
|
||||
guint *out_type);
|
||||
gboolean gdk_memory_format_is_hdr (GdkMemoryFormat format);
|
||||
|
||||
void gdk_memory_convert (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
GdkMemoryFormat dest_format,
|
||||
GdkColorProfile *dest_profile,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
GdkMemoryFormat src_format,
|
||||
GdkColorProfile *src_profile,
|
||||
gsize width,
|
||||
gsize height);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_MEMORY_CONVERT_PRIVATE_H__ */
|
||||
@@ -20,6 +20,9 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
|
||||
#include "gdkcolorprofileprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gsk/ngl/fp16private.h"
|
||||
|
||||
/**
|
||||
@@ -45,80 +48,6 @@ struct _GdkMemoryTextureClass
|
||||
|
||||
G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE)
|
||||
|
||||
gsize
|
||||
gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
return 3;
|
||||
|
||||
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_B8G8R8A8:
|
||||
case GDK_MEMORY_A8R8G8B8:
|
||||
case GDK_MEMORY_R8G8B8A8:
|
||||
case GDK_MEMORY_A8B8G8R8:
|
||||
return 4;
|
||||
|
||||
case GDK_MEMORY_R16G16B16:
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
return 6;
|
||||
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
return 8;
|
||||
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
return 12;
|
||||
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
return 16;
|
||||
|
||||
case GDK_MEMORY_N_FORMATS:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static gsize
|
||||
gdk_memory_format_alignment (GdkMemoryFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_B8G8R8A8:
|
||||
case GDK_MEMORY_A8R8G8B8:
|
||||
case GDK_MEMORY_R8G8B8A8:
|
||||
case GDK_MEMORY_A8B8G8R8:
|
||||
return G_ALIGNOF (guchar);
|
||||
|
||||
case GDK_MEMORY_R16G16B16:
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
return G_ALIGNOF (guint16);
|
||||
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
return G_ALIGNOF (guint16);
|
||||
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
return G_ALIGNOF (float);
|
||||
|
||||
case GDK_MEMORY_N_FORMATS:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return G_ALIGNOF (double);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_memory_texture_dispose (GObject *object)
|
||||
{
|
||||
@@ -143,10 +72,12 @@ gdk_memory_texture_download (GdkTexture *texture,
|
||||
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
|
||||
|
||||
gdk_memory_convert (data, stride,
|
||||
GDK_MEMORY_CONVERT_DOWNLOAD,
|
||||
GDK_MEMORY_DEFAULT,
|
||||
gdk_color_profile_get_srgb (),
|
||||
(guchar *) g_bytes_get_data (self->bytes, NULL),
|
||||
self->stride,
|
||||
self->format,
|
||||
gdk_texture_get_color_profile (texture),
|
||||
gdk_texture_get_width (texture),
|
||||
gdk_texture_get_height (texture));
|
||||
}
|
||||
@@ -158,12 +89,24 @@ gdk_memory_texture_download_float (GdkTexture *texture,
|
||||
{
|
||||
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
|
||||
|
||||
gdk_memory_convert_to_float (data, stride,
|
||||
(guchar *) g_bytes_get_data (self->bytes, NULL),
|
||||
self->stride,
|
||||
self->format,
|
||||
gdk_texture_get_width (texture),
|
||||
gdk_texture_get_height (texture));
|
||||
gdk_memory_convert ((guchar *) data,
|
||||
stride * sizeof (float),
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
||||
gdk_color_profile_get_srgb (),
|
||||
(guchar *) g_bytes_get_data (self->bytes, NULL),
|
||||
self->stride,
|
||||
self->format,
|
||||
gdk_texture_get_color_profile (texture),
|
||||
gdk_texture_get_width (texture),
|
||||
gdk_texture_get_height (texture));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_memory_texture_is_hdr (GdkTexture *texture)
|
||||
{
|
||||
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
|
||||
|
||||
return gdk_memory_format_is_hdr (self->format);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -175,6 +118,7 @@ gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
|
||||
texture_class->download_texture = gdk_memory_texture_download_texture;
|
||||
texture_class->download = gdk_memory_texture_download;
|
||||
texture_class->download_float = gdk_memory_texture_download_float;
|
||||
texture_class->is_hdr = gdk_memory_texture_is_hdr;
|
||||
gobject_class->dispose = gdk_memory_texture_dispose;
|
||||
}
|
||||
|
||||
@@ -231,6 +175,9 @@ gdk_memory_sanitize (GBytes *bytes,
|
||||
* The `GBytes` must contain @stride x @height pixels
|
||||
* in the given format.
|
||||
*
|
||||
* This function calls [ctor@Gdk.MemoryTexture.new_with_color_profile]
|
||||
* with the sRGB profile.
|
||||
*
|
||||
* Returns: A newly-created `GdkTexture`
|
||||
*/
|
||||
GdkTexture *
|
||||
@@ -239,11 +186,49 @@ gdk_memory_texture_new (int width,
|
||||
GdkMemoryFormat format,
|
||||
GBytes *bytes,
|
||||
gsize stride)
|
||||
{
|
||||
g_return_val_if_fail (width > 0, NULL);
|
||||
g_return_val_if_fail (height > 0, NULL);
|
||||
g_return_val_if_fail (bytes != NULL, NULL);
|
||||
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
|
||||
|
||||
return gdk_memory_texture_new_with_color_profile (width, height,
|
||||
format,
|
||||
gdk_color_profile_get_srgb (),
|
||||
bytes, stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_memory_texture_new_with_color_profile:
|
||||
* @width: the width of the texture
|
||||
* @height: the height of the texture
|
||||
* @format: the format of the data
|
||||
* @color_profile: a `GdkColorProfile`
|
||||
* @bytes: the `GBytes` containing the pixel data
|
||||
* @stride: rowstride for the data
|
||||
*
|
||||
* Creates a new texture for a blob of image data with a given color profile.
|
||||
*
|
||||
* The `GBytes` must contain @stride x @height pixels
|
||||
* in the given format.
|
||||
*
|
||||
* Returns: A newly-created `GdkTexture`
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
GdkTexture *
|
||||
gdk_memory_texture_new_with_color_profile (int width,
|
||||
int height,
|
||||
GdkMemoryFormat format,
|
||||
GdkColorProfile *color_profile,
|
||||
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 (GDK_IS_COLOR_PROFILE (color_profile), NULL);
|
||||
g_return_val_if_fail (bytes != NULL, NULL);
|
||||
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
|
||||
|
||||
@@ -252,6 +237,7 @@ gdk_memory_texture_new (int width,
|
||||
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
|
||||
"width", width,
|
||||
"height", height,
|
||||
"color-profile", color_profile,
|
||||
NULL);
|
||||
|
||||
self->format = format;
|
||||
@@ -261,12 +247,88 @@ gdk_memory_texture_new (int width,
|
||||
return GDK_TEXTURE (self);
|
||||
}
|
||||
|
||||
GdkMemoryTexture *
|
||||
gdk_memory_texture_convert (GdkMemoryTexture *source,
|
||||
GdkMemoryFormat to_format,
|
||||
GdkColorProfile *to_profile,
|
||||
const GdkRectangle *rect_or_null)
|
||||
{
|
||||
GdkTexture *texture = GDK_TEXTURE (source);
|
||||
GdkTexture *result;
|
||||
GBytes *to_bytes;
|
||||
int width, height;
|
||||
gsize offset, stride;
|
||||
|
||||
width = texture->width;
|
||||
height = texture->height;
|
||||
if (rect_or_null)
|
||||
{
|
||||
g_assert (rect_or_null->x + rect_or_null->width <= width);
|
||||
g_assert (rect_or_null->y + rect_or_null->height <= height);
|
||||
|
||||
offset = rect_or_null->y * source->stride +
|
||||
rect_or_null->x * gdk_memory_format_bytes_per_pixel (source->format);
|
||||
width = rect_or_null->width;
|
||||
height = rect_or_null->height;
|
||||
}
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
if (to_format == source->format &&
|
||||
gdk_color_profile_equal (texture->color_profile, to_profile))
|
||||
{
|
||||
if (offset == 0 && width == texture->width && height == texture->height)
|
||||
return source;
|
||||
|
||||
to_bytes = g_bytes_new_from_bytes (source->bytes,
|
||||
offset,
|
||||
source->stride * height);
|
||||
stride = source->stride;
|
||||
}
|
||||
else
|
||||
{
|
||||
guchar *data;
|
||||
|
||||
stride = gdk_memory_format_bytes_per_pixel (to_format) * width;
|
||||
data = g_malloc_n (stride, height);
|
||||
gdk_memory_convert (data,
|
||||
stride,
|
||||
to_format,
|
||||
to_profile,
|
||||
(guchar *) g_bytes_get_data (source->bytes, NULL) + offset,
|
||||
source->stride,
|
||||
source->format,
|
||||
texture->color_profile,
|
||||
width,
|
||||
height);
|
||||
to_bytes = g_bytes_new_take (data, stride * height);
|
||||
}
|
||||
|
||||
result = gdk_memory_texture_new_with_color_profile (width,
|
||||
height,
|
||||
to_format,
|
||||
to_profile,
|
||||
to_bytes,
|
||||
stride);
|
||||
|
||||
g_bytes_unref (to_bytes);
|
||||
g_object_unref (source);
|
||||
|
||||
return GDK_MEMORY_TEXTURE (result);
|
||||
}
|
||||
|
||||
GdkMemoryFormat
|
||||
gdk_memory_texture_get_format (GdkMemoryTexture *self)
|
||||
{
|
||||
return self->format;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
gdk_memory_texture_get_bytes (GdkMemoryTexture *self)
|
||||
{
|
||||
return self->bytes;
|
||||
}
|
||||
|
||||
const guchar *
|
||||
gdk_memory_texture_get_data (GdkMemoryTexture *self)
|
||||
{
|
||||
@@ -279,429 +341,3 @@ gdk_memory_texture_get_stride (GdkMemoryTexture *self)
|
||||
return self->stride;
|
||||
}
|
||||
|
||||
static void
|
||||
convert_memcpy (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
gsize width,
|
||||
gsize height)
|
||||
{
|
||||
gsize y;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
memcpy (dest_data + y * dest_stride, src_data + y * src_stride, 4 * width);
|
||||
}
|
||||
|
||||
#define SWIZZLE(A,R,G,B) \
|
||||
static void \
|
||||
convert_swizzle ## A ## R ## G ## B (guchar *dest_data, \
|
||||
gsize dest_stride, \
|
||||
const guchar *src_data, \
|
||||
gsize src_stride, \
|
||||
gsize width, \
|
||||
gsize height) \
|
||||
{ \
|
||||
gsize x, y; \
|
||||
\
|
||||
for (y = 0; y < height; y++) \
|
||||
{ \
|
||||
for (x = 0; x < width; x++) \
|
||||
{ \
|
||||
dest_data[4 * x + A] = src_data[4 * x + 0]; \
|
||||
dest_data[4 * x + R] = src_data[4 * x + 1]; \
|
||||
dest_data[4 * x + G] = src_data[4 * x + 2]; \
|
||||
dest_data[4 * x + B] = src_data[4 * x + 3]; \
|
||||
} \
|
||||
\
|
||||
dest_data += dest_stride; \
|
||||
src_data += src_stride; \
|
||||
} \
|
||||
}
|
||||
|
||||
SWIZZLE(3,2,1,0)
|
||||
SWIZZLE(2,1,0,3)
|
||||
SWIZZLE(3,0,1,2)
|
||||
SWIZZLE(1,2,3,0)
|
||||
|
||||
#define SWIZZLE_OPAQUE(A,R,G,B) \
|
||||
static void \
|
||||
convert_swizzle_opaque_## A ## R ## G ## B (guchar *dest_data, \
|
||||
gsize dest_stride, \
|
||||
const guchar *src_data, \
|
||||
gsize src_stride, \
|
||||
gsize width, \
|
||||
gsize height) \
|
||||
{ \
|
||||
gsize x, y; \
|
||||
\
|
||||
for (y = 0; y < height; y++) \
|
||||
{ \
|
||||
for (x = 0; x < width; x++) \
|
||||
{ \
|
||||
dest_data[4 * x + A] = 0xFF; \
|
||||
dest_data[4 * x + R] = src_data[3 * x + 0]; \
|
||||
dest_data[4 * x + G] = src_data[3 * x + 1]; \
|
||||
dest_data[4 * x + B] = src_data[3 * x + 2]; \
|
||||
} \
|
||||
\
|
||||
dest_data += dest_stride; \
|
||||
src_data += src_stride; \
|
||||
} \
|
||||
}
|
||||
|
||||
SWIZZLE_OPAQUE(3,2,1,0)
|
||||
SWIZZLE_OPAQUE(3,0,1,2)
|
||||
SWIZZLE_OPAQUE(0,1,2,3)
|
||||
SWIZZLE_OPAQUE(0,3,2,1)
|
||||
|
||||
#define PREMULTIPLY(d,c,a) G_STMT_START { guint t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END
|
||||
#define SWIZZLE_PREMULTIPLY(A,R,G,B, A2,R2,G2,B2) \
|
||||
static void \
|
||||
convert_swizzle_premultiply_ ## A ## R ## G ## B ## _ ## A2 ## R2 ## G2 ## B2 \
|
||||
(guchar *dest_data, \
|
||||
gsize dest_stride, \
|
||||
const guchar *src_data, \
|
||||
gsize src_stride, \
|
||||
gsize width, \
|
||||
gsize height) \
|
||||
{ \
|
||||
gsize x, y; \
|
||||
\
|
||||
for (y = 0; y < height; y++) \
|
||||
{ \
|
||||
for (x = 0; x < width; x++) \
|
||||
{ \
|
||||
dest_data[4 * x + A] = src_data[4 * x + A2]; \
|
||||
PREMULTIPLY(dest_data[4 * x + R], src_data[4 * x + R2], src_data[4 * x + A2]); \
|
||||
PREMULTIPLY(dest_data[4 * x + G], src_data[4 * x + G2], src_data[4 * x + A2]); \
|
||||
PREMULTIPLY(dest_data[4 * x + B], src_data[4 * x + B2], src_data[4 * x + A2]); \
|
||||
} \
|
||||
\
|
||||
dest_data += dest_stride; \
|
||||
src_data += src_stride; \
|
||||
} \
|
||||
}
|
||||
|
||||
SWIZZLE_PREMULTIPLY (3,2,1,0, 3,2,1,0)
|
||||
SWIZZLE_PREMULTIPLY (0,1,2,3, 3,2,1,0)
|
||||
SWIZZLE_PREMULTIPLY (3,2,1,0, 0,1,2,3)
|
||||
SWIZZLE_PREMULTIPLY (0,1,2,3, 0,1,2,3)
|
||||
SWIZZLE_PREMULTIPLY (3,2,1,0, 3,0,1,2)
|
||||
SWIZZLE_PREMULTIPLY (0,1,2,3, 3,0,1,2)
|
||||
SWIZZLE_PREMULTIPLY (3,2,1,0, 0,3,2,1)
|
||||
SWIZZLE_PREMULTIPLY (0,1,2,3, 0,3,2,1)
|
||||
SWIZZLE_PREMULTIPLY (3,0,1,2, 3,2,1,0)
|
||||
SWIZZLE_PREMULTIPLY (3,0,1,2, 0,1,2,3)
|
||||
SWIZZLE_PREMULTIPLY (3,0,1,2, 3,0,1,2)
|
||||
SWIZZLE_PREMULTIPLY (3,0,1,2, 0,3,2,1)
|
||||
|
||||
#define CONVERT_FUNC(name,suffix,R,G,B,A,step) \
|
||||
static void \
|
||||
convert_ ## name ## _to_ ## suffix (guchar *dest_data, \
|
||||
gsize dest_stride, \
|
||||
const guchar *src_data, \
|
||||
gsize src_stride, \
|
||||
gsize width, \
|
||||
gsize height) \
|
||||
{ \
|
||||
gsize x, y; \
|
||||
\
|
||||
for (y = 0; y < height; y++) \
|
||||
{ \
|
||||
for (x = 0; x < width; x++) \
|
||||
{ \
|
||||
guchar conv[4]; \
|
||||
convert_pixel_ ## name (conv, src_data + step * x); \
|
||||
dest_data[4 * x + R] = conv[0]; \
|
||||
dest_data[4 * x + G] = conv[1]; \
|
||||
dest_data[4 * x + B] = conv[2]; \
|
||||
dest_data[4 * x + A] = conv[3]; \
|
||||
} \
|
||||
\
|
||||
dest_data += dest_stride; \
|
||||
src_data += src_stride; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CONVERT_FUNCS(name,step) \
|
||||
CONVERT_FUNC(name, download_le, 2, 1, 0, 3, step) \
|
||||
CONVERT_FUNC(name, download_be, 1, 2, 3, 0, step) \
|
||||
CONVERT_FUNC(name, gles_rgba, 0, 1, 2, 3, step) \
|
||||
|
||||
static inline void
|
||||
convert_pixel_rgb16 (guchar *dest_data, const guchar *src_data)
|
||||
{
|
||||
const guint16 *src = (const guint16 *) src_data;
|
||||
dest_data[0] = (guchar)(src[0] >> 8);
|
||||
dest_data[1] = (guchar)(src[1] >> 8);
|
||||
dest_data[2] = (guchar)(src[2] >> 8);
|
||||
dest_data[3] = 0xFF;
|
||||
}
|
||||
CONVERT_FUNCS(rgb16, 3 * sizeof (guint16))
|
||||
|
||||
static inline void
|
||||
convert_pixel_rgba16 (guchar *dest_data, const guchar *src_data)
|
||||
{
|
||||
const guint16 *src = (const guint16 *) src_data;
|
||||
dest_data[0] = (guchar)(src[0] >> 8);
|
||||
dest_data[1] = (guchar)(src[1] >> 8);
|
||||
dest_data[2] = (guchar)(src[2] >> 8);
|
||||
dest_data[3] = (guchar)(src[3] >> 8);
|
||||
}
|
||||
CONVERT_FUNCS(rgba16, 4 * sizeof (guint16))
|
||||
|
||||
static inline void
|
||||
convert_pixel_rgb16f (guchar *dest_data, const guchar *src_data)
|
||||
{
|
||||
float src[4];
|
||||
guint16 tmp[4];
|
||||
memcpy(tmp, src_data, sizeof(guint16) * 3);
|
||||
half_to_float4(tmp, src);
|
||||
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
|
||||
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
|
||||
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
|
||||
dest_data[3] = 0xFF;
|
||||
}
|
||||
CONVERT_FUNCS(rgb16f, 3 * sizeof (guint16))
|
||||
|
||||
static inline void
|
||||
convert_pixel_rgba16f (guchar *dest_data, const guchar *src_data)
|
||||
{
|
||||
float src[4];
|
||||
half_to_float4((const guint16 *) src_data, src);
|
||||
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
|
||||
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
|
||||
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
|
||||
dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
|
||||
}
|
||||
CONVERT_FUNCS(rgba16f, 4 * sizeof (guint16))
|
||||
|
||||
static inline void
|
||||
convert_pixel_rgb32f (guchar *dest_data, const guchar *src_data)
|
||||
{
|
||||
float *src = (float *) src_data;
|
||||
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
|
||||
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
|
||||
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
|
||||
dest_data[3] = 0xFF;
|
||||
}
|
||||
CONVERT_FUNCS(rgb32f, 3 * sizeof (float))
|
||||
|
||||
static inline void
|
||||
convert_pixel_rgba32f (guchar *dest_data, const guchar *src_data)
|
||||
{
|
||||
float *src = (float *) src_data;
|
||||
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
|
||||
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
|
||||
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
|
||||
dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
|
||||
}
|
||||
CONVERT_FUNCS(rgba32f, 4 * sizeof (float))
|
||||
|
||||
typedef void (* ConversionFunc) (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
gsize width,
|
||||
gsize height);
|
||||
|
||||
static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_CONVERSIONS] =
|
||||
{
|
||||
{ convert_memcpy, convert_swizzle3210, convert_swizzle2103 },
|
||||
{ convert_swizzle3210, convert_memcpy, convert_swizzle3012 },
|
||||
{ convert_swizzle2103, convert_swizzle1230, convert_memcpy },
|
||||
{ convert_swizzle_premultiply_3210_3210, convert_swizzle_premultiply_0123_3210, convert_swizzle_premultiply_3012_3210, },
|
||||
{ convert_swizzle_premultiply_3210_0123, convert_swizzle_premultiply_0123_0123, convert_swizzle_premultiply_3012_0123 },
|
||||
{ convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, convert_swizzle_premultiply_3012_3012 },
|
||||
{ convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, convert_swizzle_premultiply_3012_0321 },
|
||||
{ convert_swizzle_opaque_3210, convert_swizzle_opaque_0123, convert_swizzle_opaque_3012 },
|
||||
{ convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 },
|
||||
{ convert_rgb16_to_download_le, convert_rgb16_to_download_be, convert_rgb16_to_gles_rgba },
|
||||
{ convert_rgba16_to_download_le, convert_rgba16_to_download_be, convert_rgba16_to_gles_rgba },
|
||||
{ convert_rgb16f_to_download_le, convert_rgb16f_to_download_be, convert_rgb16f_to_gles_rgba },
|
||||
{ convert_rgba16f_to_download_le, convert_rgba16f_to_download_be, convert_rgba16f_to_gles_rgba },
|
||||
{ convert_rgb32f_to_download_le, convert_rgb32f_to_download_be, convert_rgb32f_to_gles_rgba },
|
||||
{ convert_rgba32f_to_download_le, convert_rgba32f_to_download_be, convert_rgba32f_to_gles_rgba }
|
||||
};
|
||||
|
||||
void
|
||||
gdk_memory_convert (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
GdkMemoryConversion dest_format,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
GdkMemoryFormat src_format,
|
||||
gsize width,
|
||||
gsize height)
|
||||
{
|
||||
g_assert (dest_format < 3);
|
||||
g_assert (src_format < GDK_MEMORY_N_FORMATS);
|
||||
|
||||
converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height);
|
||||
}
|
||||
|
||||
#define CONVERT_FLOAT(R,G,B,A,premultiply) G_STMT_START {\
|
||||
for (y = 0; y < height; y++) \
|
||||
{ \
|
||||
for (x = 0; x < width; x++) \
|
||||
{ \
|
||||
if (A >= 0) \
|
||||
{ \
|
||||
dest_data[4 * x + 0] = src_data[4 * x + R] / 255.0f; \
|
||||
dest_data[4 * x + 1] = src_data[4 * x + G] / 255.0f; \
|
||||
dest_data[4 * x + 2] = src_data[4 * x + B] / 255.0f; \
|
||||
dest_data[4 * x + 3] = src_data[4 * x + A] / 255.0f; \
|
||||
if (premultiply) \
|
||||
{ \
|
||||
dest_data[4 * x + 0] *= dest_data[4 * x + 3]; \
|
||||
dest_data[4 * x + 1] *= dest_data[4 * x + 3]; \
|
||||
dest_data[4 * x + 2] *= dest_data[4 * x + 3]; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
dest_data[4 * x + 0] = src_data[3 * x + R] / 255.0f; \
|
||||
dest_data[4 * x + 1] = src_data[3 * x + G] / 255.0f; \
|
||||
dest_data[4 * x + 2] = src_data[3 * x + B] / 255.0f; \
|
||||
dest_data[4 * x + 3] = 1.0; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
dest_data += dest_stride; \
|
||||
src_data += src_stride; \
|
||||
} \
|
||||
}G_STMT_END
|
||||
|
||||
#define CONVERT_FLOAT_PIXEL(func,step) G_STMT_START{\
|
||||
for (y = 0; y < height; y++) \
|
||||
{ \
|
||||
for (x = 0; x < width; x++) \
|
||||
{ \
|
||||
func (dest_data + 4 * x, src_data + step * x); \
|
||||
} \
|
||||
\
|
||||
dest_data += dest_stride; \
|
||||
src_data += src_stride; \
|
||||
} \
|
||||
}G_STMT_END
|
||||
|
||||
static inline void
|
||||
convert_rgb16_to_float (float *dest, const guchar *src_data)
|
||||
{
|
||||
const guint16 *src = (const guint16 *) src_data;
|
||||
dest[0] = src[0] / 65535.f;
|
||||
dest[1] = src[1] / 65535.f;
|
||||
dest[2] = src[2] / 65535.f;
|
||||
dest[3] = 1.0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
convert_rgba16_to_float (float *dest, const guchar *src_data)
|
||||
{
|
||||
const guint16 *src = (const guint16 *) src_data;
|
||||
dest[0] = src[0] / 65535.f;
|
||||
dest[1] = src[1] / 65535.f;
|
||||
dest[2] = src[2] / 65535.f;
|
||||
dest[3] = src[3] / 65535.f;
|
||||
}
|
||||
|
||||
static inline void
|
||||
convert_rgb16f_to_float (float *dest, const guchar *src_data)
|
||||
{
|
||||
guint16 tmp[4];
|
||||
memcpy(tmp, src_data, sizeof(guint16) * 3);
|
||||
tmp[3] = FP16_ONE;
|
||||
half_to_float4 (tmp, dest);
|
||||
}
|
||||
|
||||
static inline void
|
||||
convert_rgba16f_to_float (float *dest, const guchar *src_data)
|
||||
{
|
||||
half_to_float4 ((const guint16 *) src_data, dest);
|
||||
}
|
||||
|
||||
static inline void
|
||||
convert_rgb32f_to_float (float *dest, const guchar *src_data)
|
||||
{
|
||||
const float *src = (const float *) src_data;
|
||||
dest[0] = src[0];
|
||||
dest[1] = src[1];
|
||||
dest[2] = src[2];
|
||||
dest[3] = 1.0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
convert_rgba32f_to_float (float *dest, const guchar *src_data)
|
||||
{
|
||||
const float *src = (const float *) src_data;
|
||||
dest[0] = src[0];
|
||||
dest[1] = src[1];
|
||||
dest[2] = src[2];
|
||||
dest[3] = src[3];
|
||||
}
|
||||
|
||||
void
|
||||
gdk_memory_convert_to_float (float *dest_data,
|
||||
gsize dest_stride,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
GdkMemoryFormat src_format,
|
||||
gsize width,
|
||||
gsize height)
|
||||
{
|
||||
gsize x, y;
|
||||
|
||||
switch (src_format)
|
||||
{
|
||||
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
|
||||
CONVERT_FLOAT (2, 1, 0, 3, FALSE);
|
||||
break;
|
||||
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
|
||||
CONVERT_FLOAT (1, 2, 3, 0, FALSE);
|
||||
break;
|
||||
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
|
||||
CONVERT_FLOAT (0, 1, 2, 3, FALSE);
|
||||
break;
|
||||
case GDK_MEMORY_B8G8R8A8:
|
||||
CONVERT_FLOAT (2, 1, 0, 3, TRUE);
|
||||
break;
|
||||
case GDK_MEMORY_A8R8G8B8:
|
||||
CONVERT_FLOAT (1, 2, 3, 0, TRUE);
|
||||
break;
|
||||
case GDK_MEMORY_R8G8B8A8:
|
||||
CONVERT_FLOAT (0, 1, 2, 3, TRUE);
|
||||
break;
|
||||
case GDK_MEMORY_A8B8G8R8:
|
||||
CONVERT_FLOAT (3, 2, 1, 0, TRUE);
|
||||
break;
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
CONVERT_FLOAT (0, 1, 2, -1, FALSE);
|
||||
break;
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
CONVERT_FLOAT (2, 1, 0, -1, FALSE);
|
||||
break;
|
||||
case GDK_MEMORY_R16G16B16:
|
||||
CONVERT_FLOAT_PIXEL (convert_rgb16_to_float, 3 * sizeof (guint16));
|
||||
break;
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
CONVERT_FLOAT_PIXEL (convert_rgba16_to_float, 4 * sizeof (guint16));
|
||||
break;
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
CONVERT_FLOAT_PIXEL (convert_rgb16f_to_float, 3 * sizeof (guint16));
|
||||
break;
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
CONVERT_FLOAT_PIXEL (convert_rgba16f_to_float, 4 * sizeof (guint16));
|
||||
break;
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
CONVERT_FLOAT_PIXEL (convert_rgb32f_to_float, 3 * sizeof (float));
|
||||
break;
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
CONVERT_FLOAT_PIXEL (convert_rgba32f_to_float, 4 * sizeof (float));
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_N_FORMATS:
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,11 @@ typedef enum {
|
||||
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
||||
GDK_MEMORY_R32G32B32_FLOAT,
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
||||
#ifdef GTK_COMPILATION
|
||||
GDK_MEMORY_R16G16B16A16,
|
||||
GDK_MEMORY_R16G16B16A16_FLOAT,
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT,
|
||||
#endif
|
||||
|
||||
GDK_MEMORY_N_FORMATS
|
||||
} GdkMemoryFormat;
|
||||
@@ -130,6 +135,14 @@ GdkTexture * gdk_memory_texture_new (int
|
||||
GdkMemoryFormat format,
|
||||
GBytes *bytes,
|
||||
gsize stride);
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkTexture * gdk_memory_texture_new_with_color_profile
|
||||
(int width,
|
||||
int height,
|
||||
GdkMemoryFormat format,
|
||||
GdkColorProfile *color_profile,
|
||||
GBytes *bytes,
|
||||
gsize stride);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -29,44 +29,15 @@ G_BEGIN_DECLS
|
||||
#define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8
|
||||
#define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8
|
||||
|
||||
typedef enum {
|
||||
GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN,
|
||||
GDK_MEMORY_CONVERT_DOWNLOAD_BIT_ENDIAN,
|
||||
GDK_MEMORY_CONVERT_GLES_RGBA,
|
||||
GdkMemoryTexture * gdk_memory_texture_convert (GdkMemoryTexture *source,
|
||||
GdkMemoryFormat to_format,
|
||||
GdkColorProfile *to_profile,
|
||||
const GdkRectangle *rect_or_null);
|
||||
|
||||
GDK_MEMORY_N_CONVERSIONS
|
||||
} GdkMemoryConversion;
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_BIG_ENDIAN
|
||||
#else
|
||||
#error "Unknown byte order for GDK_MEMORY_CONVERT_DOWNLOAD"
|
||||
#endif
|
||||
|
||||
gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format);
|
||||
|
||||
GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *self);
|
||||
const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self);
|
||||
gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self);
|
||||
|
||||
void gdk_memory_convert (guchar *dest_data,
|
||||
gsize dest_stride,
|
||||
GdkMemoryConversion dest_format,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
GdkMemoryFormat src_format,
|
||||
gsize width,
|
||||
gsize height);
|
||||
|
||||
void gdk_memory_convert_to_float (float *dest_data,
|
||||
gsize dest_stride,
|
||||
const guchar *src_data,
|
||||
gsize src_stride,
|
||||
GdkMemoryFormat src_format,
|
||||
gsize width,
|
||||
gsize height);
|
||||
GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *self);
|
||||
GBytes * gdk_memory_texture_get_bytes (GdkMemoryTexture *self);
|
||||
const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self);
|
||||
gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
|
||||
#include "gdkpixbuf.h"
|
||||
|
||||
#include "gdkcolorprofile.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdksurface.h"
|
||||
#include "gdktextureprivate.h"
|
||||
|
||||
@@ -214,6 +217,13 @@ gdk_pixbuf_get_from_surface (cairo_surface_t *surface,
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void
|
||||
pixbuf_texture_unref_cb (guchar *pixels,
|
||||
gpointer texture)
|
||||
{
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_get_from_texture:
|
||||
* @texture: a `GdkTexture`
|
||||
@@ -229,17 +239,24 @@ gdk_pixbuf_get_from_surface (cairo_surface_t *surface,
|
||||
GdkPixbuf *
|
||||
gdk_pixbuf_get_from_texture (GdkTexture *texture)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
cairo_surface_t *surface;
|
||||
int width, height;
|
||||
GdkMemoryTexture *memtex;
|
||||
gboolean alpha;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
|
||||
memtex = GDK_MEMORY_TEXTURE (gdk_texture_download_texture (texture));
|
||||
alpha = gdk_memory_format_alpha (gdk_memory_texture_get_format (memtex)) != GDK_MEMORY_ALPHA_OPAQUE;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
surface = gdk_texture_download_surface (texture);
|
||||
pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
return pixbuf;
|
||||
memtex = gdk_memory_texture_convert (memtex,
|
||||
alpha ? GDK_MEMORY_GDK_PIXBUF_ALPHA
|
||||
: GDK_MEMORY_GDK_PIXBUF_OPAQUE,
|
||||
gdk_color_profile_get_srgb (),
|
||||
NULL);
|
||||
return gdk_pixbuf_new_from_data (gdk_memory_texture_get_data (memtex),
|
||||
GDK_COLORSPACE_RGB,
|
||||
alpha,
|
||||
8,
|
||||
gdk_texture_get_width (GDK_TEXTURE (memtex)),
|
||||
gdk_texture_get_height (GDK_TEXTURE (memtex)),
|
||||
gdk_memory_texture_get_stride (memtex),
|
||||
pixbuf_texture_unref_cb,
|
||||
memtex);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "gdksurface.h"
|
||||
|
||||
#include "gdk-private.h"
|
||||
#include "gdkcairo.h"
|
||||
#include "gdkcolorprofile.h"
|
||||
#include "gdkcontentprovider.h"
|
||||
#include "gdkdeviceprivate.h"
|
||||
#include "gdkdisplayprivate.h"
|
||||
@@ -88,13 +90,14 @@ enum {
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_COLOR_PROFILE,
|
||||
PROP_CURSOR,
|
||||
PROP_DISPLAY,
|
||||
PROP_FRAME_CLOCK,
|
||||
PROP_MAPPED,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
PROP_MAPPED,
|
||||
PROP_SCALE_FACTOR,
|
||||
PROP_WIDTH,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
@@ -485,10 +488,18 @@ gdk_surface_init (GdkSurface *surface)
|
||||
|
||||
surface->alpha = 255;
|
||||
|
||||
surface->color_profile = g_object_ref (gdk_color_profile_get_srgb ());
|
||||
|
||||
surface->device_cursor = g_hash_table_new_full (NULL, NULL,
|
||||
NULL, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_surface_real_set_hdr (GdkSurface *surface,
|
||||
gboolean hdr)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_surface_class_init (GdkSurfaceClass *klass)
|
||||
{
|
||||
@@ -499,6 +510,25 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
|
||||
object_class->get_property = gdk_surface_get_property;
|
||||
|
||||
klass->beep = gdk_surface_real_beep;
|
||||
klass->set_hdr = gdk_surface_real_set_hdr;
|
||||
|
||||
/**
|
||||
* GdkSurface:color-profile: (attributes org.gtk.Property.get=gdk_surface_get_color_profile)
|
||||
*
|
||||
* The preferred color profile for rendering to the surface
|
||||
*
|
||||
* This profile is negotiated between GTK and the compositor.
|
||||
*
|
||||
* The profile may change as the surface gets moved around - for example to different
|
||||
* monitors or when the compositor gets reconfigured. As long as the surface isn't show, the
|
||||
* profile may not represent the actual color profile that is going to be used.
|
||||
*/
|
||||
properties[PROP_COLOR_PROFILE] =
|
||||
g_param_spec_object ("color-profile",
|
||||
P_("Color profile"),
|
||||
P_("The preferred color profile of the surface"),
|
||||
GDK_TYPE_COLOR_PROFILE,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkSurface:cursor: (attributes org.gtk.Property.get=gdk_surface_get_cursor org.gtk.Property.set=gdk_surface_set_cursor)
|
||||
@@ -729,6 +759,7 @@ gdk_surface_finalize (GObject *object)
|
||||
g_clear_object (&surface->cursor);
|
||||
g_clear_pointer (&surface->device_cursor, g_hash_table_destroy);
|
||||
g_clear_pointer (&surface->devices_inside, g_list_free);
|
||||
g_clear_object (&surface->color_profile);
|
||||
|
||||
g_clear_object (&surface->display);
|
||||
|
||||
@@ -783,6 +814,10 @@ gdk_surface_get_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_COLOR_PROFILE:
|
||||
g_value_set_object (value, gdk_surface_get_color_profile (surface));
|
||||
break;
|
||||
|
||||
case PROP_CURSOR:
|
||||
g_value_set_object (value, gdk_surface_get_cursor (surface));
|
||||
break;
|
||||
@@ -2049,6 +2084,38 @@ gdk_surface_get_height (GdkSurface *surface)
|
||||
return surface->height;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_surface_set_color_profile (GdkSurface *self,
|
||||
GdkColorProfile *color_profile)
|
||||
{
|
||||
/* This way we support unsetting, too */
|
||||
if (GDK_DISPLAY_DEBUG_CHECK (self->display, SRGB))
|
||||
color_profile = gdk_color_profile_get_srgb();
|
||||
|
||||
if (gdk_color_profile_equal (self->color_profile, color_profile))
|
||||
return;
|
||||
|
||||
g_set_object (&self->color_profile, color_profile);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_PROFILE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_surface_get_color_profile: (attributes org.gtk.Method.get_property=color-profile)
|
||||
* @self: a `GdkSurface`
|
||||
*
|
||||
* Returns the preferred color profile for rendering to the given @surface.
|
||||
*
|
||||
* Returns: (transfer none): The color profile of @surface
|
||||
*/
|
||||
GdkColorProfile *
|
||||
gdk_surface_get_color_profile (GdkSurface *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_SURFACE (self), gdk_color_profile_get_srgb ());
|
||||
|
||||
return self->color_profile;
|
||||
}
|
||||
|
||||
/*
|
||||
* gdk_surface_get_origin:
|
||||
* @surface: a `GdkSurface`
|
||||
@@ -2361,7 +2428,7 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
* with it.
|
||||
*/
|
||||
cairo_surface_t *
|
||||
gdk_surface_create_similar_surface (GdkSurface * surface,
|
||||
gdk_surface_create_similar_surface (GdkSurface * surface,
|
||||
cairo_content_t content,
|
||||
int width,
|
||||
int height)
|
||||
@@ -2377,6 +2444,7 @@ gdk_surface_create_similar_surface (GdkSurface * surface,
|
||||
content == CAIRO_CONTENT_ALPHA ? CAIRO_FORMAT_A8 : CAIRO_FORMAT_ARGB32,
|
||||
width * scale, height * scale);
|
||||
cairo_surface_set_device_scale (similar_surface, scale, scale);
|
||||
gdk_cairo_surface_set_color_profile (similar_surface, gdk_surface_get_color_profile (surface));
|
||||
|
||||
return similar_surface;
|
||||
}
|
||||
@@ -3063,3 +3131,11 @@ gdk_surface_leave_monitor (GdkSurface *surface,
|
||||
{
|
||||
g_signal_emit (surface, signals[LEAVE_MONITOR], 0, monitor);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_surface_set_hdr (GdkSurface *surface,
|
||||
gboolean hdr)
|
||||
{
|
||||
GDK_SURFACE_GET_CLASS (surface)->set_hdr (surface, hdr);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,17 +86,19 @@ GDK_AVAILABLE_IN_ALL
|
||||
GdkCursor *gdk_surface_get_device_cursor (GdkSurface *surface,
|
||||
GdkDevice *device);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gdk_surface_get_width (GdkSurface *surface);
|
||||
int gdk_surface_get_width (GdkSurface *surface);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gdk_surface_get_height (GdkSurface *surface);
|
||||
int gdk_surface_get_height (GdkSurface *surface);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_surface_translate_coordinates (GdkSurface *from,
|
||||
GdkSurface *to,
|
||||
double *x,
|
||||
double *y);
|
||||
int gdk_surface_get_scale_factor (GdkSurface *surface);
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkColorProfile * gdk_surface_get_color_profile (GdkSurface *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_surface_translate_coordinates (GdkSurface *from,
|
||||
GdkSurface *to,
|
||||
double *x,
|
||||
double *y);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gdk_surface_get_scale_factor (GdkSurface *surface);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_surface_get_device_position (GdkSurface *surface,
|
||||
|
||||
@@ -52,6 +52,7 @@ struct _GdkSurface
|
||||
int y;
|
||||
|
||||
GdkGLContext *gl_paint_context;
|
||||
GdkColorProfile *color_profile;
|
||||
|
||||
cairo_region_t *update_area;
|
||||
guint update_freeze_count;
|
||||
@@ -160,6 +161,9 @@ struct _GdkSurfaceClass
|
||||
cairo_region_t *region);
|
||||
void (* request_layout) (GdkSurface *surface);
|
||||
gboolean (* compute_size) (GdkSurface *surface);
|
||||
|
||||
void (* set_hdr) (GdkSurface *surface,
|
||||
gboolean hdr);
|
||||
};
|
||||
|
||||
#define GDK_SURFACE_DESTROYED(d) (((GdkSurface *)(d))->destroyed)
|
||||
@@ -171,6 +175,8 @@ void gdk_surface_set_state (GdkSurface *surface,
|
||||
|
||||
void gdk_surface_set_is_mapped (GdkSurface *surface,
|
||||
gboolean is_mapped);
|
||||
void gdk_surface_set_color_profile (GdkSurface *self,
|
||||
GdkColorProfile *color_profile);
|
||||
|
||||
GdkMonitor * gdk_surface_get_layout_monitor (GdkSurface *surface,
|
||||
GdkPopupLayout *layout,
|
||||
@@ -344,6 +350,8 @@ void gdk_surface_request_compute_size (GdkSurface *surface);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_surface_request_motion (GdkSurface *surface);
|
||||
|
||||
void gdk_surface_set_hdr (GdkSurface *surface,
|
||||
gboolean hdr);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
198
gdk/gdktexture.c
@@ -40,7 +40,10 @@
|
||||
|
||||
#include "gdktextureprivate.h"
|
||||
|
||||
#include "gdkcairo.h"
|
||||
#include "gdkiccprofile.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdkpaintable.h"
|
||||
#include "gdksnapshot.h"
|
||||
@@ -60,8 +63,9 @@ gtk_snapshot_append_texture (GdkSnapshot *snapshot,
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_WIDTH,
|
||||
PROP_COLOR_PROFILE,
|
||||
PROP_HEIGHT,
|
||||
PROP_WIDTH,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
@@ -262,14 +266,20 @@ gdk_texture_set_property (GObject *gobject,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_WIDTH:
|
||||
self->width = g_value_get_int (value);
|
||||
case PROP_COLOR_PROFILE:
|
||||
self->color_profile = g_value_dup_object (value);
|
||||
if (self->color_profile == NULL)
|
||||
self->color_profile = g_object_ref (gdk_color_profile_get_srgb ());
|
||||
break;
|
||||
|
||||
case PROP_HEIGHT:
|
||||
self->height = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_WIDTH:
|
||||
self->width = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
@@ -286,14 +296,18 @@ gdk_texture_get_property (GObject *gobject,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_WIDTH:
|
||||
g_value_set_int (value, self->width);
|
||||
case PROP_COLOR_PROFILE:
|
||||
g_value_set_object (value, self->color_profile);
|
||||
break;
|
||||
|
||||
case PROP_HEIGHT:
|
||||
g_value_set_int (value, self->height);
|
||||
break;
|
||||
|
||||
case PROP_WIDTH:
|
||||
g_value_set_int (value, self->width);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
@@ -306,10 +320,17 @@ gdk_texture_dispose (GObject *object)
|
||||
GdkTexture *self = GDK_TEXTURE (object);
|
||||
|
||||
gdk_texture_clear_render_data (self);
|
||||
g_clear_object (&self->color_profile);
|
||||
|
||||
G_OBJECT_CLASS (gdk_texture_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_texture_real_is_hdr (GdkTexture *texture)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_texture_class_init (GdkTextureClass *klass)
|
||||
{
|
||||
@@ -318,20 +339,38 @@ gdk_texture_class_init (GdkTextureClass *klass)
|
||||
klass->download_texture = gdk_texture_real_download_texture;
|
||||
klass->download = gdk_texture_real_download;
|
||||
klass->download_float = gdk_texture_real_download_float;
|
||||
klass->is_hdr = gdk_texture_real_is_hdr;
|
||||
|
||||
gobject_class->set_property = gdk_texture_set_property;
|
||||
gobject_class->get_property = gdk_texture_get_property;
|
||||
gobject_class->dispose = gdk_texture_dispose;
|
||||
|
||||
/**
|
||||
* GdkTexture:width: (attributes org.gtk.Property.get=gdk_texture_get_width)
|
||||
* GdkTexture:color-profile: (attributes org.gtk.Property.get=gdk_texture_get_color_profile)
|
||||
*
|
||||
* The width of the texture, in pixels.
|
||||
* The color profile associated with texture.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
properties[PROP_WIDTH] =
|
||||
g_param_spec_int ("width",
|
||||
"Width",
|
||||
"The width of the texture",
|
||||
properties[PROP_COLOR_PROFILE] =
|
||||
g_param_spec_object ("color-profile",
|
||||
P_("Color Profile"),
|
||||
P_("The associated color profile"),
|
||||
GDK_TYPE_COLOR_PROFILE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GdkTexture:height: (attributes org.gtk.Property.get=gdk_texture_get_height)
|
||||
*
|
||||
* The height of the texture, in pixels.
|
||||
*/
|
||||
properties[PROP_HEIGHT] =
|
||||
g_param_spec_int ("height",
|
||||
P_("Height"),
|
||||
P_("The height of the texture"),
|
||||
1,
|
||||
G_MAXINT,
|
||||
1,
|
||||
@@ -341,14 +380,14 @@ gdk_texture_class_init (GdkTextureClass *klass)
|
||||
G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GdkTexture:height: (attributes org.gtk.Property.get=gdk_texture_get_height)
|
||||
* GdkTexture:width: (attributes org.gtk.Property.get=gdk_texture_get_width)
|
||||
*
|
||||
* The height of the texture, in pixels.
|
||||
* The width of the texture, in pixels.
|
||||
*/
|
||||
properties[PROP_HEIGHT] =
|
||||
g_param_spec_int ("height",
|
||||
"Height",
|
||||
"The height of the texture",
|
||||
properties[PROP_WIDTH] =
|
||||
g_param_spec_int ("width",
|
||||
P_("Width"),
|
||||
P_("The width of the texture"),
|
||||
1,
|
||||
G_MAXINT,
|
||||
1,
|
||||
@@ -391,17 +430,42 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
|
||||
(GDestroyNotify) cairo_surface_destroy,
|
||||
cairo_surface_reference (surface));
|
||||
|
||||
texture = gdk_memory_texture_new (cairo_image_surface_get_width (surface),
|
||||
cairo_image_surface_get_height (surface),
|
||||
GDK_MEMORY_DEFAULT,
|
||||
bytes,
|
||||
cairo_image_surface_get_stride (surface));
|
||||
texture = gdk_memory_texture_new_with_color_profile (cairo_image_surface_get_width (surface),
|
||||
cairo_image_surface_get_height (surface),
|
||||
GDK_MEMORY_DEFAULT,
|
||||
gdk_cairo_surface_get_color_profile (surface),
|
||||
bytes,
|
||||
cairo_image_surface_get_stride (surface));
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static GdkColorProfile *
|
||||
gdk_color_profile_from_pixbuf (GdkPixbuf *pixbuf)
|
||||
{
|
||||
const char *icc_profile_base64;
|
||||
GdkColorProfile *profile = 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);
|
||||
profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (bytes, NULL));
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
if (!profile)
|
||||
profile = g_object_ref (gdk_color_profile_get_srgb ());
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_texture_new_for_pixbuf:
|
||||
* @pixbuf: a `GdkPixbuf`
|
||||
@@ -419,24 +483,31 @@ gdk_texture_new_for_pixbuf (GdkPixbuf *pixbuf)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
GBytes *bytes;
|
||||
GdkColorProfile *profile;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
|
||||
|
||||
profile = gdk_color_profile_from_pixbuf (pixbuf);
|
||||
|
||||
bytes = g_bytes_new_with_free_func (gdk_pixbuf_get_pixels (pixbuf),
|
||||
gdk_pixbuf_get_height (pixbuf)
|
||||
* 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_profile (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,
|
||||
profile,
|
||||
bytes,
|
||||
gdk_pixbuf_get_rowstride (pixbuf));
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
g_object_unref (profile);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@@ -692,23 +763,73 @@ gdk_texture_get_height (GdkTexture *texture)
|
||||
return texture->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_texture_get_color_profile: (attributes org.gtk.Method.get_property=color-profile)
|
||||
* @texture: a `GdkTexture`
|
||||
*
|
||||
* Returns the color profile associsated with @texture.
|
||||
*
|
||||
* Returns: (transfer none): the color profile of the `GdkTexture`
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
GdkColorProfile *
|
||||
gdk_texture_get_color_profile (GdkTexture *texture)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0);
|
||||
|
||||
return texture->color_profile;
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gdk_texture_download_surface:
|
||||
* @texture: the texture to download
|
||||
* @target_profile: (nullable): The target color profile or %NULL for the
|
||||
* default sRGB.
|
||||
*
|
||||
* Downloads the texture into a newly created Cairo surface.
|
||||
*
|
||||
* Returns: A new Cairo surface.
|
||||
**/
|
||||
cairo_surface_t *
|
||||
gdk_texture_download_surface (GdkTexture *texture)
|
||||
gdk_texture_download_surface (GdkTexture *texture,
|
||||
GdkColorProfile *target_profile)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_status_t surface_status;
|
||||
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
texture->width, texture->height);
|
||||
if (target_profile != NULL)
|
||||
gdk_cairo_surface_set_color_profile (surface, target_profile);
|
||||
else
|
||||
target_profile = gdk_color_profile_get_srgb ();
|
||||
|
||||
surface_status = cairo_surface_status (surface);
|
||||
if (surface_status != CAIRO_STATUS_SUCCESS)
|
||||
g_warning ("%s: surface error: %s", __FUNCTION__,
|
||||
cairo_status_to_string (surface_status));
|
||||
{
|
||||
g_warning ("%s: surface error: %s", __FUNCTION__,
|
||||
cairo_status_to_string (surface_status));
|
||||
}
|
||||
else
|
||||
{
|
||||
GdkTexture *download = gdk_texture_download_texture (texture);
|
||||
GdkMemoryTexture *memdownload = GDK_MEMORY_TEXTURE (download);
|
||||
|
||||
gdk_memory_convert (cairo_image_surface_get_data (surface),
|
||||
cairo_image_surface_get_stride (surface),
|
||||
GDK_MEMORY_DEFAULT,
|
||||
target_profile,
|
||||
gdk_memory_texture_get_data (memdownload),
|
||||
gdk_memory_texture_get_stride (memdownload),
|
||||
gdk_memory_texture_get_format (memdownload),
|
||||
download->color_profile,
|
||||
download->width,
|
||||
download->height);
|
||||
g_object_unref (download);
|
||||
}
|
||||
|
||||
gdk_texture_download (texture,
|
||||
cairo_image_surface_get_data (surface),
|
||||
cairo_image_surface_get_stride (surface));
|
||||
cairo_surface_mark_dirty (surface);
|
||||
|
||||
return surface;
|
||||
@@ -973,3 +1094,10 @@ gdk_texture_save_to_tiff_bytes (GdkTexture *texture)
|
||||
return gdk_save_tiff (texture);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_texture_is_hdr (GdkTexture *texture)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_TEXTURE (texture), FALSE);
|
||||
|
||||
return GDK_TEXTURE_GET_CLASS (texture)->is_hdr (texture);
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@ GDK_AVAILABLE_IN_ALL
|
||||
int gdk_texture_get_width (GdkTexture *texture) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gdk_texture_get_height (GdkTexture *texture) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GdkColorProfile * gdk_texture_get_color_profile (GdkTexture *texture) G_GNUC_PURE;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_texture_download (GdkTexture *texture,
|
||||
|
||||
@@ -15,6 +15,7 @@ struct _GdkTexture
|
||||
|
||||
int width;
|
||||
int height;
|
||||
GdkColorProfile *color_profile;
|
||||
|
||||
gpointer render_key;
|
||||
gpointer render_data;
|
||||
@@ -33,12 +34,16 @@ struct _GdkTextureClass {
|
||||
void (* download_float) (GdkTexture *texture,
|
||||
float *data,
|
||||
gsize stride);
|
||||
gboolean (* is_hdr) (GdkTexture *texture);
|
||||
};
|
||||
|
||||
gboolean gdk_texture_can_load (GBytes *bytes);
|
||||
|
||||
gboolean gdk_texture_is_hdr (GdkTexture *self);
|
||||
|
||||
GdkTexture * gdk_texture_new_for_surface (cairo_surface_t *surface);
|
||||
cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture);
|
||||
cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture,
|
||||
GdkColorProfile *color_profile);
|
||||
/* NB: GdkMemoryTexture */
|
||||
GdkTexture * gdk_texture_download_texture (GdkTexture *texture);
|
||||
|
||||
|
||||
@@ -73,6 +73,9 @@ typedef cairo_rectangle_int_t GdkRectangle;
|
||||
|
||||
/* Forward declarations of commonly used types */
|
||||
typedef struct _GdkRGBA GdkRGBA;
|
||||
typedef struct _GdkColorProfile GdkColorProfile;
|
||||
typedef struct _GdkICCProfile GdkICCProfile;
|
||||
typedef struct _GdkDerivedProfile GdkDerivedProfile;
|
||||
typedef struct _GdkContentFormats GdkContentFormats;
|
||||
typedef struct _GdkContentProvider GdkContentProvider;
|
||||
typedef struct _GdkCursor GdkCursor;
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
|
||||
#include "gdkjpegprivate.h"
|
||||
|
||||
#include "gdkiccprofile.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdktexture.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdktexture.h"
|
||||
|
||||
#include "gdkprofilerprivate.h"
|
||||
|
||||
@@ -173,9 +174,12 @@ gdk_load_jpeg (GBytes *input_bytes,
|
||||
guint width, height, stride;
|
||||
unsigned char *data;
|
||||
unsigned char *row[1];
|
||||
JOCTET *icc_data;
|
||||
unsigned int icc_len;
|
||||
GBytes *bytes;
|
||||
GdkTexture *texture;
|
||||
GdkMemoryFormat format;
|
||||
GdkColorProfile *color_profile;
|
||||
G_GNUC_UNUSED guint64 before = GDK_PROFILER_CURRENT_TIME;
|
||||
|
||||
info.err = jpeg_std_error (&jerr.pub);
|
||||
@@ -195,6 +199,9 @@ gdk_load_jpeg (GBytes *input_bytes,
|
||||
g_bytes_get_data (input_bytes, NULL),
|
||||
g_bytes_get_size (input_bytes));
|
||||
|
||||
/* save color profile */
|
||||
jpeg_save_markers (&info, JPEG_APP0 + 2, 0xFFFF);
|
||||
|
||||
jpeg_read_header (&info, TRUE);
|
||||
jpeg_start_decompress (&info);
|
||||
|
||||
@@ -252,14 +259,29 @@ gdk_load_jpeg (GBytes *input_bytes,
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
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_profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (icc_bytes, error));
|
||||
g_bytes_unref (icc_bytes);
|
||||
}
|
||||
else
|
||||
color_profile = g_object_ref (gdk_color_profile_get_srgb ());
|
||||
|
||||
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);
|
||||
if (color_profile)
|
||||
{
|
||||
texture = gdk_memory_texture_new_with_color_profile (width, height,
|
||||
format,
|
||||
color_profile,
|
||||
bytes, stride);
|
||||
}
|
||||
else
|
||||
texture = NULL;
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
@@ -279,9 +301,12 @@ gdk_save_jpeg (GdkTexture *texture)
|
||||
guchar *input = NULL;
|
||||
guchar *row;
|
||||
int width, height, stride;
|
||||
GdkColorProfile *color_profile;
|
||||
GBytes *bytes;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
color_profile = gdk_texture_get_color_profile (texture);
|
||||
|
||||
info.err = jpeg_std_error (&jerr.pub);
|
||||
jerr.pub.error_exit = fatal_error_handler;
|
||||
@@ -315,6 +340,12 @@ gdk_save_jpeg (GdkTexture *texture)
|
||||
|
||||
jpeg_start_compress (&info, TRUE);
|
||||
|
||||
bytes = gdk_icc_profile_get_icc_profile (GDK_ICC_PROFILE (color_profile));
|
||||
jpeg_write_icc_profile (&info,
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes));
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
while (info.next_scanline < info.image_height)
|
||||
{
|
||||
row = &input[info.next_scanline * stride];
|
||||
|
||||
@@ -19,12 +19,15 @@
|
||||
|
||||
#include "gdkpngprivate.h"
|
||||
|
||||
#include "gdkiccprofileprivate.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdkprofilerprivate.h"
|
||||
#include "gdktexture.h"
|
||||
#include "gdktextureprivate.h"
|
||||
#include "gsk/ngl/fp16private.h"
|
||||
|
||||
#include <png.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -126,169 +129,101 @@ png_simple_warning_callback (png_structp png,
|
||||
{
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Format conversion */
|
||||
|
||||
static void
|
||||
unpremultiply (guchar *data,
|
||||
int width,
|
||||
int height)
|
||||
static GdkColorProfile *
|
||||
gdk_png_get_color_profile (png_struct *png,
|
||||
png_info *info)
|
||||
{
|
||||
gsize x, y;
|
||||
GdkColorProfile *profile;
|
||||
guchar *icc_data;
|
||||
png_uint_32 icc_len;
|
||||
char *name;
|
||||
double gamma;
|
||||
cmsCIExyY whitepoint;
|
||||
cmsCIExyYTRIPLE primaries;
|
||||
cmsToneCurve *curve;
|
||||
cmsHPROFILE lcms_profile;
|
||||
int intent;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
if (png_get_iCCP (png, info, &name, NULL, &icc_data, &icc_len))
|
||||
{
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
guchar *b = &data[x * 4];
|
||||
guint32 pixel;
|
||||
guchar alpha;
|
||||
GBytes *bytes = g_bytes_new (icc_data, icc_len);
|
||||
|
||||
memcpy (&pixel, b, sizeof (guint32));
|
||||
alpha = (pixel & 0xff000000) >> 24;
|
||||
if (alpha == 0)
|
||||
{
|
||||
b[0] = 0;
|
||||
b[1] = 0;
|
||||
b[2] = 0;
|
||||
b[3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
b[0] = (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
|
||||
b[1] = (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
|
||||
b[2] = (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
|
||||
b[3] = alpha;
|
||||
}
|
||||
}
|
||||
data += width * 4;
|
||||
profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (bytes, NULL));
|
||||
g_bytes_unref (bytes);
|
||||
if (profile)
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unpremultiply_float_to_16bit (guchar *data,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
gsize x, y;
|
||||
float *src = (float *)data;;
|
||||
guint16 *dest = (guint16 *)data;
|
||||
if (png_get_sRGB (png, info, &intent))
|
||||
return g_object_ref (gdk_color_profile_get_srgb ());
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
/* 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 g_object_ref (gdk_color_profile_get_srgb ());
|
||||
|
||||
if (!png_get_gAMA (png, info, &gamma))
|
||||
gamma = 2.4;
|
||||
|
||||
if (!png_get_cHRM (png, info,
|
||||
&whitepoint.x, &whitepoint.y,
|
||||
&primaries.Red.x, &primaries.Red.y,
|
||||
&primaries.Green.x, &primaries.Green.y,
|
||||
&primaries.Blue.x, &primaries.Blue.y))
|
||||
{
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
float r, g, b, a;
|
||||
if (gamma == 2.4)
|
||||
return g_object_ref (gdk_color_profile_get_srgb ());
|
||||
|
||||
r = src[0];
|
||||
g = src[1];
|
||||
b = src[2];
|
||||
a = src[3];
|
||||
if (a == 0)
|
||||
{
|
||||
dest[0] = 0;
|
||||
dest[1] = 0;
|
||||
dest[2] = 0;
|
||||
dest[3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[0] = (guint16) CLAMP (65536.f * r / a, 0.f, 65535.f);
|
||||
dest[1] = (guint16) CLAMP (65536.f * g / a, 0.f, 65535.f);
|
||||
dest[2] = (guint16) CLAMP (65536.f * b / a, 0.f, 65535.f);
|
||||
dest[3] = (guint16) CLAMP (65536.f * a, 0.f, 65535.f);
|
||||
}
|
||||
|
||||
dest += 4;
|
||||
src += 4;
|
||||
}
|
||||
whitepoint = (cmsCIExyY) { 0.3127, 0.3290, 1.0 };
|
||||
primaries = (cmsCIExyYTRIPLE) {
|
||||
{ 0.6400, 0.3300, 1.0 },
|
||||
{ 0.3000, 0.6000, 1.0 },
|
||||
{ 0.1500, 0.0600, 1.0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
multiply_alpha (int alpha, int color)
|
||||
{
|
||||
int temp = (alpha * color) + 0x80;
|
||||
return ((temp + (temp >> 8)) >> 8);
|
||||
}
|
||||
|
||||
static void
|
||||
premultiply_data (png_structp png,
|
||||
png_row_infop row_info,
|
||||
png_bytep data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < row_info->rowbytes; i += 4)
|
||||
else
|
||||
{
|
||||
uint8_t *base = &data[i];
|
||||
uint8_t alpha = base[3];
|
||||
uint32_t p;
|
||||
|
||||
if (alpha == 0)
|
||||
{
|
||||
p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t red = base[0];
|
||||
uint8_t green = base[1];
|
||||
uint8_t blue = base[2];
|
||||
|
||||
if (alpha != 0xff)
|
||||
{
|
||||
red = multiply_alpha (alpha, red);
|
||||
green = multiply_alpha (alpha, green);
|
||||
blue = multiply_alpha (alpha, blue);
|
||||
}
|
||||
p = ((uint32_t)alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
|
||||
}
|
||||
memcpy (base, &p, sizeof (uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
convert_bytes_to_data (png_structp png,
|
||||
png_row_infop row_info,
|
||||
png_bytep data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < row_info->rowbytes; i += 4)
|
||||
{
|
||||
uint8_t *base = &data[i];
|
||||
uint8_t red = base[0];
|
||||
uint8_t green = base[1];
|
||||
uint8_t blue = base[2];
|
||||
uint32_t pixel;
|
||||
|
||||
pixel = (0xffu << 24) | (red << 16) | (green << 8) | (blue << 0);
|
||||
memcpy (base, &pixel, sizeof (uint32_t));
|
||||
primaries.Red.Y = 1.0;
|
||||
primaries.Green.Y = 1.0;
|
||||
primaries.Blue.Y = 1.0;
|
||||
}
|
||||
|
||||
curve = cmsBuildGamma (NULL, 1.0 / gamma);
|
||||
lcms_profile = cmsCreateRGBProfile (&whitepoint,
|
||||
&primaries,
|
||||
(cmsToneCurve*[3]) { curve, curve, curve });
|
||||
profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_lcms_profile (lcms_profile, NULL));
|
||||
/* FIXME: errors? */
|
||||
if (profile == NULL)
|
||||
profile = g_object_ref (gdk_color_profile_get_srgb ());
|
||||
cmsFreeToneCurve (curve);
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
static void
|
||||
premultiply_16bit (guchar *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride)
|
||||
gdk_png_set_icc_profile (png_struct *png,
|
||||
png_info *info,
|
||||
GdkICCProfile *profile)
|
||||
{
|
||||
gsize x, y;
|
||||
guint16 *src;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
/* FIXME: allow deconstructing RGB profiles into gAMA and cHRM instead of
|
||||
* falling back to iCCP
|
||||
*/
|
||||
if (profile == gdk_color_profile_get_srgb ())
|
||||
{
|
||||
src = (guint16 *)data;
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
float alpha = src[x * 4 + 3] / 65535.f;
|
||||
src[x * 4 ] = (guint16) CLAMP (src[x * 4 ] * alpha, 0.f, 65535.f);
|
||||
src[x * 4 + 1] = (guint16) CLAMP (src[x * 4 + 1] * alpha, 0.f, 65535.f);
|
||||
src[x * 4 + 2] = (guint16) CLAMP (src[x * 4 + 2] * alpha, 0.f, 65535.f);
|
||||
}
|
||||
|
||||
data += stride;
|
||||
png_set_sRGB_gAMA_and_cHRM (png, info, /* FIXME */ PNG_sRGB_INTENT_PERCEPTUAL);
|
||||
}
|
||||
else if (GDK_IS_ICC_PROFILE (profile))
|
||||
{
|
||||
GBytes *bytes = gdk_icc_profile_get_icc_profile (profile);
|
||||
png_set_iCCP (png, info,
|
||||
"ICC profile",
|
||||
0,
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes));
|
||||
}
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
@@ -308,6 +243,7 @@ gdk_load_png (GBytes *bytes,
|
||||
guchar *buffer = NULL;
|
||||
guchar **row_pointers = NULL;
|
||||
GBytes *out_bytes;
|
||||
GdkColorProfile *color_profile;
|
||||
GdkTexture *texture;
|
||||
int bpp;
|
||||
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
|
||||
@@ -354,9 +290,6 @@ gdk_load_png (GBytes *bytes,
|
||||
if (png_get_valid (png, info, PNG_INFO_tRNS))
|
||||
png_set_tRNS_to_alpha (png);
|
||||
|
||||
if (depth == 8)
|
||||
png_set_filler (png, 0xff, PNG_FILLER_AFTER);
|
||||
|
||||
if (depth < 8)
|
||||
png_set_packing (png);
|
||||
|
||||
@@ -367,18 +300,20 @@ gdk_load_png (GBytes *bytes,
|
||||
if (interlace != PNG_INTERLACE_NONE)
|
||||
png_set_interlace_handling (png);
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
png_set_swap (png);
|
||||
#endif
|
||||
|
||||
png_read_update_info (png, info);
|
||||
png_get_IHDR (png, info,
|
||||
&width, &height, &depth,
|
||||
&color_type, &interlace, NULL, NULL);
|
||||
if ((depth != 8 && depth != 16) ||
|
||||
!(color_type == PNG_COLOR_TYPE_RGB ||
|
||||
color_type == PNG_COLOR_TYPE_RGB_ALPHA))
|
||||
if (depth != 8 && depth != 16)
|
||||
{
|
||||
png_destroy_read_struct (&png, &info, NULL);
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
_("Failed to parse png image"));
|
||||
_("Unsupported depth %u in png image"), depth);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -387,35 +322,41 @@ gdk_load_png (GBytes *bytes,
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
if (depth == 8)
|
||||
{
|
||||
format = GDK_MEMORY_DEFAULT;
|
||||
png_set_read_user_transform_fn (png, premultiply_data);
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_A8B8G8R8;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
png_set_swap (png);
|
||||
#endif
|
||||
format = GDK_MEMORY_R16G16B16A16;
|
||||
}
|
||||
break;
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
if (depth == 8)
|
||||
{
|
||||
format = GDK_MEMORY_DEFAULT;
|
||||
png_set_read_user_transform_fn (png, convert_bytes_to_data);
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_B8G8R8;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
else if (depth == 16)
|
||||
{
|
||||
format = GDK_MEMORY_R16G16B16;
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
png_set_swap (png);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
png_destroy_read_struct (&png, &info, NULL);
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
_("Unsupportd color type %u in png image"), color_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
color_profile = gdk_png_get_color_profile (png, info);
|
||||
|
||||
bpp = gdk_memory_format_bytes_per_pixel (format);
|
||||
stride = width * bpp;
|
||||
if (stride % 8)
|
||||
@@ -426,6 +367,7 @@ gdk_load_png (GBytes *bytes,
|
||||
|
||||
if (!buffer || !row_pointers)
|
||||
{
|
||||
g_object_unref (color_profile);
|
||||
g_free (buffer);
|
||||
g_free (row_pointers);
|
||||
png_destroy_read_struct (&png, &info, NULL);
|
||||
@@ -441,12 +383,13 @@ gdk_load_png (GBytes *bytes,
|
||||
png_read_image (png, row_pointers);
|
||||
png_read_end (png, info);
|
||||
|
||||
if (format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED)
|
||||
premultiply_16bit (buffer, width, height, stride);
|
||||
|
||||
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_profile (width, height,
|
||||
format,
|
||||
color_profile,
|
||||
out_bytes, stride);
|
||||
g_bytes_unref (out_bytes);
|
||||
g_object_unref (color_profile);
|
||||
|
||||
g_free (row_pointers);
|
||||
png_destroy_read_struct (&png, &info, NULL);
|
||||
@@ -467,20 +410,22 @@ gdk_save_png (GdkTexture *texture)
|
||||
png_struct *png = NULL;
|
||||
png_info *info;
|
||||
png_io io = { NULL, 0, 0 };
|
||||
guint width, height, stride;
|
||||
guchar *data = NULL;
|
||||
guchar *row;
|
||||
int width, height;
|
||||
gsize stride;
|
||||
const guchar *data;
|
||||
int y;
|
||||
GdkTexture *mtexture;
|
||||
GdkMemoryTexture *memtex;
|
||||
GdkMemoryFormat format;
|
||||
GdkColorProfile *color_profile;
|
||||
int png_format;
|
||||
int depth;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
color_profile = GDK_ICC_PROFILE (gdk_texture_get_color_profile (texture));
|
||||
|
||||
mtexture = gdk_texture_download_texture (texture);
|
||||
format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (mtexture));
|
||||
memtex = GDK_MEMORY_TEXTURE (gdk_texture_download_texture (texture));
|
||||
format = gdk_memory_texture_get_format (memtex);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
@@ -491,29 +436,42 @@ gdk_save_png (GdkTexture *texture)
|
||||
case GDK_MEMORY_A8R8G8B8:
|
||||
case GDK_MEMORY_R8G8B8A8:
|
||||
case GDK_MEMORY_A8B8G8R8:
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
stride = width * 4;
|
||||
data = g_malloc_n (stride, height);
|
||||
gdk_texture_download (mtexture, data, stride);
|
||||
unpremultiply (data, width, height);
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_A8B8G8R8;
|
||||
#endif
|
||||
png_format = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
depth = 8;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_R16G16B16:
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
data = g_malloc_n (width * 16, height);
|
||||
gdk_texture_download_float (mtexture, (float *)data, width * 4);
|
||||
unpremultiply_float_to_16bit (data, width, height);
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_B8G8R8;
|
||||
#endif
|
||||
png_format = PNG_COLOR_TYPE_RGB;
|
||||
depth = 8;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_R16G16B16A16:
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
format = GDK_MEMORY_R16G16B16A16;
|
||||
png_format = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
stride = width * 8;
|
||||
depth = 16;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_R16G16B16:
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
format = GDK_MEMORY_R16G16B16;
|
||||
png_format = PNG_COLOR_TYPE_RGB;
|
||||
depth = 16;
|
||||
break;
|
||||
|
||||
@@ -540,12 +498,14 @@ gdk_save_png (GdkTexture *texture)
|
||||
|
||||
if (sigsetjmp (png_jmpbuf (png), 1))
|
||||
{
|
||||
g_free (data);
|
||||
g_object_unref (memtex);
|
||||
g_free (io.data);
|
||||
png_destroy_read_struct (&png, &info, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memtex = gdk_memory_texture_convert (memtex, format, color_profile, NULL);
|
||||
|
||||
png_set_write_fn (png, &io, png_write_func, png_flush_func);
|
||||
|
||||
png_set_IHDR (png, info, width, height, depth,
|
||||
@@ -554,20 +514,24 @@ gdk_save_png (GdkTexture *texture)
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
gdk_png_set_icc_profile (png, info, GDK_ICC_PROFILE (color_profile));
|
||||
|
||||
png_write_info (png, info);
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
png_set_swap (png);
|
||||
#endif
|
||||
|
||||
for (y = 0, row = data; y < height; y++, row += stride)
|
||||
png_write_rows (png, &row, 1);
|
||||
data = gdk_memory_texture_get_data (memtex);
|
||||
stride = gdk_memory_texture_get_stride (memtex);
|
||||
for (y = 0; y < height; y++)
|
||||
png_write_row (png, data + y * stride);
|
||||
|
||||
png_write_end (png, info);
|
||||
|
||||
png_destroy_write_struct (&png, &info);
|
||||
|
||||
g_free (data);
|
||||
g_object_unref (memtex);
|
||||
|
||||
return g_bytes_new_take (io.data, io.size);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
#include "gdktiffprivate.h"
|
||||
|
||||
#include "gdkiccprofileprivate.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdkprofilerprivate.h"
|
||||
#include "gdktexture.h"
|
||||
@@ -243,6 +245,44 @@ flip_02 (guchar *data,
|
||||
}
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Color profile handling */
|
||||
|
||||
static GdkColorProfile *
|
||||
gdk_tiff_get_icc_profile (TIFF *tiff)
|
||||
{
|
||||
const char *icc_data;
|
||||
guint icc_len;
|
||||
|
||||
if (TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_len, &icc_data))
|
||||
{
|
||||
GBytes *icc_bytes;
|
||||
GdkColorProfile *profile;
|
||||
|
||||
icc_bytes = g_bytes_new (icc_data, icc_len);
|
||||
profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (icc_bytes, NULL));
|
||||
g_bytes_unref (icc_bytes);
|
||||
|
||||
if (profile)
|
||||
return profile;
|
||||
}
|
||||
|
||||
return g_object_ref (gdk_color_profile_get_srgb ());
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_tiff_set_icc_profile (TIFF *tiff,
|
||||
GdkICCProfile *profile)
|
||||
{
|
||||
GBytes *bytes = gdk_icc_profile_get_icc_profile (profile);
|
||||
|
||||
TIFFSetField (tiff, TIFFTAG_ICCPROFILE,
|
||||
g_bytes_get_size (bytes),
|
||||
g_bytes_get_data (bytes, NULL));
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Public API */
|
||||
|
||||
@@ -276,11 +316,13 @@ gdk_save_tiff (GdkTexture *texture)
|
||||
GBytes *result = NULL;
|
||||
GdkTexture *memory_texture;
|
||||
GdkMemoryFormat format;
|
||||
GdkICCProfile *icc_profile;
|
||||
|
||||
tif = tiff_open_write (&result);
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
icc_profile = GDK_ICC_PROFILE (gdk_texture_get_color_profile (texture));
|
||||
|
||||
memory_texture = gdk_texture_download_texture (texture);
|
||||
format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (memory_texture));
|
||||
@@ -323,7 +365,8 @@ gdk_save_tiff (GdkTexture *texture)
|
||||
TIFFSetField (tif, TIFFTAG_SAMPLEFORMAT, sample_format);
|
||||
TIFFSetField (tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
||||
TIFFSetField (tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
|
||||
// TODO: save gamma / colorspace
|
||||
|
||||
gdk_tiff_set_icc_profile (tif, icc_profile);
|
||||
|
||||
if (samples_per_pixel > 3)
|
||||
{
|
||||
@@ -360,12 +403,13 @@ gdk_save_tiff (GdkTexture *texture)
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
load_fallback (TIFF *tif,
|
||||
GError **error)
|
||||
load_fallback (TIFF *tif,
|
||||
GError **error)
|
||||
{
|
||||
int width, height;
|
||||
guchar *data;
|
||||
GBytes *bytes;
|
||||
GdkColorProfile *profile;
|
||||
GdkTexture *texture;
|
||||
|
||||
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width);
|
||||
@@ -382,14 +426,18 @@ load_fallback (TIFF *tif,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
profile = gdk_tiff_get_icc_profile (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_profile (width, height,
|
||||
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
||||
profile,
|
||||
bytes,
|
||||
width * 4);
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
g_object_unref (profile);
|
||||
|
||||
return texture;
|
||||
}
|
||||
@@ -411,6 +459,7 @@ gdk_load_tiff (GBytes *input_bytes,
|
||||
gsize stride;
|
||||
int bpp;
|
||||
GBytes *bytes;
|
||||
GdkColorProfile *profile;
|
||||
GdkTexture *texture;
|
||||
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
|
||||
|
||||
@@ -497,14 +546,18 @@ gdk_load_tiff (GBytes *input_bytes,
|
||||
line += stride;
|
||||
}
|
||||
|
||||
profile = gdk_tiff_get_icc_profile (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_profile (width, height,
|
||||
format, profile,
|
||||
bytes, width * bpp);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
g_object_unref (profile);
|
||||
|
||||
TIFFClose (tif);
|
||||
|
||||
if (GDK_PROFILER_IS_RUNNING)
|
||||
|
||||
@@ -4,12 +4,15 @@ gdk_public_sources = files([
|
||||
'gdkcairo.c',
|
||||
'gdkcairocontext.c',
|
||||
'gdkclipboard.c',
|
||||
'gdkcolor.c',
|
||||
'gdkcolorprofile.c',
|
||||
'gdkcontentdeserializer.c',
|
||||
'gdkcontentformats.c',
|
||||
'gdkcontentprovider.c',
|
||||
'gdkcontentproviderimpl.c',
|
||||
'gdkcontentserializer.c',
|
||||
'gdkcursor.c',
|
||||
'gdkderivedprofile.c',
|
||||
'gdkdevice.c',
|
||||
'gdkdevicepad.c',
|
||||
'gdkdevicetool.c',
|
||||
@@ -28,8 +31,10 @@ gdk_public_sources = files([
|
||||
'gdkglobals.c',
|
||||
'gdkgltexture.c',
|
||||
'gdkhsla.c',
|
||||
'gdkiccprofile.c',
|
||||
'gdkkeys.c',
|
||||
'gdkkeyuni.c',
|
||||
'gdkmemoryformat.c',
|
||||
'gdkmemorytexture.c',
|
||||
'gdkmonitor.c',
|
||||
'gdkpaintable.c',
|
||||
@@ -63,12 +68,14 @@ gdk_public_headers = files([
|
||||
'gdkcairo.h',
|
||||
'gdkcairocontext.h',
|
||||
'gdkclipboard.h',
|
||||
'gdkcolorprofile.h',
|
||||
'gdkcontentdeserializer.h',
|
||||
'gdkcontentformats.h',
|
||||
'gdkcontentprovider.h',
|
||||
'gdkcontentproviderimpl.h',
|
||||
'gdkcontentserializer.h',
|
||||
'gdkcursor.h',
|
||||
'gdkderivedprofile.h',
|
||||
'gdkdevice.h',
|
||||
'gdkdevicepad.h',
|
||||
'gdkdevicetool.h',
|
||||
@@ -82,6 +89,7 @@ gdk_public_headers = files([
|
||||
'gdkframetimings.h',
|
||||
'gdkglcontext.h',
|
||||
'gdkgltexture.h',
|
||||
'gdkiccprofile.h',
|
||||
'gdkkeys.h',
|
||||
'gdkkeysyms.h',
|
||||
'gdkmemorytexture.h',
|
||||
@@ -203,6 +211,7 @@ gdk_deps = [
|
||||
fontconfig_dep,
|
||||
platform_gio_dep,
|
||||
pangocairo_dep,
|
||||
lcms2_dep,
|
||||
vulkan_dep,
|
||||
png_dep,
|
||||
tiff_dep,
|
||||
|
||||
@@ -157,6 +157,9 @@ gdk_wayland_cairo_context_begin_frame (GdkDrawContext *draw_context,
|
||||
else
|
||||
self->paint_surface = gdk_wayland_cairo_context_create_surface (self);
|
||||
|
||||
gdk_cairo_surface_set_color_profile (self->paint_surface,
|
||||
gdk_surface_get_color_profile (gdk_draw_context_get_surface (draw_context)));
|
||||
|
||||
surface_region = gdk_wayland_cairo_context_surface_get_region (self->paint_surface);
|
||||
if (surface_region)
|
||||
cairo_region_union (region, surface_region);
|
||||
|
||||
@@ -47,6 +47,7 @@ create_cairo_surface_for_surface (GdkSurface *surface,
|
||||
|
||||
cairo_surface = cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_ARGB32);
|
||||
cairo_surface_set_device_scale (cairo_surface, scale, scale);
|
||||
gdk_cairo_surface_set_color_profile (cairo_surface, gdk_surface_get_color_profile (surface));
|
||||
|
||||
return cairo_surface;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ create_cairo_surface_for_surface (GdkSurface *surface)
|
||||
gdk_surface_get_width (surface) * scale,
|
||||
gdk_surface_get_height (surface) * scale);
|
||||
cairo_surface_set_device_scale (cairo_surface, scale, scale);
|
||||
gdk_cairo_surface_set_color_profile (cairo_surface,
|
||||
gdk_surface_get_color_profile (surface));
|
||||
|
||||
return cairo_surface;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "gdkkeysprivate.h"
|
||||
#include "gdkmarshalers.h"
|
||||
#include "xsettings-client.h"
|
||||
#include "gdkiccprofileprivate.h"
|
||||
|
||||
#include "gdkcairocontext-x11.h"
|
||||
#include "gdkclipboard-x11.h"
|
||||
@@ -1403,6 +1404,71 @@ gdk_x11_display_init_leader_surface (GdkX11Display *self)
|
||||
self->leader_window_title_set = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
voidXFree (gpointer data)
|
||||
{
|
||||
XFree (data);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_display_check_color_profile (GdkX11Display *self)
|
||||
{
|
||||
GdkDisplay *display = GDK_DISPLAY (self);
|
||||
GdkX11Screen *screen;
|
||||
char *atom_name;
|
||||
Atom type;
|
||||
int result;
|
||||
int format;
|
||||
gulong nitems;
|
||||
gulong bytes_after;
|
||||
guchar *data;
|
||||
GBytes *bytes;
|
||||
|
||||
screen = self->screen;
|
||||
if (screen->screen_num > 0)
|
||||
atom_name = g_strdup_printf ("_ICC_PROFILE_%d", screen->screen_num);
|
||||
else
|
||||
atom_name = g_strdup ("_ICC_PROFILE");
|
||||
|
||||
g_clear_object (&self->color_profile);
|
||||
self->color_profile = g_object_ref (gdk_color_profile_get_srgb ());
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
|
||||
screen->xroot_window,
|
||||
gdk_x11_get_xatom_by_name_for_display (display, atom_name),
|
||||
0, G_MAXLONG, False, XA_CARDINAL, &type,
|
||||
&format, &nitems,
|
||||
&bytes_after, &data);
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
|
||||
g_free (atom_name);
|
||||
|
||||
if (result != Success || type != XA_CARDINAL || nitems <= 0)
|
||||
return;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 8:
|
||||
bytes = g_bytes_new_with_free_func (data, nitems, voidXFree, data);
|
||||
break;
|
||||
case 16:
|
||||
bytes = g_bytes_new_with_free_func (data, sizeof (short) * nitems, voidXFree, data);
|
||||
break;
|
||||
case 32:
|
||||
bytes = g_bytes_new_with_free_func (data, sizeof (long) * nitems, voidXFree, data);
|
||||
break;
|
||||
default:
|
||||
XFree (data);
|
||||
return;
|
||||
}
|
||||
|
||||
g_clear_object (&self->color_profile);
|
||||
self->color_profile = GDK_COLOR_PROFILE (gdk_icc_profile_new_from_icc_bytes (bytes, NULL));
|
||||
if (!self->color_profile)
|
||||
self->color_profile = g_object_ref (gdk_color_profile_get_srgb ());
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_x11_display_open:
|
||||
* @display_name: (nullable): name of the X display.
|
||||
@@ -1470,6 +1536,9 @@ gdk_x11_display_open (const char *display_name)
|
||||
/* initialize the display's screens */
|
||||
display_x11->screen = _gdk_x11_screen_new (display, DefaultScreen (display_x11->xdisplay));
|
||||
|
||||
/* We want this for the leader surface already */
|
||||
gdk_x11_display_check_color_profile (display_x11);
|
||||
|
||||
/* If GL is available we want to pick better default/rgba visuals,
|
||||
* as we care about GLX details such as alpha/depth/stencil depth,
|
||||
* stereo and double buffering
|
||||
@@ -1915,15 +1984,17 @@ gdk_x11_display_ungrab (GdkDisplay *display)
|
||||
static void
|
||||
gdk_x11_display_dispose (GObject *object)
|
||||
{
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (object);
|
||||
GdkX11Display *self = GDK_X11_DISPLAY (object);
|
||||
|
||||
if (display_x11->event_source)
|
||||
if (self->event_source)
|
||||
{
|
||||
g_source_destroy (display_x11->event_source);
|
||||
g_source_unref (display_x11->event_source);
|
||||
display_x11->event_source = NULL;
|
||||
g_source_destroy (self->event_source);
|
||||
g_source_unref (self->event_source);
|
||||
self->event_source = NULL;
|
||||
}
|
||||
|
||||
g_clear_object (&self->color_profile);
|
||||
|
||||
G_OBJECT_CLASS (gdk_x11_display_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@ struct _GdkX11Display
|
||||
guint have_damage;
|
||||
#endif
|
||||
|
||||
/* Stored in the ICC_PROFILE rootwindow prop */
|
||||
GdkColorProfile *color_profile;
|
||||
|
||||
/* If GL is not supported, store the error here */
|
||||
GError *gl_error;
|
||||
|
||||
|
||||
@@ -1011,6 +1011,8 @@ setup_toplevel_window (GdkSurface *surface,
|
||||
|
||||
/* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
|
||||
XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
|
||||
|
||||
gdk_surface_set_color_profile (surface, GDK_X11_DISPLAY (display)->color_profile);
|
||||
|
||||
if (!gdk_running_in_sandbox ())
|
||||
{
|
||||
@@ -3175,7 +3177,7 @@ gdk_surface_update_icon (GdkSurface *surface,
|
||||
|
||||
toplevel->icon_pixmap = gdk_x11_surface_create_pixmap_surface (surface, width, height);
|
||||
|
||||
cairo_surface = gdk_texture_download_surface (best_icon);
|
||||
cairo_surface = gdk_texture_download_surface (best_icon, NULL);
|
||||
|
||||
cr = cairo_create (toplevel->icon_pixmap);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
|
||||
@@ -449,7 +449,7 @@ get_colorized_texture (GdkTexture *texture,
|
||||
const graphene_matrix_t *color_matrix,
|
||||
const graphene_vec4_t *color_offset)
|
||||
{
|
||||
cairo_surface_t *surface = gdk_texture_download_surface (texture);
|
||||
cairo_surface_t *surface = gdk_texture_download_surface (texture, NULL);
|
||||
cairo_surface_t *image_surface;
|
||||
graphene_vec4_t pixel;
|
||||
guint32* pixel_data;
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskrendererprivate.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
#include "gdk/gdkcolorprofileprivate.h"
|
||||
#include "gdk/gdkmemorytextureprivate.h"
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
@@ -40,6 +43,7 @@ struct _GskCairoRenderer
|
||||
|
||||
GdkCairoContext *cairo_context;
|
||||
|
||||
gboolean color_managed;
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
ProfileTimers profile_timers;
|
||||
#endif
|
||||
@@ -77,8 +81,8 @@ gsk_cairo_renderer_do_render (GskRenderer *renderer,
|
||||
cairo_t *cr,
|
||||
GskRenderNode *root)
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
GskProfiler *profiler;
|
||||
gint64 cpu_time;
|
||||
#endif
|
||||
@@ -103,11 +107,15 @@ gsk_cairo_renderer_render_texture (GskRenderer *renderer,
|
||||
GskRenderNode *root,
|
||||
const graphene_rect_t *viewport)
|
||||
{
|
||||
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
|
||||
GdkTexture *texture;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (viewport->size.width), ceil (viewport->size.height));
|
||||
if (self->color_managed)
|
||||
gdk_cairo_surface_set_color_profile (surface, gdk_color_profile_get_srgb_linear ());
|
||||
|
||||
cr = cairo_create (surface);
|
||||
|
||||
cairo_translate (cr, - viewport->origin.x, - viewport->origin.y);
|
||||
@@ -152,7 +160,65 @@ gsk_cairo_renderer_render (GskRenderer *renderer,
|
||||
}
|
||||
#endif
|
||||
|
||||
gsk_cairo_renderer_do_render (renderer, cr, root);
|
||||
if (!self->color_managed ||
|
||||
gdk_color_profile_is_linear (gdk_cairo_get_color_profile (cr)))
|
||||
{
|
||||
gsk_cairo_renderer_do_render (renderer, cr, root);
|
||||
}
|
||||
else
|
||||
{
|
||||
GdkSurface *surface = gsk_renderer_get_surface (renderer);
|
||||
GdkColorProfile *target_profile = gdk_cairo_get_color_profile (cr);
|
||||
cairo_surface_t *cairo_surface;
|
||||
cairo_t *cr2;
|
||||
GdkTexture *color_correct;
|
||||
const cairo_region_t *frame_region;
|
||||
cairo_rectangle_int_t extents;
|
||||
guint i, n;
|
||||
|
||||
frame_region = gdk_draw_context_get_frame_region (GDK_DRAW_CONTEXT (self->cairo_context));
|
||||
cairo_region_get_extents (frame_region, &extents);
|
||||
/* We can't use cairo_push_group() here, because we'd lose the
|
||||
* color profile information. */
|
||||
cairo_surface = gdk_surface_create_similar_surface (surface,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
extents.width,
|
||||
extents.height);
|
||||
gdk_cairo_surface_set_color_profile (cairo_surface,
|
||||
gdk_color_profile_get_srgb_linear ());
|
||||
|
||||
cr2 = cairo_create (cairo_surface);
|
||||
cairo_translate (cr2, -extents.x, -extents.y);
|
||||
gdk_cairo_region (cr2, frame_region);
|
||||
cairo_clip (cr2);
|
||||
gsk_cairo_renderer_do_render (renderer, cr2, root);
|
||||
cairo_destroy (cr2);
|
||||
|
||||
color_correct = gdk_texture_new_for_surface (cairo_surface);
|
||||
cairo_surface_destroy (cairo_surface);
|
||||
n = cairo_region_num_rectangles (frame_region);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
GdkMemoryTexture *sub;
|
||||
|
||||
cairo_region_get_rectangle (frame_region, i, &rect);
|
||||
rect.x -= extents.x;
|
||||
rect.y -= extents.y;
|
||||
|
||||
sub = gdk_memory_texture_convert (g_object_ref (GDK_MEMORY_TEXTURE (color_correct)),
|
||||
GDK_MEMORY_DEFAULT,
|
||||
target_profile,
|
||||
&rect);
|
||||
cairo_surface = gdk_texture_download_surface (GDK_TEXTURE (sub), target_profile);
|
||||
cairo_set_source_surface (cr, cairo_surface, rect.x + extents.x, rect.y + extents.y);
|
||||
cairo_paint (cr);
|
||||
cairo_surface_destroy (cairo_surface);
|
||||
g_object_unref (sub);
|
||||
}
|
||||
g_object_unref (color_correct);
|
||||
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
@@ -173,6 +239,8 @@ gsk_cairo_renderer_class_init (GskCairoRendererClass *klass)
|
||||
static void
|
||||
gsk_cairo_renderer_init (GskCairoRenderer *self)
|
||||
{
|
||||
self->color_managed = TRUE;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
|
||||
|
||||
|
||||
@@ -725,3 +725,8 @@ gsk_value_dup_render_node (const GValue *value)
|
||||
return gsk_render_node_ref (value->data[0].v_pointer);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_render_node_is_hdr (const GskRenderNode *node)
|
||||
{
|
||||
return node->is_hdr;
|
||||
}
|
||||
|
||||
@@ -27,11 +27,20 @@
|
||||
#include "gskroundedrectprivate.h"
|
||||
#include "gsktransformprivate.h"
|
||||
|
||||
#include "gdk/gdkcolorprivate.h"
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
#include "gdk/gdk-private.h"
|
||||
|
||||
#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
|
||||
|
||||
|
||||
static inline void
|
||||
gsk_cairo_rectangle (cairo_t *cr,
|
||||
const graphene_rect_t *rect)
|
||||
@@ -179,6 +188,7 @@ gsk_linear_gradient_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskLinearGradientNode *self = (GskLinearGradientNode *) node;
|
||||
GdkColorProfile *profile;
|
||||
cairo_pattern_t *pattern;
|
||||
gsize i;
|
||||
|
||||
@@ -188,14 +198,20 @@ gsk_linear_gradient_node_draw (GskRenderNode *node,
|
||||
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
|
||||
|
||||
profile = gdk_cairo_get_color_profile (cr);
|
||||
for (i = 0; i < self->n_stops; i++)
|
||||
{
|
||||
GdkColor color;
|
||||
const float *components;
|
||||
gdk_color_convert_rgba (&color, profile, &self->stops[i].color);
|
||||
components = gdk_color_get_components (&color);
|
||||
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,
|
||||
self->stops[i].color.alpha);
|
||||
components[0],
|
||||
components[1],
|
||||
components[2],
|
||||
gdk_color_get_alpha (&color));
|
||||
gdk_color_finish (&color);
|
||||
}
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
@@ -812,11 +828,17 @@ gsk_conic_gradient_node_finalize (GskRenderNode *node)
|
||||
#define DEG_TO_RAD(x) ((x) * (G_PI / 180.f))
|
||||
|
||||
static void
|
||||
_cairo_mesh_pattern_set_corner_rgba (cairo_pattern_t *pattern,
|
||||
guint corner_num,
|
||||
const GdkRGBA *rgba)
|
||||
_cairo_mesh_pattern_set_corner_color (cairo_pattern_t *pattern,
|
||||
guint corner_num,
|
||||
const GdkColor *color)
|
||||
{
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, corner_num, rgba->red, rgba->green, rgba->blue, rgba->alpha);
|
||||
const float *components = gdk_color_get_components (color);
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern,
|
||||
corner_num,
|
||||
components[0],
|
||||
components[1],
|
||||
components[2],
|
||||
gdk_color_get_alpha (color));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -845,9 +867,9 @@ static void
|
||||
gsk_conic_gradient_node_add_patch (cairo_pattern_t *pattern,
|
||||
float radius,
|
||||
float start_angle,
|
||||
const GdkRGBA *start_color,
|
||||
const GdkColor *start_color,
|
||||
float end_angle,
|
||||
const GdkRGBA *end_color)
|
||||
const GdkColor *end_color)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
@@ -860,46 +882,26 @@ gsk_conic_gradient_node_add_patch (cairo_pattern_t *pattern,
|
||||
cairo_mesh_pattern_line_to (pattern, x, y);
|
||||
cairo_mesh_pattern_line_to (pattern, 0, 0);
|
||||
|
||||
_cairo_mesh_pattern_set_corner_rgba (pattern, 0, start_color);
|
||||
_cairo_mesh_pattern_set_corner_rgba (pattern, 1, start_color);
|
||||
_cairo_mesh_pattern_set_corner_rgba (pattern, 2, end_color);
|
||||
_cairo_mesh_pattern_set_corner_rgba (pattern, 3, end_color);
|
||||
_cairo_mesh_pattern_set_corner_color (pattern, 0, start_color);
|
||||
_cairo_mesh_pattern_set_corner_color (pattern, 1, start_color);
|
||||
_cairo_mesh_pattern_set_corner_color (pattern, 2, end_color);
|
||||
_cairo_mesh_pattern_set_corner_color (pattern, 3, end_color);
|
||||
|
||||
cairo_mesh_pattern_end_patch (pattern);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_rgba_color_interpolate (GdkRGBA *dest,
|
||||
const GdkRGBA *src1,
|
||||
const GdkRGBA *src2,
|
||||
double progress)
|
||||
{
|
||||
double alpha = src1->alpha * (1.0 - progress) + src2->alpha * progress;
|
||||
|
||||
dest->alpha = alpha;
|
||||
if (alpha == 0)
|
||||
{
|
||||
dest->red = src1->red * (1.0 - progress) + src2->red * progress;
|
||||
dest->green = src1->green * (1.0 - progress) + src2->green * progress;
|
||||
dest->blue = src1->blue * (1.0 - progress) + src2->blue * progress;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->red = (src1->red * src1->alpha * (1.0 - progress) + src2->red * src2->alpha * progress) / alpha;
|
||||
dest->green = (src1->green * src1->alpha * (1.0 - progress) + src2->green * src2->alpha * progress) / alpha;
|
||||
dest->blue = (src1->blue * src1->alpha * (1.0 - progress) + src2->blue * src2->alpha * progress) / alpha;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_conic_gradient_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskConicGradientNode *self = (GskConicGradientNode *) node;
|
||||
GdkColorProfile *color_profile;
|
||||
cairo_pattern_t *pattern;
|
||||
graphene_point_t corner;
|
||||
float radius;
|
||||
gsize i;
|
||||
|
||||
color_profile = gdk_cairo_get_color_profile (cr);
|
||||
|
||||
pattern = cairo_pattern_create_mesh ();
|
||||
graphene_rect_get_top_right (&node->bounds, &corner);
|
||||
@@ -915,26 +917,31 @@ gsk_conic_gradient_node_draw (GskRenderNode *node,
|
||||
{
|
||||
GskColorStop *stop1 = &self->stops[MAX (i, 1) - 1];
|
||||
GskColorStop *stop2 = &self->stops[MIN (i, self->n_stops - 1)];
|
||||
GdkColor stop1_color, stop2_color;
|
||||
double offset1 = i > 0 ? stop1->offset : 0;
|
||||
double offset2 = i < self->n_stops ? stop2->offset : 1;
|
||||
double start_angle, end_angle;
|
||||
|
||||
offset1 = offset1 * 360 + self->rotation - 90;
|
||||
offset2 = offset2 * 360 + self->rotation - 90;
|
||||
gdk_color_convert_rgba (&stop1_color, color_profile, &stop1->color);
|
||||
gdk_color_convert_rgba (&stop2_color, color_profile, &stop1->color);
|
||||
|
||||
for (start_angle = offset1; start_angle < offset2; start_angle = end_angle)
|
||||
{
|
||||
GdkRGBA start_color, end_color;
|
||||
GdkColor start_color, end_color;
|
||||
end_angle = (floor (start_angle / 45) + 1) * 45;
|
||||
end_angle = MIN (end_angle, offset2);
|
||||
gdk_rgba_color_interpolate (&start_color,
|
||||
&stop1->color,
|
||||
&stop2->color,
|
||||
(start_angle - offset1) / (offset2 - offset1));
|
||||
gdk_rgba_color_interpolate (&end_color,
|
||||
&stop1->color,
|
||||
&stop2->color,
|
||||
(end_angle - offset1) / (offset2 - offset1));
|
||||
gdk_color_mix (&start_color,
|
||||
color_profile,
|
||||
&stop1_color,
|
||||
&stop2_color,
|
||||
(start_angle - offset1) / (offset2 - offset1));
|
||||
gdk_color_mix (&end_color,
|
||||
color_profile,
|
||||
&stop1_color,
|
||||
&stop2_color,
|
||||
(end_angle - offset1) / (offset2 - offset1));
|
||||
|
||||
gsk_conic_gradient_node_add_patch (pattern,
|
||||
radius,
|
||||
@@ -943,6 +950,9 @@ gsk_conic_gradient_node_draw (GskRenderNode *node,
|
||||
DEG_TO_RAD (end_angle),
|
||||
&end_color);
|
||||
}
|
||||
|
||||
gdk_color_finish (&stop2_color);
|
||||
gdk_color_finish (&stop1_color);
|
||||
}
|
||||
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
|
||||
@@ -1158,7 +1168,8 @@ struct _GskBorderNode
|
||||
|
||||
static void
|
||||
gsk_border_node_mesh_add_patch (cairo_pattern_t *pattern,
|
||||
const GdkRGBA *color,
|
||||
GdkColorProfile *color_profile,
|
||||
const GdkRGBA *rgba,
|
||||
double x0,
|
||||
double y0,
|
||||
double x1,
|
||||
@@ -1168,16 +1179,26 @@ gsk_border_node_mesh_add_patch (cairo_pattern_t *pattern,
|
||||
double x3,
|
||||
double y3)
|
||||
{
|
||||
GdkColor color;
|
||||
const float *components;
|
||||
float alpha;
|
||||
|
||||
gdk_color_convert_rgba (&color, color_profile, rgba);
|
||||
components = gdk_color_get_components (&color);
|
||||
alpha = gdk_color_get_alpha (&color);
|
||||
|
||||
cairo_mesh_pattern_begin_patch (pattern);
|
||||
cairo_mesh_pattern_move_to (pattern, x0, y0);
|
||||
cairo_mesh_pattern_line_to (pattern, x1, y1);
|
||||
cairo_mesh_pattern_line_to (pattern, x2, y2);
|
||||
cairo_mesh_pattern_line_to (pattern, x3, y3);
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, color->red, color->green, color->blue, color->alpha);
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, 1, color->red, color->green, color->blue, color->alpha);
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, color->red, color->green, color->blue, color->alpha);
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, 3, color->red, color->green, color->blue, color->alpha);
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, components[0], components[1], components[2], alpha);
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, 1, components[0], components[1], components[2], alpha);
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, components[0], components[1], components[2], alpha);
|
||||
cairo_mesh_pattern_set_corner_color_rgba (pattern, 3, components[0], components[1], components[2], alpha);
|
||||
cairo_mesh_pattern_end_patch (pattern);
|
||||
|
||||
gdk_color_finish (&color);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1222,11 +1243,13 @@ gsk_border_node_draw (GskRenderNode *node,
|
||||
* Note that the call to cairo_fill() will add the potential final
|
||||
* segment by closing the path, so we don't have to care.
|
||||
*/
|
||||
GdkColorProfile *profile;
|
||||
cairo_pattern_t *mesh;
|
||||
cairo_matrix_t mat;
|
||||
graphene_point_t tl, br;
|
||||
float scale;
|
||||
|
||||
profile = gdk_cairo_get_color_profile (cr);
|
||||
mesh = cairo_pattern_create_mesh ();
|
||||
cairo_matrix_init_translate (&mat, -bounds->origin.x, -bounds->origin.y);
|
||||
cairo_pattern_set_matrix (mesh, &mat);
|
||||
@@ -1244,6 +1267,7 @@ gsk_border_node_draw (GskRenderNode *node,
|
||||
if (self->border_width[0] > 0)
|
||||
{
|
||||
gsk_border_node_mesh_add_patch (mesh,
|
||||
profile,
|
||||
&self->border_color[0],
|
||||
0, 0,
|
||||
tl.x, tl.y,
|
||||
@@ -1255,6 +1279,7 @@ gsk_border_node_draw (GskRenderNode *node,
|
||||
if (self->border_width[1] > 0)
|
||||
{
|
||||
gsk_border_node_mesh_add_patch (mesh,
|
||||
profile,
|
||||
&self->border_color[1],
|
||||
bounds->size.width, 0,
|
||||
br.x, tl.y,
|
||||
@@ -1266,6 +1291,7 @@ gsk_border_node_draw (GskRenderNode *node,
|
||||
if (self->border_width[2] > 0)
|
||||
{
|
||||
gsk_border_node_mesh_add_patch (mesh,
|
||||
profile,
|
||||
&self->border_color[2],
|
||||
0, bounds->size.height,
|
||||
tl.x, br.y,
|
||||
@@ -1277,6 +1303,7 @@ gsk_border_node_draw (GskRenderNode *node,
|
||||
if (self->border_width[3] > 0)
|
||||
{
|
||||
gsk_border_node_mesh_add_patch (mesh,
|
||||
profile,
|
||||
&self->border_color[3],
|
||||
0, 0,
|
||||
tl.x, tl.y,
|
||||
@@ -1483,7 +1510,8 @@ gsk_texture_node_draw (GskRenderNode *node,
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
surface = gdk_texture_download_surface (self->texture);
|
||||
surface = gdk_texture_download_surface (self->texture,
|
||||
gdk_cairo_get_color_profile (cr));
|
||||
pattern = cairo_pattern_create_for_surface (surface);
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
|
||||
|
||||
@@ -1560,6 +1588,8 @@ gsk_texture_node_new (GdkTexture *texture,
|
||||
self->texture = g_object_ref (texture);
|
||||
graphene_rect_init_from_rect (&node->bounds, bounds);
|
||||
|
||||
node->is_hdr = gdk_texture_is_hdr (texture);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -2730,11 +2760,13 @@ gsk_container_node_new (GskRenderNode **children,
|
||||
|
||||
self->children[0] = gsk_render_node_ref (children[0]);
|
||||
graphene_rect_init_from_rect (&bounds, &(children[0]->bounds));
|
||||
node->is_hdr = gsk_render_node_is_hdr (children[0]);
|
||||
|
||||
for (guint i = 1; i < n_children; i++)
|
||||
{
|
||||
self->children[i] = gsk_render_node_ref (children[i]);
|
||||
graphene_rect_union (&bounds, &(children[i]->bounds), &bounds);
|
||||
node->is_hdr |= gsk_render_node_is_hdr (children[i]);
|
||||
}
|
||||
|
||||
graphene_rect_init_from_rect (&node->bounds, &bounds);
|
||||
@@ -2965,6 +2997,8 @@ gsk_transform_node_new (GskRenderNode *child,
|
||||
&child->bounds,
|
||||
&node->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -3100,6 +3134,8 @@ gsk_opacity_node_new (GskRenderNode *child,
|
||||
|
||||
graphene_rect_init_from_rect (&node->bounds, &child->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -3302,6 +3338,8 @@ gsk_color_matrix_node_new (GskRenderNode *child,
|
||||
|
||||
graphene_rect_init_from_rect (&node->bounds, &child->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -3451,6 +3489,8 @@ gsk_repeat_node_new (const graphene_rect_t *bounds,
|
||||
else
|
||||
graphene_rect_init_from_rect (&self->child_bounds, &child->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -3582,6 +3622,8 @@ gsk_clip_node_new (GskRenderNode *child,
|
||||
|
||||
graphene_rect_intersection (&self->clip, &child->bounds, &node->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -3713,6 +3755,8 @@ gsk_rounded_clip_node_new (GskRenderNode *child,
|
||||
|
||||
graphene_rect_intersection (&self->clip.bounds, &child->bounds, &node->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -3932,6 +3976,8 @@ gsk_shadow_node_new (GskRenderNode *child,
|
||||
|
||||
gsk_shadow_node_get_bounds (self, &node->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -4125,6 +4171,8 @@ gsk_blend_node_new (GskRenderNode *bottom,
|
||||
|
||||
graphene_rect_union (&bottom->bounds, &top->bounds, &node->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (bottom) || gsk_render_node_is_hdr (top);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -4273,6 +4321,8 @@ gsk_cross_fade_node_new (GskRenderNode *start,
|
||||
|
||||
graphene_rect_union (&start->bounds, &end->bounds, &node->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (start) || gsk_render_node_is_hdr (end);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -4357,12 +4407,22 @@ gsk_text_node_finalize (GskRenderNode *node)
|
||||
parent_class->finalize (node);
|
||||
}
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
|
||||
static void
|
||||
gsk_text_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
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 };
|
||||
|
||||
face = pango_fc_font_lock_face (PANGO_FC_FONT (self->font));
|
||||
FT_Face_Properties (face, 1, &property);
|
||||
#endif
|
||||
|
||||
glyphs.num_glyphs = self->num_glyphs;
|
||||
glyphs.glyphs = self->glyphs;
|
||||
@@ -4375,8 +4435,14 @@ gsk_text_node_draw (GskRenderNode *node,
|
||||
pango_cairo_show_glyph_string (cr, self->font, &glyphs);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
pango_fc_font_unlock_face (PANGO_FC_FONT (self->font));
|
||||
#endif
|
||||
}
|
||||
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
static void
|
||||
gsk_text_node_diff (GskRenderNode *node1,
|
||||
GskRenderNode *node2,
|
||||
@@ -4864,6 +4930,8 @@ gsk_blur_node_new (GskRenderNode *child,
|
||||
- clip_radius,
|
||||
- clip_radius);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -4986,6 +5054,8 @@ gsk_debug_node_new (GskRenderNode *child,
|
||||
|
||||
graphene_rect_init_from_rect (&node->bounds, &child->bounds);
|
||||
|
||||
node->is_hdr = gsk_render_node_is_hdr (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -5150,7 +5220,10 @@ gsk_gl_shader_node_new (GskGLShader *shader,
|
||||
{
|
||||
self->children = g_malloc_n (n_children, sizeof (GskRenderNode *));
|
||||
for (guint i = 0; i < n_children; i++)
|
||||
self->children[i] = gsk_render_node_ref (children[i]);
|
||||
{
|
||||
self->children[i] = gsk_render_node_ref (children[i]);
|
||||
node->is_hdr |= gsk_render_node_is_hdr (children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
|
||||
@@ -1399,7 +1399,8 @@ parse_cairo_node (GtkCssParser *parser)
|
||||
else if (pixels != NULL)
|
||||
{
|
||||
cairo_t *cr = gsk_cairo_node_get_draw_context (node);
|
||||
surface = gdk_texture_download_surface (pixels);
|
||||
surface = gdk_texture_download_surface (pixels,
|
||||
gdk_texture_get_color_profile (pixels));
|
||||
cairo_set_source_surface (cr, surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
@@ -27,6 +27,8 @@ struct _GskRenderNode
|
||||
gatomicrefcount ref_count;
|
||||
|
||||
graphene_rect_t bounds;
|
||||
|
||||
guint is_hdr : 1;
|
||||
};
|
||||
|
||||
struct _GskRenderNodeClass
|
||||
@@ -109,6 +111,7 @@ GskRenderNode ** gsk_container_node_get_children (const GskRenderNode *no
|
||||
void gsk_transform_node_get_translate (const GskRenderNode *node,
|
||||
float *dx,
|
||||
float *dy);
|
||||
gboolean gsk_render_node_is_hdr (const GskRenderNode *node);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -19,6 +19,10 @@ gsk_private_ngl_shaders = [
|
||||
'ngl/resources/repeat.glsl',
|
||||
'ngl/resources/custom.glsl',
|
||||
'ngl/resources/filled_border.glsl',
|
||||
'ngl/resources/postprocessing.glsl',
|
||||
'ngl/resources/linearize.glsl',
|
||||
'ngl/resources/premultiply.glsl',
|
||||
'ngl/resources/linearize_premultiply.glsl',
|
||||
]
|
||||
|
||||
gsk_public_sources = files([
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkcolorprofileprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gsk/gskdebugprivate.h>
|
||||
#include <gsk/gskroundedrectprivate.h>
|
||||
@@ -528,7 +530,7 @@ gsk_ngl_command_queue_begin_draw (GskNglCommandQueue *self,
|
||||
GskNglCommandBatch *batch;
|
||||
|
||||
g_assert (GSK_IS_NGL_COMMAND_QUEUE (self));
|
||||
g_assert (self->in_draw == FALSE);
|
||||
g_assert (!self->in_draw);
|
||||
g_assert (width <= G_MAXUINT16);
|
||||
g_assert (height <= G_MAXUINT16);
|
||||
|
||||
@@ -566,6 +568,7 @@ gsk_ngl_command_queue_end_draw (GskNglCommandQueue *self)
|
||||
GskNglCommandBatch *batch;
|
||||
|
||||
g_assert (GSK_IS_NGL_COMMAND_QUEUE (self));
|
||||
g_assert (self->in_draw);
|
||||
g_assert (self->batches.len > 0);
|
||||
|
||||
if (will_ignore_batch (self))
|
||||
@@ -1231,6 +1234,7 @@ gboolean
|
||||
gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self,
|
||||
int width,
|
||||
int height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
guint *out_fbo_id,
|
||||
@@ -1247,6 +1251,7 @@ gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self,
|
||||
|
||||
texture_id = gsk_ngl_command_queue_create_texture (self,
|
||||
width, height,
|
||||
format,
|
||||
min_filter, mag_filter);
|
||||
|
||||
if (texture_id == -1)
|
||||
@@ -1272,6 +1277,7 @@ int
|
||||
gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self,
|
||||
int width,
|
||||
int height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
@@ -1296,9 +1302,9 @@ gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self,
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
if (gdk_gl_context_get_use_es (self->context))
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
else
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
/* Restore the previous texture if it was set */
|
||||
if (self->attachments->textures[0].id != 0)
|
||||
@@ -1319,6 +1325,109 @@ gsk_ngl_command_queue_create_framebuffer (GskNglCommandQueue *self)
|
||||
return fbo_id;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_ngl_command_queue_do_upload_texture (GdkGLContext *context,
|
||||
GdkTexture *texture,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
guint texture_target,
|
||||
GskConversion *conversion)
|
||||
{
|
||||
GdkMemoryTexture *memory_texture;
|
||||
GdkMemoryFormat data_format;
|
||||
GdkColorProfile *data_profile;
|
||||
GLenum gl_internalformat;
|
||||
GLenum gl_format;
|
||||
GLenum gl_type;
|
||||
gsize bpp, stride;
|
||||
const guchar *data;
|
||||
gboolean convert_locally = FALSE;
|
||||
|
||||
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
||||
|
||||
memory_texture = GDK_MEMORY_TEXTURE (gdk_texture_download_texture (texture));
|
||||
data_format = gdk_memory_texture_get_format (memory_texture);
|
||||
data_profile = gdk_texture_get_color_profile (GDK_TEXTURE (memory_texture));
|
||||
|
||||
if (data_profile == gdk_color_profile_get_srgb ())
|
||||
*conversion = GSK_CONVERSION_LINEARIZE;
|
||||
else if (data_profile == gdk_color_profile_get_srgb_linear ())
|
||||
*conversion = 0;
|
||||
else
|
||||
convert_locally = TRUE;
|
||||
|
||||
if (!gdk_memory_format_gl_format (data_format,
|
||||
gdk_gl_context_get_use_es (context),
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type))
|
||||
{
|
||||
if (!gdk_gl_context_get_use_es (context))
|
||||
{
|
||||
*conversion |= GSK_CONVERSION_PREMULTIPLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
convert_locally = TRUE;
|
||||
data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
if (!gdk_memory_format_gl_format (GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
||||
gdk_gl_context_get_use_es (context),
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type))
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (convert_locally)
|
||||
{
|
||||
memory_texture = gdk_memory_texture_convert (memory_texture,
|
||||
data_format,
|
||||
gdk_color_profile_get_srgb_linear (),
|
||||
&(GdkRectangle) { x, y, width, height });
|
||||
*conversion = 0;
|
||||
}
|
||||
|
||||
bpp = gdk_memory_format_bytes_per_pixel (data_format);
|
||||
stride = gdk_memory_texture_get_stride (memory_texture);
|
||||
data = gdk_memory_texture_get_data (memory_texture);
|
||||
|
||||
/* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
|
||||
* the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
|
||||
*/
|
||||
if (stride == width * bpp)
|
||||
{
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
|
||||
}
|
||||
else if ((stride % bpp == 0) &&
|
||||
(!gdk_gl_context_get_use_es (context) ||
|
||||
gdk_gl_context_has_version (context, 3, 0) ||
|
||||
gdk_gl_context_has_unpack_subimage (context)))
|
||||
{
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
|
||||
|
||||
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
|
||||
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL);
|
||||
for (i = 0; i < height; i++)
|
||||
glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
|
||||
}
|
||||
|
||||
g_clear_object (&memory_texture);
|
||||
}
|
||||
|
||||
int
|
||||
gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self,
|
||||
GdkTexture *texture,
|
||||
@@ -1327,14 +1436,11 @@ gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self,
|
||||
guint width,
|
||||
guint height,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
int mag_filter,
|
||||
GskConversion *conversion)
|
||||
{
|
||||
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
|
||||
cairo_surface_t *surface = NULL;
|
||||
GdkMemoryFormat data_format;
|
||||
const guchar *data;
|
||||
gsize data_stride;
|
||||
gsize bpp;
|
||||
int format;
|
||||
int texture_id;
|
||||
|
||||
g_assert (GSK_IS_NGL_COMMAND_QUEUE (self));
|
||||
@@ -1344,6 +1450,8 @@ gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self,
|
||||
g_assert (min_filter == GL_LINEAR || min_filter == GL_NEAREST);
|
||||
g_assert (mag_filter == GL_LINEAR || min_filter == GL_NEAREST);
|
||||
|
||||
*conversion = 0;
|
||||
|
||||
if (width > self->max_texture_size || height > self->max_texture_size)
|
||||
{
|
||||
g_warning ("Attempt to create texture of size %ux%u but max size is %d. "
|
||||
@@ -1353,47 +1461,33 @@ gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self,
|
||||
height = MAX (height, self->max_texture_size);
|
||||
}
|
||||
|
||||
texture_id = gsk_ngl_command_queue_create_texture (self, width, height, min_filter, mag_filter);
|
||||
format = gdk_texture_is_hdr (texture) ? GL_RGBA16F : GL_RGBA8;
|
||||
|
||||
texture_id = gsk_ngl_command_queue_create_texture (self,
|
||||
width, height,
|
||||
format,
|
||||
min_filter, mag_filter);
|
||||
if (texture_id == -1)
|
||||
return texture_id;
|
||||
|
||||
if (GDK_IS_MEMORY_TEXTURE (texture))
|
||||
{
|
||||
GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (texture);
|
||||
data = gdk_memory_texture_get_data (memory_texture);
|
||||
data_format = gdk_memory_texture_get_format (memory_texture);
|
||||
data_stride = gdk_memory_texture_get_stride (memory_texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fall back to downloading to a surface */
|
||||
surface = gdk_texture_download_surface (texture);
|
||||
cairo_surface_flush (surface);
|
||||
data = cairo_image_surface_get_data (surface);
|
||||
data_format = GDK_MEMORY_DEFAULT;
|
||||
data_stride = cairo_image_surface_get_stride (surface);
|
||||
}
|
||||
|
||||
self->n_uploads++;
|
||||
|
||||
bpp = gdk_memory_format_bytes_per_pixel (data_format);
|
||||
|
||||
/* Switch to texture0 as 2D. We'll restore it later. */
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, texture_id);
|
||||
|
||||
gdk_gl_context_upload_texture (gdk_gl_context_get_current (),
|
||||
data + x_offset * bpp + y_offset * data_stride,
|
||||
width, height, data_stride,
|
||||
data_format, GL_TEXTURE_2D);
|
||||
gsk_ngl_command_queue_do_upload_texture (self->context,
|
||||
texture,
|
||||
x_offset, y_offset,
|
||||
width, height,
|
||||
GL_TEXTURE_2D,
|
||||
conversion);
|
||||
|
||||
/* Restore previous texture state if any */
|
||||
if (self->attachments->textures[0].id > 0)
|
||||
glBindTexture (self->attachments->textures[0].target,
|
||||
self->attachments->textures[0].id);
|
||||
|
||||
g_clear_pointer (&surface, cairo_surface_destroy);
|
||||
|
||||
if (gdk_profiler_is_running ())
|
||||
gdk_profiler_add_markf (start_time, GDK_PROFILER_CURRENT_TIME-start_time,
|
||||
"Upload Texture",
|
||||
|
||||
@@ -279,6 +279,13 @@ void gsk_ngl_command_queue_execute (GskNglCommandQue
|
||||
guint surface_height,
|
||||
guint scale_factor,
|
||||
const cairo_region_t *scissor);
|
||||
|
||||
typedef enum {
|
||||
GSK_CONVERSION_LINEARIZE = 1 << 0,
|
||||
GSK_CONVERSION_PREMULTIPLY = 1 << 1,
|
||||
GSK_CONVERSION_FLIP = 1 << 2,
|
||||
} GskConversion;
|
||||
|
||||
int gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self,
|
||||
GdkTexture *texture,
|
||||
guint x_offset,
|
||||
@@ -286,16 +293,19 @@ int gsk_ngl_command_queue_upload_texture (GskNglCommandQue
|
||||
guint width,
|
||||
guint height,
|
||||
int min_filter,
|
||||
int mag_filter);
|
||||
int mag_filter,
|
||||
GskConversion *remaining);
|
||||
int gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self,
|
||||
int width,
|
||||
int height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter);
|
||||
guint gsk_ngl_command_queue_create_framebuffer (GskNglCommandQueue *self);
|
||||
gboolean gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self,
|
||||
int width,
|
||||
int height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
guint *out_fbo_id,
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdkcolorprofileprivate.h>
|
||||
#include <gsk/gskdebugprivate.h>
|
||||
#include <gsk/gskglshaderprivate.h>
|
||||
#include <gsk/gskrendererprivate.h>
|
||||
@@ -183,6 +184,7 @@ gsk_ngl_driver_create_atlas (GskNglDriver *self)
|
||||
atlas->texture_id = gsk_ngl_command_queue_create_texture (self->command_queue,
|
||||
atlas->width,
|
||||
atlas->height,
|
||||
GL_RGBA8,
|
||||
GL_LINEAR,
|
||||
GL_LINEAR);
|
||||
|
||||
@@ -715,6 +717,137 @@ gsk_ngl_driver_cache_texture (GskNglDriver *self,
|
||||
g_hash_table_insert (self->texture_id_to_key, GUINT_TO_POINTER (texture_id), k);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_rect (GskNglCommandQueue *command_queue,
|
||||
float min_x,
|
||||
float min_y,
|
||||
float max_x,
|
||||
float max_y,
|
||||
gboolean flip)
|
||||
{
|
||||
GskNglDrawVertex *vertices = gsk_ngl_command_queue_add_vertices (command_queue);
|
||||
float min_u = 0;
|
||||
float max_u = 1;
|
||||
float min_v = flip ? 0 : 1;
|
||||
float max_v = flip ? 1 : 0;
|
||||
guint16 c[4] = { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO };
|
||||
|
||||
vertices[0] = (GskNglDrawVertex) { .position = { min_x, min_y }, .uv = { min_u, min_v }, .color = { c[0], c[1], c[2], c[3] } };
|
||||
vertices[1] = (GskNglDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c[0], c[1], c[2], c[3] } };
|
||||
vertices[2] = (GskNglDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c[0], c[1], c[2], c[3] } };
|
||||
vertices[3] = (GskNglDrawVertex) { .position = { max_x, max_y }, .uv = { max_u, max_v }, .color = { c[0], c[1], c[2], c[3] } };
|
||||
vertices[4] = (GskNglDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c[0], c[1], c[2], c[3] } };
|
||||
vertices[5] = (GskNglDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c[0], c[1], c[2], c[3] } };
|
||||
}
|
||||
|
||||
static void
|
||||
set_viewport_for_size (GskNglDriver *self,
|
||||
GskNglProgram *program,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
float viewport[4] = { 0, 0, width, height };
|
||||
|
||||
gsk_ngl_uniform_state_set4fv (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_VIEWPORT, 0,
|
||||
1,
|
||||
(const float *)&viewport);
|
||||
self->stamps[UNIFORM_SHARED_VIEWPORT]++;
|
||||
}
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
|
||||
static void
|
||||
set_projection_for_size (GskNglDriver *self,
|
||||
GskNglProgram *program,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
graphene_matrix_t projection;
|
||||
|
||||
graphene_matrix_init_ortho (&projection, 0, width, 0, height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
|
||||
graphene_matrix_scale (&projection, 1, -1, 1);
|
||||
|
||||
gsk_ngl_uniform_state_set_matrix (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_PROJECTION, 0,
|
||||
&projection);
|
||||
self->stamps[UNIFORM_SHARED_PROJECTION]++;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_modelview (GskNglDriver *self,
|
||||
GskNglProgram *program)
|
||||
{
|
||||
graphene_matrix_t modelview;
|
||||
|
||||
graphene_matrix_init_identity (&modelview);
|
||||
|
||||
gsk_ngl_uniform_state_set_matrix (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_MODELVIEW, 0,
|
||||
&modelview);
|
||||
self->stamps[UNIFORM_SHARED_MODELVIEW]++;
|
||||
}
|
||||
|
||||
static GskNglTexture *
|
||||
gsk_ngl_driver_convert_texture (GskNglDriver *self,
|
||||
int texture_id,
|
||||
int width,
|
||||
int height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
GskConversion conversion)
|
||||
{
|
||||
GskNglRenderTarget *target;
|
||||
int prev_fbo;
|
||||
GskNglProgram *program;
|
||||
|
||||
if ((conversion & (GSK_CONVERSION_LINEARIZE|GSK_CONVERSION_PREMULTIPLY)) == (GSK_CONVERSION_LINEARIZE|GSK_CONVERSION_PREMULTIPLY))
|
||||
program = self->linearize_premultiply_no_clip;
|
||||
else if (conversion & GSK_CONVERSION_LINEARIZE)
|
||||
program = self->linearize_no_clip;
|
||||
else if (conversion & GSK_CONVERSION_PREMULTIPLY)
|
||||
program = self->premultiply_no_clip;
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
gdk_gl_context_make_current (self->command_queue->context);
|
||||
|
||||
gsk_ngl_driver_create_render_target (self,
|
||||
width, height,
|
||||
format,
|
||||
min_filter, mag_filter,
|
||||
&target);
|
||||
|
||||
prev_fbo = gsk_ngl_command_queue_bind_framebuffer (self->command_queue, target->framebuffer_id);
|
||||
gsk_ngl_command_queue_clear (self->command_queue, 0, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
gsk_ngl_command_queue_begin_draw (self->command_queue,
|
||||
program->program_info,
|
||||
width, height);
|
||||
|
||||
set_projection_for_size (self, program, width, height);
|
||||
set_viewport_for_size (self, program, width, height);
|
||||
reset_modelview (self, program);
|
||||
|
||||
gsk_ngl_program_set_uniform_texture (program,
|
||||
UNIFORM_SHARED_SOURCE, 0,
|
||||
GL_TEXTURE_2D, GL_TEXTURE0, texture_id);
|
||||
draw_rect (self->command_queue, 0, 0, width, height, (conversion & GSK_CONVERSION_FLIP) != 0);
|
||||
|
||||
gsk_ngl_command_queue_end_draw (self->command_queue);
|
||||
|
||||
gsk_ngl_command_queue_bind_framebuffer (self->command_queue, prev_fbo);
|
||||
|
||||
texture_id = gsk_ngl_driver_release_render_target (self, target, FALSE);
|
||||
|
||||
return g_hash_table_lookup (self->textures, GUINT_TO_POINTER (texture_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_ngl_driver_load_texture:
|
||||
* @self: a `GdkTexture`
|
||||
@@ -745,17 +878,28 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
|
||||
int mag_filter)
|
||||
{
|
||||
GdkGLContext *context;
|
||||
GdkTexture *downloaded_texture;
|
||||
GdkTexture *downloaded_texture = NULL;
|
||||
guint texture_id = 0;
|
||||
GskNglTexture *t;
|
||||
guint texture_id;
|
||||
int height;
|
||||
int width;
|
||||
int format;
|
||||
GskConversion conversion;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_NGL_DRIVER (self), 0);
|
||||
g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0);
|
||||
g_return_val_if_fail (GSK_IS_NGL_COMMAND_QUEUE (self->command_queue), 0);
|
||||
|
||||
context = self->command_queue->context;
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
format = gdk_texture_is_hdr (texture) ? GL_RGBA16F : GL_RGBA8;
|
||||
|
||||
if ((t = gdk_texture_get_render_data (texture, self)))
|
||||
{
|
||||
if (t->min_filter == min_filter && t->mag_filter == mag_filter)
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
if (GDK_IS_GL_TEXTURE (texture))
|
||||
{
|
||||
@@ -764,31 +908,56 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
|
||||
|
||||
if (gdk_gl_context_is_shared (context, texture_context))
|
||||
{
|
||||
/* A GL texture from the same GL context is a simple task... */
|
||||
return gdk_gl_texture_get_id (gl_texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
downloaded_texture = gdk_texture_download_texture (texture);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((t = gdk_texture_get_render_data (texture, self)))
|
||||
{
|
||||
if (t->min_filter == min_filter && t->mag_filter == mag_filter)
|
||||
return t->texture_id;
|
||||
}
|
||||
GdkColorProfile *profile;
|
||||
guint gl_texture_id;
|
||||
GdkGLTextureFlags flags;
|
||||
|
||||
downloaded_texture = gdk_texture_download_texture (texture);
|
||||
profile = gdk_texture_get_color_profile (texture);
|
||||
gl_texture_id = gdk_gl_texture_get_id (gl_texture);
|
||||
flags = gdk_gl_texture_get_flags (gl_texture);
|
||||
|
||||
/* A GL texture from the same GL context is a simple task... */
|
||||
if (profile == gdk_color_profile_get_srgb_linear () &&
|
||||
flags == GDK_GL_TEXTURE_PREMULTIPLIED)
|
||||
{
|
||||
return gl_texture_id;
|
||||
}
|
||||
else if (profile == gdk_color_profile_get_srgb () ||
|
||||
profile == gdk_color_profile_get_srgb_linear ())
|
||||
{
|
||||
conversion = 0;
|
||||
|
||||
if (profile == gdk_color_profile_get_srgb ())
|
||||
conversion |= GSK_CONVERSION_LINEARIZE;
|
||||
|
||||
if ((flags & GDK_GL_TEXTURE_PREMULTIPLIED) == 0)
|
||||
conversion |= GSK_CONVERSION_PREMULTIPLY;
|
||||
|
||||
if ((flags & GDK_GL_TEXTURE_FLIPPED) != 0)
|
||||
conversion |= GSK_CONVERSION_FLIP;
|
||||
|
||||
t = gsk_ngl_driver_convert_texture (self,
|
||||
gl_texture_id,
|
||||
width, height, format,
|
||||
min_filter, mag_filter,
|
||||
conversion);
|
||||
|
||||
|
||||
if (gdk_texture_set_render_data (texture, self, t, gsk_ngl_texture_destroyed))
|
||||
t->user = texture;
|
||||
|
||||
return t->texture_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
downloaded_texture = gdk_texture_download_texture (texture);
|
||||
|
||||
/* The download_texture() call may have switched the GL context. Make sure
|
||||
* the right context is at work again. */
|
||||
* the right context is at work again.
|
||||
*/
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
texture_id = gsk_ngl_command_queue_upload_texture (self->command_queue,
|
||||
downloaded_texture,
|
||||
0,
|
||||
@@ -796,22 +965,30 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
|
||||
width,
|
||||
height,
|
||||
min_filter,
|
||||
mag_filter);
|
||||
mag_filter,
|
||||
&conversion);
|
||||
|
||||
t = gsk_ngl_texture_new (texture_id,
|
||||
width, height, min_filter, mag_filter,
|
||||
width, height, format, min_filter, mag_filter,
|
||||
self->current_frame_id);
|
||||
|
||||
g_hash_table_insert (self->textures, GUINT_TO_POINTER (texture_id), t);
|
||||
|
||||
g_clear_object (&downloaded_texture);
|
||||
|
||||
if (conversion)
|
||||
t = gsk_ngl_driver_convert_texture (self,
|
||||
texture_id,
|
||||
width, height, format,
|
||||
min_filter, mag_filter,
|
||||
conversion);
|
||||
|
||||
if (gdk_texture_set_render_data (texture, self, t, gsk_ngl_texture_destroyed))
|
||||
t->user = texture;
|
||||
|
||||
gdk_gl_context_label_object_printf (context, GL_TEXTURE, t->texture_id,
|
||||
"GdkTexture<%p> %d", texture, t->texture_id);
|
||||
|
||||
g_clear_object (&downloaded_texture);
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
@@ -820,6 +997,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
|
||||
* @self: a `GskNglDriver`
|
||||
* @width: the width of the texture
|
||||
* @height: the height of the texture
|
||||
* @format: format for the texture. Should be GL_RGBA8, GL_RGBA16F or GL_RGBA32F
|
||||
* @min_filter: GL_NEAREST or GL_LINEAR
|
||||
* @mag_filter: GL_NEAREST or GL_FILTER
|
||||
*
|
||||
@@ -837,6 +1015,7 @@ GskNglTexture *
|
||||
gsk_ngl_driver_create_texture (GskNglDriver *self,
|
||||
float width,
|
||||
float height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
@@ -847,15 +1026,19 @@ gsk_ngl_driver_create_texture (GskNglDriver *self,
|
||||
|
||||
texture_id = gsk_ngl_command_queue_create_texture (self->command_queue,
|
||||
width, height,
|
||||
format,
|
||||
min_filter, mag_filter);
|
||||
texture = gsk_ngl_texture_new (texture_id,
|
||||
width, height,
|
||||
format,
|
||||
min_filter, mag_filter,
|
||||
self->current_frame_id);
|
||||
g_hash_table_insert (self->textures,
|
||||
GUINT_TO_POINTER (texture->texture_id),
|
||||
texture);
|
||||
|
||||
texture->last_used_in_frame = self->current_frame_id;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@@ -896,6 +1079,8 @@ gsk_ngl_driver_release_texture (GskNglDriver *self,
|
||||
* @self: a `GskNglDriver`
|
||||
* @width: the width for the render target
|
||||
* @height: the height for the render target
|
||||
* @format: the format to use. This should be GL_RGBA8,
|
||||
* GL_RGBA16F or GL_RGBA32F
|
||||
* @min_filter: the min filter to use for the texture
|
||||
* @mag_filter: the mag filter to use for the texture
|
||||
* @out_render_target: (out): a location for the render target
|
||||
@@ -915,6 +1100,7 @@ gboolean
|
||||
gsk_ngl_driver_create_render_target (GskNglDriver *self,
|
||||
int width,
|
||||
int height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
GskNglRenderTarget **out_render_target)
|
||||
@@ -947,6 +1133,7 @@ gsk_ngl_driver_create_render_target (GskNglDriver *self,
|
||||
|
||||
if (gsk_ngl_command_queue_create_render_target (self->command_queue,
|
||||
width, height,
|
||||
format,
|
||||
min_filter, mag_filter,
|
||||
&framebuffer_id, &texture_id))
|
||||
{
|
||||
@@ -955,6 +1142,7 @@ gsk_ngl_driver_create_render_target (GskNglDriver *self,
|
||||
render_target = g_slice_new0 (GskNglRenderTarget);
|
||||
render_target->min_filter = min_filter;
|
||||
render_target->mag_filter = mag_filter;
|
||||
render_target->format = format;
|
||||
render_target->width = width;
|
||||
render_target->height = height;
|
||||
render_target->framebuffer_id = framebuffer_id;
|
||||
@@ -1014,6 +1202,7 @@ gsk_ngl_driver_release_render_target (GskNglDriver *self,
|
||||
texture = gsk_ngl_texture_new (render_target->texture_id,
|
||||
render_target->width,
|
||||
render_target->height,
|
||||
render_target->format,
|
||||
render_target->min_filter,
|
||||
render_target->mag_filter,
|
||||
self->current_frame_id);
|
||||
@@ -1210,6 +1399,7 @@ gsk_ngl_driver_add_texture_slices (GskNglDriver *self,
|
||||
int tex_width;
|
||||
int tex_height;
|
||||
int x = 0, y = 0;
|
||||
int format;
|
||||
|
||||
g_assert (GSK_IS_NGL_DRIVER (self));
|
||||
g_assert (GDK_IS_TEXTURE (texture));
|
||||
@@ -1221,6 +1411,9 @@ gsk_ngl_driver_add_texture_slices (GskNglDriver *self,
|
||||
|
||||
tex_width = texture->width;
|
||||
tex_height = texture->height;
|
||||
|
||||
format = gdk_texture_is_hdr (texture) ? GL_RGBA16F : GL_RGBA8;
|
||||
|
||||
cols = (texture->width / max_texture_size) + 1;
|
||||
rows = (texture->height / max_texture_size) + 1;
|
||||
|
||||
@@ -1243,12 +1436,37 @@ gsk_ngl_driver_add_texture_slices (GskNglDriver *self,
|
||||
int slice_height = MIN (max_texture_size, texture->height - y);
|
||||
int slice_index = (col * rows) + row;
|
||||
guint texture_id;
|
||||
GskConversion conversion;
|
||||
|
||||
texture_id = gsk_ngl_command_queue_upload_texture (self->command_queue,
|
||||
texture,
|
||||
x, y,
|
||||
slice_width, slice_height,
|
||||
GL_NEAREST, GL_NEAREST);
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&conversion);
|
||||
|
||||
|
||||
if (conversion)
|
||||
{
|
||||
t = gsk_ngl_texture_new (texture_id,
|
||||
slice_width, slice_height,
|
||||
format,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
0);
|
||||
g_hash_table_insert (self->textures, GUINT_TO_POINTER (texture_id), t);
|
||||
|
||||
t = gsk_ngl_driver_convert_texture (self,
|
||||
texture_id,
|
||||
slice_width, slice_height,
|
||||
format,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
conversion);
|
||||
|
||||
texture_id = t->texture_id;
|
||||
t->texture_id = 0;
|
||||
g_hash_table_steal (self->textures, GUINT_TO_POINTER (texture_id));
|
||||
gsk_ngl_texture_free (t);
|
||||
}
|
||||
|
||||
slices[slice_index].rect.x = x;
|
||||
slices[slice_index].rect.y = y;
|
||||
@@ -1266,6 +1484,7 @@ gsk_ngl_driver_add_texture_slices (GskNglDriver *self,
|
||||
/* Allocate one Texture for the entire thing. */
|
||||
t = gsk_ngl_texture_new (0,
|
||||
tex_width, tex_height,
|
||||
GL_RGBA8,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
self->current_frame_id);
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ struct _GskNglRenderTarget
|
||||
guint texture_id;
|
||||
int min_filter;
|
||||
int mag_filter;
|
||||
int format;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
@@ -144,6 +145,7 @@ GdkGLContext *gsk_ngl_driver_get_context (GskNglDriver
|
||||
gboolean gsk_ngl_driver_create_render_target (GskNglDriver *self,
|
||||
int width,
|
||||
int height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
GskNglRenderTarget **render_target);
|
||||
@@ -166,6 +168,7 @@ guint gsk_ngl_driver_load_texture (GskNglDriver
|
||||
GskNglTexture *gsk_ngl_driver_create_texture (GskNglDriver *self,
|
||||
float width,
|
||||
float height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter);
|
||||
void gsk_ngl_driver_release_texture (GskNglDriver *self,
|
||||
|
||||
@@ -21,13 +21,21 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdkcolorprofileprivate.h>
|
||||
|
||||
#include "gsknglcommandqueueprivate.h"
|
||||
#include "gskngldriverprivate.h"
|
||||
#include "gsknglglyphlibraryprivate.h"
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
#include <cairo-ft.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_PARAMETER_TAGS_H
|
||||
#endif
|
||||
|
||||
#define MAX_GLYPH_SIZE 128
|
||||
|
||||
G_DEFINE_TYPE (GskNglGlyphLibrary, gsk_ngl_glyph_library, GSK_TYPE_GL_TEXTURE_LIBRARY)
|
||||
@@ -161,16 +169,26 @@ gsk_ngl_glyph_library_create_surface (GskNglGlyphLibrary *self,
|
||||
|
||||
static void
|
||||
render_glyph (cairo_surface_t *surface,
|
||||
const cairo_scaled_font_t *scaled_font,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
const GskNglGlyphKey *key,
|
||||
const GskNglGlyphValue *value)
|
||||
{
|
||||
cairo_t *cr;
|
||||
cairo_glyph_t glyph;
|
||||
#ifdef HAVE_PANGOFT
|
||||
FT_Face face;
|
||||
FT_Bool darken = 1;
|
||||
FT_Parameter property = { FT_PARAM_TAG_STEM_DARKENING, &darken };
|
||||
#endif
|
||||
|
||||
g_assert (surface != NULL);
|
||||
g_assert (scaled_font != NULL);
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
face = cairo_ft_scaled_font_lock_face (scaled_font);
|
||||
FT_Face_Properties (face, 1, &property);
|
||||
#endif
|
||||
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_scaled_font (cr, scaled_font);
|
||||
cairo_set_source_rgba (cr, 1, 1, 1, 1);
|
||||
@@ -183,6 +201,10 @@ render_glyph (cairo_surface_t *surface,
|
||||
cairo_destroy (cr);
|
||||
|
||||
cairo_surface_flush (surface);
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
cairo_ft_scaled_font_unlock_face (scaled_font);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -237,10 +259,12 @@ gsk_ngl_glyph_library_upload_glyph (GskNglGlyphLibrary *self,
|
||||
pixel_data = free_data = g_malloc (width * height * 4);
|
||||
gdk_memory_convert (pixel_data,
|
||||
width * 4,
|
||||
GDK_MEMORY_CONVERT_GLES_RGBA,
|
||||
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
||||
gdk_color_profile_get_srgb_linear (),
|
||||
cairo_image_surface_get_data (surface),
|
||||
width * 4,
|
||||
GDK_MEMORY_DEFAULT,
|
||||
gdk_color_profile_get_srgb_linear (),
|
||||
width, height);
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
#include <gdk/gdkcolorprofileprivate.h>
|
||||
|
||||
#include "gsknglcommandqueueprivate.h"
|
||||
#include "gskngldriverprivate.h"
|
||||
@@ -71,25 +73,105 @@ gsk_ngl_icon_library_init (GskNglIconLibrary *self)
|
||||
gsk_ngl_icon_data_free);
|
||||
}
|
||||
|
||||
static GdkMemoryTexture *
|
||||
gsk_ngl_texture_prepare_upload (GdkGLContext *context,
|
||||
GdkTexture *texture,
|
||||
GLenum *gl_internalformat,
|
||||
GLenum *gl_format,
|
||||
GLenum *gl_type)
|
||||
{
|
||||
GdkMemoryTexture *memtex;
|
||||
GdkMemoryFormat format;
|
||||
|
||||
memtex = GDK_MEMORY_TEXTURE (gdk_texture_download_texture (texture));
|
||||
format = gdk_memory_texture_get_format (memtex);
|
||||
|
||||
if (!gdk_memory_format_gl_format (format,
|
||||
gdk_gl_context_get_use_es (context),
|
||||
gl_internalformat,
|
||||
gl_format,
|
||||
gl_type))
|
||||
{
|
||||
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
if (!gdk_memory_format_gl_format (format,
|
||||
gdk_gl_context_get_use_es (context),
|
||||
gl_internalformat,
|
||||
gl_format,
|
||||
gl_type))
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
return gdk_memory_texture_convert (memtex,
|
||||
format,
|
||||
gdk_color_profile_get_srgb_linear (),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
straightTexSubImage2D (int tex,
|
||||
int level,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
GLenum gl_format,
|
||||
GLenum gl_type,
|
||||
const guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
glTexSubImage2D (tex, level,
|
||||
x, y,
|
||||
width, height,
|
||||
gl_format, gl_type,
|
||||
data);
|
||||
}
|
||||
|
||||
static void
|
||||
strideTexSubImage2D (int tex,
|
||||
int level,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
GLenum gl_format,
|
||||
GLenum gl_type,
|
||||
const guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
glTexSubImage2D (tex, level,
|
||||
x, y + i,
|
||||
width, height,
|
||||
gl_format, gl_type,
|
||||
data + i * stride);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gsk_ngl_icon_library_add (GskNglIconLibrary *self,
|
||||
GdkTexture *key,
|
||||
const GskNglIconData **out_value)
|
||||
{
|
||||
GskNglTextureLibrary *tl = (GskNglTextureLibrary *)self;
|
||||
GdkGLContext *context = gdk_gl_context_get_current ();
|
||||
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
|
||||
cairo_surface_t *surface;
|
||||
GdkMemoryTexture *memtex;
|
||||
GskNglIconData *icon_data;
|
||||
guint8 *pixel_data;
|
||||
guint8 *surface_data;
|
||||
guint8 *free_data = NULL;
|
||||
guint gl_format;
|
||||
guint gl_type;
|
||||
const guchar *pixel_data;
|
||||
gsize stride, bpp;
|
||||
GdkMemoryFormat format;
|
||||
GLenum gl_internalformat;
|
||||
GLenum gl_format;
|
||||
GLenum gl_type;
|
||||
guint packed_x;
|
||||
guint packed_y;
|
||||
int width;
|
||||
int height;
|
||||
guint texture_id;
|
||||
void (* upload_func) (int, int, int, int, int, int, GLenum, GLenum, const guchar *, gsize);
|
||||
|
||||
g_assert (GSK_IS_NGL_ICON_LIBRARY (self));
|
||||
g_assert (GDK_IS_TEXTURE (key));
|
||||
@@ -106,104 +188,117 @@ gsk_ngl_icon_library_add (GskNglIconLibrary *self,
|
||||
icon_data->source_texture = g_object_ref (key);
|
||||
|
||||
/* actually upload the texture */
|
||||
surface = gdk_texture_download_surface (key);
|
||||
surface_data = cairo_image_surface_get_data (surface);
|
||||
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
|
||||
gdk_gl_context_push_debug_group_printf (context,
|
||||
"Uploading texture");
|
||||
memtex = gsk_ngl_texture_prepare_upload (context,
|
||||
key,
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type);
|
||||
|
||||
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
|
||||
{
|
||||
pixel_data = free_data = g_malloc (width * height * 4);
|
||||
gdk_memory_convert (pixel_data, width * 4,
|
||||
GDK_MEMORY_CONVERT_GLES_RGBA,
|
||||
surface_data, cairo_image_surface_get_stride (surface),
|
||||
GDK_MEMORY_DEFAULT, width, height);
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel_data = surface_data;
|
||||
gl_format = GL_BGRA;
|
||||
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
}
|
||||
pixel_data = gdk_memory_texture_get_data (memtex);
|
||||
stride = gdk_memory_texture_get_stride (memtex);
|
||||
format = gdk_memory_texture_get_format (memtex);
|
||||
bpp = gdk_memory_format_bytes_per_pixel (format);
|
||||
|
||||
texture_id = GSK_NGL_TEXTURE_ATLAS_ENTRY_TEXTURE (icon_data);
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, texture_id);
|
||||
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1, packed_y + 1,
|
||||
width, height,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
||||
/* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
|
||||
* the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
|
||||
*/
|
||||
if ((stride % bpp == 0) &&
|
||||
(!gdk_gl_context_get_use_es (context) ||
|
||||
gdk_gl_context_has_version (context, 3, 0) ||
|
||||
gdk_gl_context_has_unpack_subimage (context)))
|
||||
{
|
||||
upload_func = straightTexSubImage2D;
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
|
||||
}
|
||||
else
|
||||
{
|
||||
upload_func = strideTexSubImage2D;
|
||||
}
|
||||
|
||||
upload_func (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1, packed_y + 1,
|
||||
width, height,
|
||||
gl_format, gl_type,
|
||||
pixel_data,
|
||||
stride);
|
||||
/* Padding top */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1, packed_y,
|
||||
width, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
upload_func (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1, packed_y,
|
||||
width, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data,
|
||||
stride);
|
||||
/* Padding left */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y + 1,
|
||||
1, height,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
upload_func (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y + 1,
|
||||
1, height,
|
||||
gl_format, gl_type,
|
||||
pixel_data,
|
||||
stride);
|
||||
/* Padding top left */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
upload_func (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data,
|
||||
stride);
|
||||
|
||||
/* Padding right */
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
|
||||
glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x + width + 1, packed_y + 1,
|
||||
1, height,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
upload_func (GL_TEXTURE_2D, 0,
|
||||
packed_x + width + 1, packed_y + 1,
|
||||
1, height,
|
||||
gl_format, gl_type,
|
||||
pixel_data + (width - 1) * bpp,
|
||||
stride);
|
||||
/* Padding top right */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x + width + 1, packed_y,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
upload_func (GL_TEXTURE_2D, 0,
|
||||
packed_x + width + 1, packed_y,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data + (width - 1) * bpp,
|
||||
stride);
|
||||
/* Padding bottom */
|
||||
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
glPixelStorei (GL_UNPACK_SKIP_ROWS, height - 1);
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1, packed_y + 1 + height,
|
||||
width, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
upload_func (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1, packed_y + 1 + height,
|
||||
width, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data + (height - 1) * stride,
|
||||
stride);
|
||||
/* Padding bottom left */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y + 1 + height,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
upload_func (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y + 1 + height,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data + (height - 1) * stride,
|
||||
stride);
|
||||
/* Padding bottom right */
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
|
||||
glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1 + width, packed_y + 1 + height,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
upload_func (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1 + width, packed_y + 1 + height,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data + (width - 1) * bpp + (height - 1) * stride,
|
||||
stride);
|
||||
|
||||
/* Reset this */
|
||||
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
|
||||
if ((stride % bpp == 0) &&
|
||||
(!gdk_gl_context_get_use_es (context) ||
|
||||
gdk_gl_context_has_version (context, 3, 0) ||
|
||||
gdk_gl_context_has_unpack_subimage (context)))
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
|
||||
|
||||
*out_value = icon_data;
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
g_free (free_data);
|
||||
g_object_unref (memtex);
|
||||
|
||||
tl->driver->command_queue->n_uploads++;
|
||||
|
||||
|
||||
@@ -82,3 +82,19 @@ GSK_NGL_DEFINE_PROGRAM (unblurred_outset_shadow,
|
||||
GSK_NGL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread)
|
||||
GSK_NGL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset)
|
||||
GSK_NGL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
|
||||
|
||||
GSK_NGL_DEFINE_PROGRAM (postprocessing,
|
||||
"/org/gtk/libgsk/ngl/postprocessing.glsl",
|
||||
GSK_NGL_NO_UNIFORMS)
|
||||
|
||||
GSK_NGL_DEFINE_PROGRAM (linearize,
|
||||
"/org/gtk/libgsk/ngl/linearize.glsl",
|
||||
GSK_NGL_NO_UNIFORMS)
|
||||
|
||||
GSK_NGL_DEFINE_PROGRAM (premultiply,
|
||||
"/org/gtk/libgsk/ngl/premultiply.glsl",
|
||||
GSK_NGL_NO_UNIFORMS)
|
||||
|
||||
GSK_NGL_DEFINE_PROGRAM (linearize_premultiply,
|
||||
"/org/gtk/libgsk/ngl/linearize_premultiply.glsl",
|
||||
GSK_NGL_NO_UNIFORMS)
|
||||
|
||||
@@ -22,8 +22,11 @@
|
||||
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdksurfaceprivate.h>
|
||||
#include <gsk/gskdebugprivate.h>
|
||||
#include <gsk/gskrendererprivate.h>
|
||||
#include <gsk/gskrendernodeprivate.h>
|
||||
|
||||
#include "gsknglcommandqueueprivate.h"
|
||||
#include "gskngldriverprivate.h"
|
||||
@@ -245,6 +248,7 @@ gsk_ngl_renderer_render_texture (GskRenderer *renderer,
|
||||
|
||||
if (gsk_ngl_driver_create_render_target (self->driver,
|
||||
width, height,
|
||||
GL_RGBA8,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&render_target))
|
||||
{
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include <gsk/gskrendernodeprivate.h>
|
||||
#include <gsk/gskglshaderprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
#include <gdk/gdkcolorprofileprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <gsk/gsktransformprivate.h>
|
||||
#include <gsk/gskroundedrectprivate.h>
|
||||
#include <math.h>
|
||||
@@ -162,6 +164,11 @@ struct _GskNglRenderJob
|
||||
|
||||
/* If we should be rendering red zones over fallback nodes */
|
||||
guint debug_fallback : 1;
|
||||
|
||||
/* Format of the framebuffer we are rendering on, used in
|
||||
* determining the format for intermediate textures
|
||||
*/
|
||||
int framebuffer_format;
|
||||
};
|
||||
|
||||
typedef struct _GskNglRenderOffscreen
|
||||
@@ -198,6 +205,16 @@ static gboolean gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob
|
||||
const GskRenderNode *node,
|
||||
GskNglRenderOffscreen *offscreen);
|
||||
|
||||
static inline int
|
||||
get_target_format (GskNglRenderJob *job,
|
||||
const GskRenderNode *node)
|
||||
{
|
||||
if (!gsk_render_node_is_hdr (node))
|
||||
return GL_RGBA8;
|
||||
|
||||
return job->framebuffer_format;
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_full_texture_region (GskNglRenderOffscreen *offscreen)
|
||||
{
|
||||
@@ -924,11 +941,24 @@ gsk_ngl_render_job_update_clip (GskNglRenderJob *job,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Convert from sRGB floats to linear sRGB half-floats */
|
||||
static inline void
|
||||
rgba_to_half (const GdkRGBA *rgba,
|
||||
guint16 h[4])
|
||||
{
|
||||
float_to_half4 ((const float *)rgba, h);
|
||||
GdkRGBA d;
|
||||
gdk_memory_convert ((guchar *) &d,
|
||||
sizeof (float) * 4,
|
||||
GDK_MEMORY_R32G32B32_FLOAT,
|
||||
gdk_color_profile_get_srgb_linear (),
|
||||
(guchar *) rgba,
|
||||
sizeof (float) * 4,
|
||||
GDK_MEMORY_R32G32B32_FLOAT,
|
||||
gdk_color_profile_get_srgb (),
|
||||
1,
|
||||
1);
|
||||
d.alpha = rgba->alpha;
|
||||
float_to_half4 ((const float *)&d, h);
|
||||
}
|
||||
|
||||
/* fill_vertex_data */
|
||||
@@ -1162,6 +1192,9 @@ gsk_ngl_render_job_visit_as_fallback (GskNglRenderJob *job,
|
||||
surface_width,
|
||||
surface_height);
|
||||
|
||||
gdk_cairo_surface_set_color_profile (rendered_surface,
|
||||
gdk_color_profile_get_srgb_linear ());
|
||||
|
||||
cairo_surface_set_device_scale (rendered_surface, scale_x, scale_y);
|
||||
cr = cairo_create (rendered_surface);
|
||||
|
||||
@@ -1258,6 +1291,7 @@ blur_offscreen (GskNglRenderJob *job,
|
||||
if (!gsk_ngl_driver_create_render_target (job->driver,
|
||||
MAX (texture_to_blur_width, 1),
|
||||
MAX (texture_to_blur_height, 1),
|
||||
job->framebuffer_format,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&pass1))
|
||||
return 0;
|
||||
@@ -1268,6 +1302,7 @@ blur_offscreen (GskNglRenderJob *job,
|
||||
if (!gsk_ngl_driver_create_render_target (job->driver,
|
||||
texture_to_blur_width,
|
||||
texture_to_blur_height,
|
||||
job->framebuffer_format,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&pass2))
|
||||
return gsk_ngl_driver_release_render_target (job->driver, pass1, FALSE);
|
||||
@@ -2179,6 +2214,7 @@ gsk_ngl_render_job_visit_blurred_inset_shadow_node (GskNglRenderJob *job,
|
||||
|
||||
if (!gsk_ngl_driver_create_render_target (job->driver,
|
||||
texture_width, texture_height,
|
||||
get_target_format (job, node),
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&render_target))
|
||||
g_assert_not_reached ();
|
||||
@@ -2449,6 +2485,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job,
|
||||
|
||||
gsk_ngl_driver_create_render_target (job->driver,
|
||||
texture_width, texture_height,
|
||||
get_target_format (job, node),
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&render_target);
|
||||
|
||||
@@ -3533,7 +3570,8 @@ gsk_ngl_render_job_visit_repeat_node (GskNglRenderJob *job,
|
||||
|
||||
/* If the size of the repeat node is smaller than the size of the
|
||||
* child node, we don't repeat at all and can just draw that part
|
||||
* of the child texture... */
|
||||
* of the child texture...
|
||||
*/
|
||||
if (rect_contains_rect (child_bounds, &node->bounds))
|
||||
{
|
||||
gsk_ngl_render_job_visit_clipped_child (job, child, &node->bounds);
|
||||
@@ -3856,6 +3894,7 @@ gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob *job,
|
||||
|
||||
if (!gsk_ngl_driver_create_render_target (job->driver,
|
||||
scaled_width, scaled_height,
|
||||
get_target_format (job, node),
|
||||
filter, filter,
|
||||
&render_target))
|
||||
g_assert_not_reached ();
|
||||
@@ -3954,6 +3993,7 @@ gsk_ngl_render_job_render_flipped (GskNglRenderJob *job,
|
||||
if (!gsk_ngl_command_queue_create_render_target (job->command_queue,
|
||||
MAX (1, job->viewport.size.width),
|
||||
MAX (1, job->viewport.size.height),
|
||||
job->framebuffer_format,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&framebuffer_id, &texture_id))
|
||||
return;
|
||||
@@ -3988,6 +4028,21 @@ gsk_ngl_render_job_render_flipped (GskNglRenderJob *job,
|
||||
glDeleteTextures (1, &texture_id);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_ngl_render_job_postprocess (GskNglRenderJob *job,
|
||||
guint texture_id)
|
||||
{
|
||||
gsk_ngl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
|
||||
gsk_ngl_command_queue_clear (job->command_queue, 0, &job->viewport);
|
||||
|
||||
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, postprocessing));
|
||||
gsk_ngl_program_set_uniform_texture (job->current_program,
|
||||
UNIFORM_SHARED_SOURCE, 0,
|
||||
GL_TEXTURE_2D, GL_TEXTURE0, texture_id);
|
||||
gsk_ngl_render_job_draw_offscreen_rect (job, &job->viewport);
|
||||
gsk_ngl_render_job_end_draw (job);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_ngl_render_job_render (GskNglRenderJob *job,
|
||||
GskRenderNode *root)
|
||||
@@ -3995,6 +4050,8 @@ gsk_ngl_render_job_render (GskNglRenderJob *job,
|
||||
G_GNUC_UNUSED gint64 start_time;
|
||||
guint scale_factor;
|
||||
guint surface_height;
|
||||
GskNglRenderTarget *render_target;
|
||||
guint texture_id;
|
||||
|
||||
g_return_if_fail (job != NULL);
|
||||
g_return_if_fail (root != NULL);
|
||||
@@ -4005,15 +4062,27 @@ gsk_ngl_render_job_render (GskNglRenderJob *job,
|
||||
|
||||
gsk_ngl_command_queue_make_current (job->command_queue);
|
||||
|
||||
gsk_ngl_driver_create_render_target (job->driver,
|
||||
job->viewport.size.width,
|
||||
job->viewport.size.height,
|
||||
job->framebuffer_format,
|
||||
GL_NEAREST,
|
||||
GL_NEAREST,
|
||||
&render_target);
|
||||
|
||||
/* Build the command queue using the shared GL context for all renderers
|
||||
* on the same display.
|
||||
*/
|
||||
start_time = GDK_PROFILER_CURRENT_TIME;
|
||||
gdk_gl_context_push_debug_group (job->command_queue->context, "Building command queue");
|
||||
gsk_ngl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
|
||||
gsk_ngl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
|
||||
gsk_ngl_command_queue_clear (job->command_queue, 0, &job->viewport);
|
||||
gsk_ngl_render_job_visit_node (job, root);
|
||||
gdk_gl_context_pop_debug_group (job->command_queue->context);
|
||||
|
||||
texture_id = gsk_ngl_driver_release_render_target (job->driver, render_target, FALSE);
|
||||
gsk_ngl_render_job_postprocess (job, texture_id);
|
||||
|
||||
gdk_profiler_add_mark (start_time, GDK_PROFILER_CURRENT_TIME-start_time, "Build GL command queue", "");
|
||||
|
||||
#if 0
|
||||
@@ -4044,6 +4113,23 @@ gsk_ngl_render_job_set_debug_fallback (GskNglRenderJob *job,
|
||||
job->debug_fallback = !!debug_fallback;
|
||||
}
|
||||
|
||||
static int
|
||||
get_framebuffer_format (guint framebuffer)
|
||||
{
|
||||
int type, size;
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
|
||||
glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE, &type);
|
||||
glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &size);
|
||||
|
||||
if (type == GL_FLOAT && size == 32)
|
||||
return GL_RGBA32F;
|
||||
else if (size > 8)
|
||||
return GL_RGBA16F;
|
||||
else
|
||||
return GL_RGBA8;
|
||||
}
|
||||
|
||||
GskNglRenderJob *
|
||||
gsk_ngl_render_job_new (GskNglDriver *driver,
|
||||
const graphene_rect_t *viewport,
|
||||
@@ -4070,6 +4156,7 @@ gsk_ngl_render_job_new (GskNglDriver *driver,
|
||||
job->scale_x = scale_factor;
|
||||
job->scale_y = scale_factor;
|
||||
job->viewport = *viewport;
|
||||
job->framebuffer_format = get_framebuffer_format (framebuffer);
|
||||
|
||||
gsk_ngl_render_job_set_alpha (job, 1.0f);
|
||||
gsk_ngl_render_job_set_projection_from_rect (job, viewport, NULL);
|
||||
|
||||
@@ -59,6 +59,7 @@ GskNglTexture *
|
||||
gsk_ngl_texture_new (guint texture_id,
|
||||
int width,
|
||||
int height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
gint64 frame_id)
|
||||
@@ -70,6 +71,7 @@ gsk_ngl_texture_new (guint texture_id,
|
||||
texture->link.data = texture;
|
||||
texture->min_filter = min_filter;
|
||||
texture->mag_filter = mag_filter;
|
||||
texture->format = format;
|
||||
texture->width = width;
|
||||
texture->height = height;
|
||||
texture->last_used_in_frame = frame_id;
|
||||
|
||||
@@ -228,7 +228,7 @@ gsk_ngl_texture_library_pack_one (GskNglTextureLibrary *self,
|
||||
height = MIN (height, self->driver->command_queue->max_texture_size);
|
||||
}
|
||||
|
||||
texture = gsk_ngl_driver_create_texture (self->driver, width, height, GL_LINEAR, GL_LINEAR);
|
||||
texture = gsk_ngl_driver_create_texture (self->driver, width, height, GL_RGBA8, GL_LINEAR, GL_LINEAR);
|
||||
texture->permanent = TRUE;
|
||||
|
||||
return texture;
|
||||
|
||||
@@ -67,6 +67,7 @@ struct _GskNglTexture
|
||||
int height;
|
||||
int min_filter;
|
||||
int mag_filter;
|
||||
int format;
|
||||
|
||||
/* Set when used by an atlas so we don't drop the texture */
|
||||
guint permanent : 1;
|
||||
@@ -75,6 +76,7 @@ struct _GskNglTexture
|
||||
GskNglTexture *gsk_ngl_texture_new (guint texture_id,
|
||||
int width,
|
||||
int height,
|
||||
int format,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
gint64 frame_id);
|
||||
|
||||
22
gsk/ngl/resources/linearize.glsl
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
// VERTEX_SHADER:
|
||||
// linearize.glsl
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// linearize.glsl
|
||||
|
||||
void main() {
|
||||
vec4 diffuse = GskTexture(u_source, vUv);
|
||||
|
||||
diffuse = gsk_unpremultiply(diffuse);
|
||||
diffuse = gsk_srgb_to_linear(diffuse);
|
||||
diffuse = gsk_premultiply(diffuse);
|
||||
|
||||
gskSetOutputColor(diffuse);
|
||||
}
|
||||
21
gsk/ngl/resources/linearize_premultiply.glsl
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
// VERTEX_SHADER:
|
||||
// linearize_premultiply.glsl
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// linearize_premultiply.glsl
|
||||
|
||||
void main() {
|
||||
vec4 diffuse = GskTexture(u_source, vUv);
|
||||
|
||||
diffuse = gsk_srgb_to_linear(diffuse);
|
||||
diffuse = gsk_premultiply(diffuse);
|
||||
|
||||
gskSetOutputColor(diffuse);
|
||||
}
|
||||
22
gsk/ngl/resources/postprocessing.glsl
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
// VERTEX_SHADER:
|
||||
// postprocessing.glsl
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// postprocessing.glsl
|
||||
|
||||
void main() {
|
||||
vec4 diffuse = GskTexture(u_source, vUv);
|
||||
|
||||
diffuse = gsk_unpremultiply(diffuse);
|
||||
diffuse = gsk_linear_to_srgb(diffuse);
|
||||
diffuse = gsk_premultiply(diffuse);
|
||||
|
||||
gskSetOutputColor(diffuse);
|
||||
}
|
||||
@@ -44,10 +44,31 @@ gsk_get_bounds(vec4[3] data)
|
||||
return vec4(data[0].xy, data[0].xy + data[0].zw);
|
||||
}
|
||||
|
||||
vec4 gsk_premultiply(vec4 c) {
|
||||
vec4 gsk_premultiply(vec4 c)
|
||||
{
|
||||
return vec4(c.rgb * c.a, c.a);
|
||||
}
|
||||
|
||||
vec4 gsk_unpremultiply(vec4 c)
|
||||
{
|
||||
if (c.a != 0)
|
||||
return vec4(c.rgb / c.a, c.a);
|
||||
else
|
||||
return c;
|
||||
}
|
||||
|
||||
vec4 gsk_srgb_to_linear(vec4 srgb)
|
||||
{
|
||||
vec3 linear_rgb = pow(srgb.rgb, vec3(2.2));
|
||||
return vec4(linear_rgb, srgb.a);
|
||||
}
|
||||
|
||||
vec4 gsk_linear_to_srgb(vec4 linear_rgba)
|
||||
{
|
||||
vec3 srgb = pow(linear_rgba.rgb , vec3(1/2.2));
|
||||
return vec4(srgb, linear_rgba.a);
|
||||
}
|
||||
|
||||
vec4 gsk_scaled_premultiply(vec4 c, float s) {
|
||||
// Fast version of gsk_premultiply(c) * s
|
||||
// 4 muls instead of 7
|
||||
|
||||
20
gsk/ngl/resources/premultiply.glsl
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
// VERTEX_SHADER:
|
||||
// premultiply.glsl
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// premultiply.glsl
|
||||
|
||||
void main() {
|
||||
vec4 diffuse = GskTexture(u_source, vUv);
|
||||
|
||||
diffuse = gsk_premultiply(diffuse);
|
||||
|
||||
gskSetOutputColor(diffuse);
|
||||
}
|
||||
@@ -335,7 +335,7 @@ gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
|
||||
if (data)
|
||||
return g_object_ref (data->image);
|
||||
|
||||
surface = gdk_texture_download_surface (texture);
|
||||
surface = gdk_texture_download_surface (texture,NULL);
|
||||
image = gsk_vulkan_image_new_from_data (uploader,
|
||||
cairo_image_surface_get_data (surface),
|
||||
cairo_image_surface_get_width (surface),
|
||||
|
||||
@@ -735,24 +735,19 @@ gtk_gl_area_snapshot (GtkWidget *widget,
|
||||
priv->texture = NULL;
|
||||
priv->textures = g_list_prepend (priv->textures, texture);
|
||||
|
||||
texture->holder = gdk_gl_texture_new (priv->context,
|
||||
texture->id,
|
||||
texture->width,
|
||||
texture->height,
|
||||
release_texture, texture);
|
||||
texture->holder = gdk_gl_texture_new_with_color_profile (priv->context,
|
||||
texture->id,
|
||||
texture->width,
|
||||
texture->height,
|
||||
GDK_GL_TEXTURE_PREMULTIPLIED|GDK_GL_TEXTURE_FLIPPED,
|
||||
gdk_color_profile_get_srgb (),
|
||||
release_texture, texture);
|
||||
|
||||
/* Our texture is rendered by OpenGL, so it is upside down,
|
||||
* compared to what GSK expects, so flip it back.
|
||||
*/
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (0, gtk_widget_get_height (widget)));
|
||||
gtk_snapshot_scale (snapshot, 1, -1);
|
||||
gtk_snapshot_append_texture (snapshot,
|
||||
texture->holder,
|
||||
&GRAPHENE_RECT_INIT (0, 0,
|
||||
gtk_widget_get_width (widget),
|
||||
gtk_widget_get_height (widget)));
|
||||
gtk_snapshot_restore (snapshot);
|
||||
|
||||
g_object_unref (texture->holder);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ fribidi_req = '>= 0.19.7'
|
||||
cairo_req = '>= 1.14.0'
|
||||
gdk_pixbuf_req = '>= 2.30.0'
|
||||
introspection_req = '>= 1.39.0'
|
||||
lcms2_req = '>= 2.8'
|
||||
wayland_proto_req = '>= 1.21'
|
||||
wayland_req = '>= 1.16.91'
|
||||
graphene_req = '>= 1.9.1'
|
||||
@@ -379,6 +380,8 @@ pango_dep = dependency('pango', version: pango_req,
|
||||
fallback : ['pango', 'libpango_dep'])
|
||||
fribidi_dep = dependency('fribidi', version: fribidi_req,
|
||||
fallback : ['fribidi', 'libfribidi_dep'])
|
||||
lcms2_dep = dependency('lcms2', version: lcms2_req,
|
||||
fallback : ['lcms2', 'liblcms2_dep'])
|
||||
|
||||
# Require PangoFT2 if on X11 or wayland
|
||||
require_pangoft2 = wayland_enabled or x11_enabled
|
||||
|
||||
@@ -292,12 +292,14 @@ gtk_gst_sink_texture_from_buffer (GtkGstSink *self,
|
||||
gst_gl_sync_meta_wait (sync_meta, self->gst_context);
|
||||
}
|
||||
|
||||
texture = gdk_gl_texture_new (self->gdk_context,
|
||||
*(guint *) frame->data[0],
|
||||
frame->info.width,
|
||||
frame->info.height,
|
||||
(GDestroyNotify) video_frame_free,
|
||||
frame);
|
||||
texture = gdk_gl_texture_new_with_color_profile (self->gdk_context,
|
||||
*(guint *) frame->data[0],
|
||||
frame->info.width,
|
||||
frame->info.height,
|
||||
0, /* Neither premultiplied nor flipped */
|
||||
gdk_color_profile_get_srgb (),
|
||||
(GDestroyNotify) video_frame_free,
|
||||
frame);
|
||||
|
||||
*pixel_aspect_ratio = ((double) frame->info.par_n) / ((double) frame->info.par_d);
|
||||
}
|
||||
|
||||
6
subprojects/lcms2.wrap
Normal file
@@ -0,0 +1,6 @@
|
||||
[wrap-git]
|
||||
directory=lcms2
|
||||
url=https://github.com/mm2/Little-CMS.git
|
||||
revision=master
|
||||
patch_directory=lcms2
|
||||
depth=1
|
||||
14
subprojects/packagefiles/lcms2/meson.build
Normal file
@@ -0,0 +1,14 @@
|
||||
project('lcms2', 'c',
|
||||
version : '2.12',
|
||||
meson_version : '>=0.56.0',
|
||||
)
|
||||
|
||||
mod = import('unstable_external_project')
|
||||
|
||||
p = mod.add_project('configure',
|
||||
configure_options : ['--prefix=@PREFIX@',
|
||||
'--libdir=@PREFIX@/@LIBDIR@',
|
||||
],
|
||||
)
|
||||
|
||||
liblcms2_dep = p.dependency('lcms2')
|
||||