Compare commits
200 Commits
4.4.1
...
ebassi/set
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24b69a9a10 | ||
|
|
043eea6ae3 | ||
|
|
181fce8342 | ||
|
|
db3858a204 | ||
|
|
07bff74544 | ||
|
|
b4262883a8 | ||
|
|
563c85e222 | ||
|
|
d75246a543 | ||
|
|
b3856a3ea0 | ||
|
|
bd4d24f8ed | ||
|
|
65ce3eb207 | ||
|
|
865ac44963 | ||
|
|
55a935db53 | ||
|
|
6fefae3dbb | ||
|
|
f7c84ddc7f | ||
|
|
f4a4dd2615 | ||
|
|
b718d99d1f | ||
|
|
c7215d1199 | ||
|
|
24d69ef125 | ||
|
|
7c3fbdecf2 | ||
|
|
b77938f40f | ||
|
|
f703744564 | ||
|
|
a3ccff3773 | ||
|
|
9869082c1c | ||
|
|
754212d0f9 | ||
|
|
a9b81577c6 | ||
|
|
eaa2dada54 | ||
|
|
ce2b2128bb | ||
|
|
41c25b8809 | ||
|
|
b5ff35ff3e | ||
|
|
06423d807f | ||
|
|
0395395d52 | ||
|
|
c3ca48b249 | ||
|
|
464e0aed04 | ||
|
|
d46e4fcecd | ||
|
|
363fb96e81 | ||
|
|
2382bd3bb2 | ||
|
|
3b0a9e84ab | ||
|
|
850aebea5d | ||
|
|
26e632e549 | ||
|
|
64d2d7074f | ||
|
|
062a15310a | ||
|
|
299c7c3514 | ||
|
|
6599cb001f | ||
|
|
f1347f5841 | ||
|
|
f3ccf62463 | ||
|
|
44fea33c5d | ||
|
|
8b48cf11f9 | ||
|
|
e681fdd958 | ||
|
|
d4b7a78c54 | ||
|
|
a45cbad553 | ||
|
|
16b9a30655 | ||
|
|
82a184a7b7 | ||
|
|
9e198a59b6 | ||
|
|
c002678085 | ||
|
|
486cffc361 | ||
|
|
67495fcc77 | ||
|
|
b26a370ce4 | ||
|
|
4dc0e67ac7 | ||
|
|
2c060663cf | ||
|
|
76a8eb4960 | ||
|
|
ad3dad1965 | ||
|
|
172d97de05 | ||
|
|
4c967d5b45 | ||
|
|
b244f31337 | ||
|
|
8550a04bf4 | ||
|
|
cb38ead48e | ||
|
|
9713c3394d | ||
|
|
fa57b006c9 | ||
|
|
9f73f0234a | ||
|
|
a4f067481c | ||
|
|
733fb527fa | ||
|
|
3667c6b053 | ||
|
|
1071818df8 | ||
|
|
11c2d9ea30 | ||
|
|
52cdf3056d | ||
|
|
32899a1edd | ||
|
|
119458f13e | ||
|
|
2863095f06 | ||
|
|
cbc050b9ed | ||
|
|
18affbd390 | ||
|
|
0b7a36ce33 | ||
|
|
1957915940 | ||
|
|
552b71d4e2 | ||
|
|
480112f9aa | ||
|
|
9a2f4d8026 | ||
|
|
3b15f32335 | ||
|
|
7404a6fc4f | ||
|
|
91d1ec41c2 | ||
|
|
9237c8be67 | ||
|
|
6c87d362c5 | ||
|
|
4f31d3587d | ||
|
|
29a2f4021a | ||
|
|
e2d321a16a | ||
|
|
7366f5099a | ||
|
|
4fbef5f466 | ||
|
|
2e48ff3362 | ||
|
|
7cdbdb663c | ||
|
|
1b390d3857 | ||
|
|
2808f9c75b | ||
|
|
49d109c29e | ||
|
|
36dd959bf9 | ||
|
|
2f9a67b8a1 | ||
|
|
6d5d9ea073 | ||
|
|
1cfd340cae | ||
|
|
369ccfc34f | ||
|
|
e556513de6 | ||
|
|
79dc1a2a4d | ||
|
|
9e5a501c73 | ||
|
|
2db8d7f6a2 | ||
|
|
94c3f4d4fc | ||
|
|
3fa26861cd | ||
|
|
ef2b0ccd6c | ||
|
|
f1702d24e7 | ||
|
|
3a50ff57d8 | ||
|
|
8ac2e8d495 | ||
|
|
e56cf85fd1 | ||
|
|
1c6aef1862 | ||
|
|
4653cbe56e | ||
|
|
93148d302f | ||
|
|
a443ba91ce | ||
|
|
d8daef2de7 | ||
|
|
845d43c77a | ||
|
|
f8dbcc472b | ||
|
|
0f0f75f6b1 | ||
|
|
4e2e2d84fc | ||
|
|
887885b6e0 | ||
|
|
a868a5c434 | ||
|
|
a0c147d246 | ||
|
|
38040c96d6 | ||
|
|
989ecf69ad | ||
|
|
9d26399143 | ||
|
|
b9cad7cc54 | ||
|
|
357b97b5a6 | ||
|
|
318160d836 | ||
|
|
5e90d63373 | ||
|
|
0b7f1e488f | ||
|
|
e281bbbb55 | ||
|
|
892bacee52 | ||
|
|
2f1db4b77c | ||
|
|
f90e9b26f8 | ||
|
|
ad71f454bd | ||
|
|
c66bd791c4 | ||
|
|
40bceef3ca | ||
|
|
9d79f55dc9 | ||
|
|
c5c1cf6d55 | ||
|
|
9eb8aa9a32 | ||
|
|
95931a7e6c | ||
|
|
d9daaed43f | ||
|
|
b9c51e65c1 | ||
|
|
da5eb92f47 | ||
|
|
03ed585f6f | ||
|
|
51f953a1aa | ||
|
|
93fb07d808 | ||
|
|
5e311d4d85 | ||
|
|
e652054d50 | ||
|
|
58c31b8627 | ||
|
|
b945033b41 | ||
|
|
92d2867170 | ||
|
|
5d38c8c558 | ||
|
|
552a4b2c82 | ||
|
|
7a4afb08bd | ||
|
|
c5cd1ac630 | ||
|
|
90edb76415 | ||
|
|
8f397502df | ||
|
|
1cb17d8613 | ||
|
|
88e796bb45 | ||
|
|
1310bf0218 | ||
|
|
4efeaa844f | ||
|
|
24685612a9 | ||
|
|
bf21df4195 | ||
|
|
417b3f9c6b | ||
|
|
2d84a1c63e | ||
|
|
5ab9a29bc4 | ||
|
|
383ea0d86a | ||
|
|
df8f75bb8f | ||
|
|
ba95ef63da | ||
|
|
bea4aa31ea | ||
|
|
6c19a8352f | ||
|
|
e3df89b524 | ||
|
|
a9003f7ac0 | ||
|
|
2cc06f60c5 | ||
|
|
4759afcc3e | ||
|
|
66b297e408 | ||
|
|
bbd2b255a3 | ||
|
|
8b2f28eee3 | ||
|
|
ae767dc5bf | ||
|
|
d923402934 | ||
|
|
9667f889b3 | ||
|
|
d2ea7af335 | ||
|
|
f95e9407a9 | ||
|
|
7be3c2974a | ||
|
|
5444f604cb | ||
|
|
94e68b0e36 | ||
|
|
910d86f958 | ||
|
|
fd885e42b0 | ||
|
|
ea31ae31c1 | ||
|
|
00763e5af3 | ||
|
|
1bf5aab18c | ||
|
|
e9e373913e |
@@ -40,7 +40,7 @@ export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
|
||||
# https://gitlab.gnome.org/GNOME/gtk/-/issues/2243
|
||||
# https://gitlab.gnome.org/GNOME/gtk/-/issues/3002
|
||||
|
||||
if ! pkg-config --atleast-version=2.65.0 glib-2.0; then
|
||||
if ! pkg-config --atleast-version=2.66.0 glib-2.0; then
|
||||
git clone https://gitlab.gnome.org/GNOME/glib.git _glib
|
||||
meson setup _glib_build _glib
|
||||
meson compile -C _glib_build
|
||||
@@ -48,7 +48,7 @@ if ! pkg-config --atleast-version=2.65.0 glib-2.0; then
|
||||
fi
|
||||
pkg-config --modversion glib-2.0
|
||||
|
||||
if ! pkg-config --atleast-version=1.47.0 pango; then
|
||||
if ! pkg-config --atleast-version=1.49.1 pango; then
|
||||
git clone https://gitlab.gnome.org/GNOME/pango.git _pango
|
||||
meson setup _pango_build _pango
|
||||
meson compile -C _pango_build
|
||||
|
||||
92
NEWS
92
NEWS
@@ -1,89 +1,19 @@
|
||||
Overview of Changes in 4.4.1
|
||||
============================
|
||||
Overview of Changes
|
||||
===================
|
||||
|
||||
* input:
|
||||
- Fix compose data on bigendian systems
|
||||
- Accept long replacement strings for compose sequences
|
||||
* gsk:
|
||||
- Drop the GL renderer in favor of NGL
|
||||
|
||||
* a11y:
|
||||
- Fix accessible relations for menu buttons
|
||||
- Fix accessible descriptions in some cases
|
||||
- Simplify atspi context a bit
|
||||
|
||||
* Theme:
|
||||
- Improve styling for toggle buttons in toolbars
|
||||
|
||||
* gsk:
|
||||
- Avoid coordinate overflow with big text selections
|
||||
* css:
|
||||
- Add support for line-height
|
||||
- Add support for text-transform
|
||||
|
||||
* GtkTextView:
|
||||
- Fix applying css properties such as
|
||||
letterspacing, line decoration, font
|
||||
features, etc
|
||||
- Improve grouping for undo
|
||||
- Invalidate Pango contexts when font settings change
|
||||
- Fix a crash
|
||||
- Add support for line height
|
||||
- Add support for text transforms
|
||||
|
||||
* GtkFileChooser:
|
||||
- Fix handling of choices
|
||||
|
||||
* GtkStackSwitcher:
|
||||
- Expand child buttons
|
||||
|
||||
* GtkCalendar:
|
||||
- Fix day names for weeks that start on monday
|
||||
|
||||
* GtkWindow:
|
||||
- Prefer menubars when handling F10
|
||||
|
||||
* GtkFontButton:
|
||||
- Make sure the dialog is on the same display
|
||||
|
||||
* X11:
|
||||
- Fix handling of randr events
|
||||
|
||||
* Windows:
|
||||
- Fix DND coordinates
|
||||
- Fix build
|
||||
|
||||
* macOS:
|
||||
- Fix handling of scale on macOS 12
|
||||
|
||||
* build:
|
||||
- Fix detection of pre-compiled css files
|
||||
|
||||
* Translation updates
|
||||
Basque
|
||||
Brazilian Portuguese
|
||||
Catalan
|
||||
Chinese (China)
|
||||
Croatian
|
||||
Czech
|
||||
Danish
|
||||
Finnish
|
||||
French
|
||||
Galician
|
||||
German
|
||||
Hebrew
|
||||
Hungarian
|
||||
Icelandic
|
||||
Indonesian
|
||||
Kazakh
|
||||
Korean
|
||||
Latvian
|
||||
Lithuanian
|
||||
Persian
|
||||
Polish
|
||||
Portuguese
|
||||
Romanian
|
||||
Russian
|
||||
Serbian
|
||||
Slovak
|
||||
Slovenian
|
||||
Spanish
|
||||
Swedish
|
||||
Turkish
|
||||
Ukrainian
|
||||
* Build:
|
||||
- Require Pango 1.49
|
||||
|
||||
|
||||
Overview of Changes in 4.4.0
|
||||
|
||||
13
README.md
13
README.md
@@ -10,12 +10,10 @@ GTK is a multi-platform toolkit for creating graphical user interfaces.
|
||||
Offering a complete set of widgets, GTK is suitable for projects ranging
|
||||
from small one-off projects to complete application suites.
|
||||
|
||||
GTK is a free and open-source software project. However, the licensing terms
|
||||
for GTK, the GNU LGPL, allow it to be used by all developers, including those
|
||||
developing proprietary software, without any license fees or royalties.
|
||||
|
||||
GTK is hosted by the GNOME project (thanks!) and used by a wide variety
|
||||
of applications and projects.
|
||||
GTK is free software and part of the GNU Project. However, the
|
||||
licensing terms for GTK, the GNU LGPL, allow it to be used by all
|
||||
developers, including those developing proprietary software, without any
|
||||
license fees or royalties.
|
||||
|
||||
The official download location
|
||||
|
||||
@@ -153,9 +151,6 @@ Contributing to GTK
|
||||
Please, follow the [contribution guide](./CONTRIBUTING.md) to know how to
|
||||
start contributing to GTK.
|
||||
|
||||
If you want to support GTK financially, please consider donating to
|
||||
the GNOME project, which runs the infrastructure hosting GTK.
|
||||
|
||||
Release notes
|
||||
-------------
|
||||
|
||||
|
||||
@@ -321,6 +321,7 @@
|
||||
<file>paintable_emblem.c</file>
|
||||
<file>paintable_mediastream.c</file>
|
||||
<file>paintable_svg.c</file>
|
||||
<file>paintable_symbolic.c</file>
|
||||
<file>panes.c</file>
|
||||
<file>password_entry.c</file>
|
||||
<file>peg_solitaire.c</file>
|
||||
|
||||
@@ -131,6 +131,19 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
|
||||
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
|
||||
}
|
||||
|
||||
#define VOID_ATTR(attr_name) \
|
||||
{ \
|
||||
tag = gtk_text_tag_table_lookup (table, #attr_name); \
|
||||
if (!tag) \
|
||||
{ \
|
||||
tag = gtk_text_tag_new (#attr_name); \
|
||||
g_object_set (tag, #attr_name, TRUE, NULL); \
|
||||
gtk_text_tag_table_add (table, tag); \
|
||||
g_object_unref (tag); \
|
||||
} \
|
||||
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
|
||||
}
|
||||
|
||||
fg_alpha = bg_alpha = 1.;
|
||||
|
||||
attrs = pango_attr_iterator_get_attrs (iter);
|
||||
@@ -255,11 +268,28 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
|
||||
INT_ATTR (insert_hyphens);
|
||||
break;
|
||||
|
||||
#if PANGO_VERSION_CHECK(1,49,0)
|
||||
case PANGO_ATTR_LINE_HEIGHT:
|
||||
FLOAT_ATTR (line_height);
|
||||
break;
|
||||
|
||||
case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PANGO_ATTR_WORD:
|
||||
VOID_ATTR (word);
|
||||
break;
|
||||
|
||||
case PANGO_ATTR_SENTENCE:
|
||||
VOID_ATTR (sentence);
|
||||
break;
|
||||
|
||||
case PANGO_ATTR_BASELINE_SHIFT:
|
||||
INT_ATTR (baseline_shift);
|
||||
break;
|
||||
|
||||
case PANGO_ATTR_FONT_SCALE:
|
||||
INT_ATTR (font_scale);
|
||||
break;
|
||||
|
||||
case PANGO_ATTR_SHAPE:
|
||||
case PANGO_ATTR_ABSOLUTE_SIZE:
|
||||
@@ -269,16 +299,9 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
|
||||
case PANGO_ATTR_BACKGROUND_ALPHA:
|
||||
break;
|
||||
|
||||
#if PANGO_VERSION_CHECK(1,49,0)
|
||||
case PANGO_ATTR_TEXT_TRANSFORM:
|
||||
#endif
|
||||
#if PANGO_VERSION_CHECK(1,49,1)
|
||||
case PANGO_ATTR_WORD:
|
||||
case PANGO_ATTR_SENTENCE:
|
||||
case PANGO_ATTR_BASELINE_SHIFT:
|
||||
case PANGO_ATTR_FONT_SCALE:
|
||||
INT_ATTR (text_transform);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PANGO_ATTR_INVALID:
|
||||
default:
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
/* Pango/Font Rendering
|
||||
*
|
||||
* Demonstrates various aspects of font rendering.
|
||||
* Demonstrates various aspects of font rendering,
|
||||
* such as hinting, antialiasing and grid alignment.
|
||||
*
|
||||
* The demo lets you explore font rendering options
|
||||
* interactively to get a feeling for they affect the
|
||||
* shape and positioning of the glyphs.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
@@ -10,16 +15,21 @@ static GtkWidget *font_button = NULL;
|
||||
static GtkWidget *entry = NULL;
|
||||
static GtkWidget *image = NULL;
|
||||
static GtkWidget *hinting = NULL;
|
||||
static GtkWidget *anti_alias = NULL;
|
||||
static GtkWidget *hint_metrics = NULL;
|
||||
static GtkWidget *up_button = NULL;
|
||||
static GtkWidget *down_button = NULL;
|
||||
static GtkWidget *text_radio = NULL;
|
||||
static GtkWidget *show_grid = NULL;
|
||||
static GtkWidget *show_extents = NULL;
|
||||
static GtkWidget *show_pixels = NULL;
|
||||
static GtkWidget *show_outlines = NULL;
|
||||
|
||||
static PangoContext *context;
|
||||
|
||||
static int scale = 9;
|
||||
static int scale = 7;
|
||||
static double pixel_alpha = 1.0;
|
||||
static double outline_alpha = 0.0;
|
||||
|
||||
static void
|
||||
update_image (void)
|
||||
@@ -37,6 +47,8 @@ update_image (void)
|
||||
cairo_font_options_t *fopt;
|
||||
cairo_hint_style_t hintstyle;
|
||||
cairo_hint_metrics_t hintmetrics;
|
||||
cairo_antialias_t antialias;
|
||||
cairo_path_t *path;
|
||||
|
||||
if (!context)
|
||||
context = gtk_widget_create_pango_context (image);
|
||||
@@ -65,6 +77,13 @@ update_image (void)
|
||||
hintmetrics = CAIRO_HINT_METRICS_OFF;
|
||||
cairo_font_options_set_hint_metrics (fopt, hintmetrics);
|
||||
|
||||
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (anti_alias)))
|
||||
antialias = CAIRO_ANTIALIAS_GRAY;
|
||||
else
|
||||
antialias = CAIRO_ANTIALIAS_NONE;
|
||||
cairo_font_options_set_antialias (fopt, antialias);
|
||||
|
||||
pango_context_set_round_glyph_positions (context, hintmetrics == CAIRO_HINT_METRICS_ON);
|
||||
pango_cairo_context_set_font_options (context, fopt);
|
||||
cairo_font_options_destroy (fopt);
|
||||
pango_context_changed (context);
|
||||
@@ -85,10 +104,14 @@ update_image (void)
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
cairo_set_source_rgba (cr, 0, 0, 0, pixel_alpha);
|
||||
|
||||
cairo_move_to (cr, 10, 10);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
pango_cairo_layout_path (cr, layout);
|
||||
path = cairo_copy_path (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
g_object_unref (layout);
|
||||
|
||||
@@ -127,7 +150,7 @@ update_image (void)
|
||||
|
||||
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (show_extents)))
|
||||
{
|
||||
cairo_set_source_rgba (cr, 0, 0, 1, 1);
|
||||
cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
|
||||
cairo_rectangle (cr,
|
||||
scale * (10 + pango_units_to_double (logical.x)) - 0.5,
|
||||
@@ -140,7 +163,7 @@ update_image (void)
|
||||
cairo_line_to (cr, scale * (10 + pango_units_to_double (logical.x + logical.width)) + 1,
|
||||
scale * (10 + pango_units_to_double (baseline)) - 0.5);
|
||||
cairo_stroke (cr);
|
||||
cairo_set_source_rgba (cr, 1, 0, 0, 1);
|
||||
cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
cairo_rectangle (cr,
|
||||
scale * (10 + pango_units_to_double (pink.x)) + 0.5,
|
||||
scale * (10 + pango_units_to_double (pink.y)) + 0.5,
|
||||
@@ -149,8 +172,36 @@ update_image (void)
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
for (int i = 0; i < path->num_data; i += path->data[i].header.length)
|
||||
{
|
||||
cairo_path_data_t *data = &path->data[i];
|
||||
switch (data->header.type)
|
||||
{
|
||||
case CAIRO_PATH_CURVE_TO:
|
||||
data[3].point.x *= scale; data[3].point.y *= scale;
|
||||
data[2].point.x *= scale; data[2].point.y *= scale;
|
||||
data[1].point.x *= scale; data[1].point.y *= scale;
|
||||
break;
|
||||
case CAIRO_PATH_LINE_TO:
|
||||
case CAIRO_PATH_MOVE_TO:
|
||||
data[1].point.x *= scale; data[1].point.y *= scale;
|
||||
break;
|
||||
case CAIRO_PATH_CLOSE_PATH:
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
cairo_set_source_rgba (cr, 0, 0, 1, outline_alpha);
|
||||
cairo_move_to (cr, scale * 20 - 0.5, scale * 20 - 0.5);
|
||||
cairo_append_path (cr, path);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
cairo_destroy (cr);
|
||||
|
||||
cairo_path_destroy (path);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -158,10 +209,26 @@ update_image (void)
|
||||
PangoLayoutRun *run;
|
||||
PangoGlyphInfo *g;
|
||||
int i, j;
|
||||
GString *str;
|
||||
gunichar ch;
|
||||
|
||||
if (*text == '\0')
|
||||
text = " ";
|
||||
|
||||
ch = g_utf8_get_char (text);
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
g_string_append_unichar (str, ch);
|
||||
g_string_append_unichar (str, 0x200c);
|
||||
}
|
||||
|
||||
layout = pango_layout_new (context);
|
||||
pango_layout_set_font_description (layout, desc);
|
||||
pango_layout_set_text (layout, "aaaa", -1);
|
||||
pango_layout_set_text (layout, str->str, -1);
|
||||
g_string_free (str, TRUE);
|
||||
pango_layout_get_extents (layout, &ink, &logical);
|
||||
pango_extents_to_pixels (&logical, NULL);
|
||||
|
||||
@@ -176,7 +243,7 @@ update_image (void)
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
g = &(run->glyphs->glyphs[i]);
|
||||
g = &(run->glyphs->glyphs[2*i]);
|
||||
g->geometry.width = PANGO_UNITS_ROUND (g->geometry.width * 3 / 2);
|
||||
}
|
||||
|
||||
@@ -184,7 +251,7 @@ update_image (void)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
g = &(run->glyphs->glyphs[i]);
|
||||
g = &(run->glyphs->glyphs[2*i]);
|
||||
g->geometry.x_offset = i * (PANGO_SCALE / 4);
|
||||
g->geometry.y_offset = j * (PANGO_SCALE / 4);
|
||||
}
|
||||
@@ -203,7 +270,6 @@ update_image (void)
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
|
||||
gtk_picture_set_pixbuf (GTK_PICTURE (image), pixbuf2);
|
||||
|
||||
g_object_unref (pixbuf2);
|
||||
@@ -211,6 +277,78 @@ update_image (void)
|
||||
pango_font_description_free (desc);
|
||||
}
|
||||
|
||||
static gboolean fading = FALSE;
|
||||
static double start_pixel_alpha;
|
||||
static double end_pixel_alpha;
|
||||
static double start_outline_alpha;
|
||||
static double end_outline_alpha;
|
||||
static gint64 start_time;
|
||||
static gint64 end_time;
|
||||
|
||||
static double
|
||||
ease_out_cubic (double t)
|
||||
{
|
||||
double p = t - 1;
|
||||
return p * p * p + 1;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
change_alpha (GtkWidget *widget,
|
||||
GdkFrameClock *clock,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint64 now = g_get_monotonic_time ();
|
||||
double t;
|
||||
|
||||
t = ease_out_cubic ((now - start_time) / (double) (end_time - start_time));
|
||||
|
||||
pixel_alpha = start_pixel_alpha + (end_pixel_alpha - start_pixel_alpha) * t;
|
||||
outline_alpha = start_outline_alpha + (end_outline_alpha - start_outline_alpha) * t;
|
||||
|
||||
update_image ();
|
||||
|
||||
if (now >= end_time)
|
||||
{
|
||||
fading = FALSE;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
start_alpha_fade (void)
|
||||
{
|
||||
gboolean pixels;
|
||||
gboolean outlines;
|
||||
|
||||
if (fading)
|
||||
return;
|
||||
|
||||
pixels = gtk_check_button_get_active (GTK_CHECK_BUTTON (show_pixels));
|
||||
outlines = gtk_check_button_get_active (GTK_CHECK_BUTTON (show_outlines));
|
||||
|
||||
start_pixel_alpha = pixel_alpha;
|
||||
if (pixels && outlines)
|
||||
end_pixel_alpha = 0.5;
|
||||
else if (pixels)
|
||||
end_pixel_alpha = 1;
|
||||
else
|
||||
end_pixel_alpha = 0;
|
||||
|
||||
start_outline_alpha = outline_alpha;
|
||||
if (outlines)
|
||||
end_outline_alpha = 1.0;
|
||||
else
|
||||
end_outline_alpha = 0.0;
|
||||
|
||||
start_time = g_get_monotonic_time ();
|
||||
end_time = start_time + G_TIME_SPAN_SECOND / 2;
|
||||
|
||||
fading = TRUE;
|
||||
gtk_widget_add_tick_callback (window, change_alpha, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
update_buttons (void)
|
||||
{
|
||||
@@ -218,20 +356,26 @@ update_buttons (void)
|
||||
gtk_widget_set_sensitive (down_button, scale > 1);
|
||||
}
|
||||
|
||||
static void
|
||||
scale_up (void)
|
||||
static gboolean
|
||||
scale_up (GtkWidget *widget,
|
||||
GVariant *args,
|
||||
gpointer user_data)
|
||||
{
|
||||
scale += 1;
|
||||
update_buttons ();
|
||||
update_image ();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
scale_down (void)
|
||||
static gboolean
|
||||
scale_down (GtkWidget *widget,
|
||||
GVariant *args,
|
||||
gpointer user_data)
|
||||
{
|
||||
scale -= 1;
|
||||
update_buttons ();
|
||||
update_image ();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@@ -252,20 +396,26 @@ do_fontrendering (GtkWidget *do_widget)
|
||||
entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry"));
|
||||
image = GTK_WIDGET (gtk_builder_get_object (builder, "image"));
|
||||
hinting = GTK_WIDGET (gtk_builder_get_object (builder, "hinting"));
|
||||
anti_alias = GTK_WIDGET (gtk_builder_get_object (builder, "antialias"));
|
||||
hint_metrics = GTK_WIDGET (gtk_builder_get_object (builder, "hint_metrics"));
|
||||
text_radio = GTK_WIDGET (gtk_builder_get_object (builder, "text_radio"));
|
||||
show_grid = GTK_WIDGET (gtk_builder_get_object (builder, "show_grid"));
|
||||
show_extents = GTK_WIDGET (gtk_builder_get_object (builder, "show_extents"));
|
||||
show_pixels = GTK_WIDGET (gtk_builder_get_object (builder, "show_pixels"));
|
||||
show_outlines = GTK_WIDGET (gtk_builder_get_object (builder, "show_outlines"));
|
||||
|
||||
g_signal_connect (up_button, "clicked", G_CALLBACK (scale_up), NULL);
|
||||
g_signal_connect (down_button, "clicked", G_CALLBACK (scale_down), NULL);
|
||||
g_signal_connect (entry, "notify::text", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (font_button, "notify::font-desc", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (hinting, "notify::active", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (anti_alias, "notify::active", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (hint_metrics, "notify::active", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (text_radio, "notify::active", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (show_grid, "notify::active", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (show_extents, "notify::active", G_CALLBACK (update_image), NULL);
|
||||
g_signal_connect (show_pixels, "notify::active", G_CALLBACK (start_alpha_fade), NULL);
|
||||
g_signal_connect (show_outlines, "notify::active", G_CALLBACK (start_alpha_fade), NULL);
|
||||
|
||||
update_image ();
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkAdjustment" id="scale_adj">
|
||||
<property name="upper">24</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">4</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="default-width">1080</property>
|
||||
<property name="default-height">430</property>
|
||||
<property name="default-width">1024</property>
|
||||
<property name="default-height">768</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<child type="title">
|
||||
@@ -87,35 +82,62 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Hinting</property>
|
||||
<property name="xalign">1</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<object class="GtkCheckButton" id="show_pixels">
|
||||
<property name="label">Show _Pixels</property>
|
||||
<property name="use-underline">1</property>
|
||||
<property name="active">1</property>
|
||||
<layout>
|
||||
<property name="column">3</property>
|
||||
<property name="row">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="hinting">
|
||||
<property name="active">0</property>
|
||||
<property name="valign">center</property>
|
||||
<items>
|
||||
<item translatable="yes" id="none">None</item>
|
||||
<item translatable="yes" id="slight">Slight</item>
|
||||
<item translatable="yes" id="medium">Medium</item>
|
||||
<item translatable="yes" id="full">Full</item>
|
||||
</items>
|
||||
<object class="GtkCheckButton" id="show_outlines">
|
||||
<property name="label">Show _Outline</property>
|
||||
<property name="use-underline">1</property>
|
||||
<layout>
|
||||
<property name="column">3</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">_Hinting</property>
|
||||
<property name="use-underline">1</property>
|
||||
<property name="mnemonic-widget">hinting</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="hinting">
|
||||
<property name="active">0</property>
|
||||
<property name="valign">center</property>
|
||||
<items>
|
||||
<item translatable="yes" id="none">None</item>
|
||||
<item translatable="yes" id="slight">Slight</item>
|
||||
<item translatable="yes" id="medium">Medium</item>
|
||||
<item translatable="yes" id="full">Full</item>
|
||||
</items>
|
||||
</object>
|
||||
</child>
|
||||
<layout>
|
||||
<property name="column">4</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="hint_metrics">
|
||||
<property name="label">Hint Metrics</property>
|
||||
<object class="GtkCheckButton" id="antialias">
|
||||
<property name="label">_Antialias</property>
|
||||
<property name="use-underline">1</property>
|
||||
<property name="active">1</property>
|
||||
<layout>
|
||||
<property name="column">4</property>
|
||||
<property name="row">1</property>
|
||||
@@ -123,21 +145,31 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="show_extents">
|
||||
<property name="label">Show Extents</property>
|
||||
<property name="active">1</property>
|
||||
<object class="GtkCheckButton" id="hint_metrics">
|
||||
<property name="label">Hint _Metrics</property>
|
||||
<property name="use-underline">1</property>
|
||||
<layout>
|
||||
<property name="column">5</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="show_extents">
|
||||
<property name="label">Show _Extents</property>
|
||||
<property name="use-underline">1</property>
|
||||
<layout>
|
||||
<property name="column">6</property>
|
||||
<property name="row">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="show_grid">
|
||||
<property name="active">1</property>
|
||||
<property name="label">Show Grid</property>
|
||||
<property name="label">Show _Grid</property>
|
||||
<property name="use-underline">1</property>
|
||||
<layout>
|
||||
<property name="column">5</property>
|
||||
<property name="column">6</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
@@ -148,8 +180,19 @@
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkShortcutController">
|
||||
<property name="scope">managed</property>
|
||||
<child>
|
||||
<object class="GtkShortcut">
|
||||
<property name="trigger"><Control>plus</property>
|
||||
<property name="action">activate</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<layout>
|
||||
<property name="column">6</property>
|
||||
<property name="column">7</property>
|
||||
<property name="row">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
@@ -160,8 +203,19 @@
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkShortcutController">
|
||||
<property name="scope">managed</property>
|
||||
<child>
|
||||
<object class="GtkShortcut">
|
||||
<property name="trigger"><Control>minus</property>
|
||||
<property name="action">activate</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<layout>
|
||||
<property name="column">6</property>
|
||||
<property name="column">7</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
@@ -170,7 +224,7 @@
|
||||
<object class="GtkLabel">
|
||||
<property name="hexpand">1</property>
|
||||
<layout>
|
||||
<property name="column">7</property>
|
||||
<property name="column">8</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
@@ -58,7 +58,7 @@ do_markup (GtkWidget *do_widget)
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 450, 450);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 600, 680);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
stack = gtk_stack_new ();
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
|
||||
Text sizes: <span size="xx-small">tiny</span> <span size="x-small">very small</span> <span size="small">small</span> <span size="medium">normal</span> <span size="large">large</span> <span size="x-large">very large</span> <span size="xx-large">huge</span>
|
||||
Text sizes: <span size="xx-small">tiny </span><span size="x-small">very small </span><span size="small">small </span><span size="medium">normal </span><span size="large">large </span><span size="x-large">very large </span><span size="xx-large">huge</span>
|
||||
|
||||
Text styles: <span style="normal">Normal</span> <span style="italic">Italic</span> <span style="oblique">Olique</span>
|
||||
|
||||
Text weights: <span weight="thin">thin</span> <span weight="light">light</span> <span weight="normal">normal</span> <span weight="bold">bold</span> <span weight="ultraheavy">ultraheavy</span>
|
||||
|
||||
Text <span color="gray">c<span color="green">o</span>l<span color="tomato">o</span>rs</span> and <span background="pink">backgrounds</span>
|
||||
|
||||
@@ -15,6 +19,12 @@ OpenType font features: <span font_desc="sans regular" font_features="dlig=0">fe
|
||||
|
||||
Shortcuts: <tt>Monospace</tt> – <b>Bold</b> – <i>Italic</i> – <big>Big</big> – <small>Small</small> – <u>Underlined</u> – <s>Strikethrough</s> – Super<sup>script</sup> – Sub<sub>script</sub>
|
||||
|
||||
<span allow_breaks="false">A</span> hyphenation algorithm is a set of rules, especially one codified for implementation in a computer program, that decides at which points a word can be broken over two lines with a hyphen. For example, a hyphenation algorithm might decide that impeachment can be broken as <span allow_breaks="false">impeach‧ment</span> or <span allow_breaks="false">im‧peachment</span> but not <span allow_breaks="false">impe‧achment.</span>
|
||||
hyphenation algorithm is a <span allow_breaks="false" style="italic">set of rules</span>, especially one codified for implementation in a computer program, that decides at which points a word can be broken over two lines with a hyphen. For example, a hyphenation algorithm might decide that impeachment can be broken as impeach‧ment or im‧peachment but not impe‧achment.
|
||||
|
||||
<span insert_hyphens="false">one/two three/four five/six seven/eight nine/ten</span>
|
||||
|
||||
<span line_height='1.33'>Line height: This is an example of widely spaced text. It was achieved by setting the line-height factor to 1.33. You can set the line-height factor to any value between 0 and 10.
|
||||
Note that the line height affects the spacing between paragraphs as well as between the wrapped lines inside a paragraph.</span>
|
||||
|
||||
Transforms: <span text_transform='uppercase'>straße</span> <span text_transform='capitalize'>up, up and away</span>
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ demos = files([
|
||||
'paintable_animated.c',
|
||||
'paintable_emblem.c',
|
||||
'paintable_mediastream.c',
|
||||
'paintable_symbolic.c',
|
||||
'panes.c',
|
||||
'password_entry.c',
|
||||
'peg_solitaire.c',
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<developer_name>Matthias Clasen and others</developer_name>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<releases>
|
||||
<release version="@BUILD_VERSION@">
|
||||
<release version="@BUILD_VERSION@" date="@BUILD_DATE@">
|
||||
<description>
|
||||
<p>A new build of GTK.</p>
|
||||
</description>
|
||||
|
||||
@@ -45,26 +45,27 @@ struct _GtkNuclearIconClass
|
||||
* so that it can be called from all the other demos, too.
|
||||
*/
|
||||
void
|
||||
gtk_nuclear_snapshot (GtkSnapshot *snapshot,
|
||||
double width,
|
||||
double height,
|
||||
double rotation,
|
||||
gboolean draw_background)
|
||||
gtk_nuclear_snapshot (GtkSnapshot *snapshot,
|
||||
const GdkRGBA *foreground,
|
||||
const GdkRGBA *background,
|
||||
double width,
|
||||
double height,
|
||||
double rotation)
|
||||
{
|
||||
#define RADIUS 0.3
|
||||
cairo_t *cr;
|
||||
double size;
|
||||
|
||||
if (draw_background)
|
||||
gtk_snapshot_append_color (snapshot,
|
||||
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 },
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_append_color (snapshot,
|
||||
background,
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
size = MIN (width, height);
|
||||
cr = gtk_snapshot_append_cairo (snapshot,
|
||||
&GRAPHENE_RECT_INIT ((width - size) / 2.0,
|
||||
(height - size) / 2.0,
|
||||
size, size));
|
||||
gdk_cairo_set_source_rgba (cr, foreground);
|
||||
cairo_translate (cr, width / 2.0, height / 2.0);
|
||||
cairo_scale (cr, size, size);
|
||||
cairo_rotate (cr, rotation);
|
||||
@@ -94,9 +95,10 @@ gtk_nuclear_icon_snapshot (GdkPaintable *paintable,
|
||||
*/
|
||||
|
||||
gtk_nuclear_snapshot (snapshot,
|
||||
&(GdkRGBA) { 0, 0, 0, 1 }, /* black */
|
||||
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 }, /* yellow */
|
||||
width, height,
|
||||
nuclear->rotation,
|
||||
TRUE);
|
||||
nuclear->rotation);
|
||||
}
|
||||
|
||||
static GdkPaintableFlags
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
void gtk_nuclear_snapshot (GtkSnapshot *snapshot,
|
||||
const GdkRGBA *foreground,
|
||||
const GdkRGBA *background,
|
||||
double width,
|
||||
double height,
|
||||
double rotation,
|
||||
gboolean draw_background);
|
||||
double rotation);
|
||||
|
||||
GdkPaintable * gtk_nuclear_icon_new (double rotation);
|
||||
GdkPaintable * gtk_nuclear_animation_new (gboolean draw_background);
|
||||
|
||||
@@ -65,9 +65,12 @@ gtk_nuclear_animation_snapshot (GdkPaintable *paintable,
|
||||
|
||||
/* We call the function from the previous example here. */
|
||||
gtk_nuclear_snapshot (snapshot,
|
||||
&(GdkRGBA) { 0, 0, 0, 1 }, /* black */
|
||||
nuclear->draw_background
|
||||
? &(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 } /* yellow */
|
||||
: &(GdkRGBA) { 0, 0, 0, 0 }, /* transparent */
|
||||
width, height,
|
||||
2 * G_PI * nuclear->progress / MAX_PROGRESS,
|
||||
nuclear->draw_background);
|
||||
2 * G_PI * nuclear->progress / MAX_PROGRESS);
|
||||
}
|
||||
|
||||
static GdkPaintable *
|
||||
|
||||
@@ -73,9 +73,10 @@ gtk_nuclear_media_stream_snapshot (GdkPaintable *paintable,
|
||||
|
||||
/* We call the function from the previous example here. */
|
||||
gtk_nuclear_snapshot (snapshot,
|
||||
&(GdkRGBA) { 0, 0, 0, 1 }, /* black */
|
||||
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 }, /* yellow */
|
||||
width, height,
|
||||
2 * G_PI * nuclear->progress / DURATION,
|
||||
TRUE);
|
||||
2 * G_PI * nuclear->progress / DURATION);
|
||||
}
|
||||
|
||||
static GdkPaintable *
|
||||
|
||||
208
demos/gtk-demo/paintable_symbolic.c
Normal file
208
demos/gtk-demo/paintable_symbolic.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/* Paintable/Symbolic Paintable
|
||||
*
|
||||
* GdkPaintables can be made to follow the theme's colors. GTK calls
|
||||
* icons that do this symbolic icons, paintables that want to have
|
||||
* the same effect can implement the GtkSymbolicPaintable interface.
|
||||
*
|
||||
* We will adapt the original paintable example by adding the ability
|
||||
* to recolor the paintable based on the symbolic colors.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "paintable.h"
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
/* First, add the boilerplate for the object itself.
|
||||
* This part would normally go in the header.
|
||||
*/
|
||||
#define GTK_TYPE_NUCLEAR_SYMBOLIC (gtk_nuclear_symbolic_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkNuclearSymbolic, gtk_nuclear_symbolic, GTK, NUCLEAR_SYMBOLIC, GObject)
|
||||
|
||||
/* Declare a few warning levels, so we can pick colors based on them */
|
||||
typedef enum
|
||||
{
|
||||
WARNING_NONE,
|
||||
WARNING_ALERT,
|
||||
WARNING_EMERGENCY
|
||||
} WarningLevel;
|
||||
|
||||
/* Declare the struct. */
|
||||
struct _GtkNuclearSymbolic
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
WarningLevel warning_level;
|
||||
};
|
||||
|
||||
struct _GtkNuclearSymbolicClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* Add a function to draw the nuclear icon in the given colors */
|
||||
static void
|
||||
gtk_nuclear_symbolic_snapshot_symbolic (GtkSymbolicPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height,
|
||||
const GdkRGBA *colors,
|
||||
gsize n_colors)
|
||||
{
|
||||
GtkNuclearSymbolic *self = GTK_NUCLEAR_SYMBOLIC (paintable);
|
||||
static const GdkRGBA transparent = { 0, };
|
||||
const GdkRGBA *bg_color;
|
||||
|
||||
/* select the right background color from the warning level */
|
||||
switch (self->warning_level)
|
||||
{
|
||||
case WARNING_NONE:
|
||||
bg_color = &transparent;
|
||||
break;
|
||||
case WARNING_ALERT:
|
||||
bg_color = &colors[GTK_SYMBOLIC_COLOR_WARNING];
|
||||
break;
|
||||
case WARNING_EMERGENCY:
|
||||
bg_color = &colors[GTK_SYMBOLIC_COLOR_ERROR];
|
||||
break;
|
||||
default:
|
||||
/* This should never happen, but we better do defensive coding
|
||||
* with this critical icon */
|
||||
g_assert_not_reached ();
|
||||
bg_color = &transparent;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Draw the icon with the selected warning color */
|
||||
gtk_nuclear_snapshot (snapshot,
|
||||
&colors[GTK_SYMBOLIC_COLOR_FOREGROUND],
|
||||
bg_color,
|
||||
width, height,
|
||||
0);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_nuclear_symbolic_symbolic_paintable_init (GtkSymbolicPaintableInterface *iface)
|
||||
{
|
||||
iface->snapshot_symbolic = gtk_nuclear_symbolic_snapshot_symbolic;
|
||||
}
|
||||
|
||||
/* We need to implement the functionality required by the GdkPaintable interface */
|
||||
static void
|
||||
gtk_nuclear_symbolic_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
/* Calling this function without passing a color is a neat trick
|
||||
* to make GTK use default colors and otherwise forward the call
|
||||
* to the snapshotting function above.
|
||||
*/
|
||||
gtk_symbolic_paintable_snapshot_symbolic (GTK_SYMBOLIC_PAINTABLE (paintable),
|
||||
snapshot,
|
||||
width, height,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
static GdkPaintableFlags
|
||||
gtk_nuclear_symbolic_get_flags (GdkPaintable *paintable)
|
||||
{
|
||||
/* This image has a static size, but the contents may change:
|
||||
* We draw different things when the warning level changes.
|
||||
*/
|
||||
return GDK_PAINTABLE_STATIC_SIZE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_nuclear_symbolic_paintable_init (GdkPaintableInterface *iface)
|
||||
{
|
||||
iface->snapshot = gtk_nuclear_symbolic_snapshot;
|
||||
iface->get_flags = gtk_nuclear_symbolic_get_flags;
|
||||
}
|
||||
|
||||
/* When defining the GType, we need to implement bot the GdkPaintable
|
||||
* and the GtkSymbolicPaintable interface */
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkNuclearSymbolic, gtk_nuclear_symbolic, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
||||
gtk_nuclear_symbolic_paintable_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SYMBOLIC_PAINTABLE,
|
||||
gtk_nuclear_symbolic_symbolic_paintable_init))
|
||||
|
||||
static void
|
||||
gtk_nuclear_symbolic_class_init (GtkNuclearSymbolicClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_nuclear_symbolic_init (GtkNuclearSymbolic *nuclear)
|
||||
{
|
||||
}
|
||||
|
||||
/* And finally, we add the simple constructor we declared in the header. */
|
||||
GdkPaintable *
|
||||
gtk_nuclear_symbolic_new (void)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_NUCLEAR_SYMBOLIC, NULL);
|
||||
}
|
||||
|
||||
/* Add some fun feature to the button */
|
||||
static void
|
||||
nuclear_button_clicked (GtkButton *button,
|
||||
GtkNuclearSymbolic *nuclear)
|
||||
{
|
||||
if (nuclear->warning_level >= WARNING_EMERGENCY)
|
||||
{
|
||||
/* On maximum warning level, reset the warning */
|
||||
nuclear->warning_level = WARNING_NONE;
|
||||
/* And sometimes (but not always to confuse people)
|
||||
* close the window.
|
||||
*/
|
||||
if (g_random_boolean ())
|
||||
gtk_window_close (GTK_WINDOW (window));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise just increase the warning level */
|
||||
nuclear->warning_level++;
|
||||
}
|
||||
|
||||
/* Don't forget to emit the signal causing the paintable to redraw.
|
||||
* Changing the warning level changes the background color after all.
|
||||
*/
|
||||
gdk_paintable_invalidate_contents (GDK_PAINTABLE (nuclear));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_paintable_symbolic (GtkWidget *do_widget)
|
||||
{
|
||||
GdkPaintable *nuclear;
|
||||
GtkWidget *image, *button;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Don't click!");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
button = gtk_button_new ();
|
||||
gtk_window_set_child (GTK_WINDOW (window), button);
|
||||
|
||||
nuclear = gtk_nuclear_symbolic_new ();
|
||||
image = gtk_image_new_from_paintable (nuclear);
|
||||
|
||||
gtk_button_set_child (GTK_BUTTON (button), image);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (nuclear_button_clicked), nuclear);
|
||||
g_object_unref (nuclear);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
<developer_name>Matthias Clasen and others</developer_name>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<releases>
|
||||
<release version="@BUILD_VERSION@">
|
||||
<release version="@BUILD_VERSION@" date="@BUILD_DATE@">
|
||||
<description>
|
||||
<p>A new build of GTK.</p>
|
||||
</description>
|
||||
|
||||
@@ -12,9 +12,19 @@ demo_conf_h = declare_dependency(
|
||||
)
|
||||
|
||||
# appdata
|
||||
today = 'unknown'
|
||||
date = find_program('date',
|
||||
required: false)
|
||||
if date.found()
|
||||
r = run_command(date, '-I')
|
||||
if r.returncode() == 0
|
||||
today = r.stdout().strip()
|
||||
endif
|
||||
endif
|
||||
|
||||
appdata_config = configuration_data()
|
||||
appdata_config.set('BUILD_VERSION', meson.project_version())
|
||||
appdata_config.set('BUILD_DATE', today)
|
||||
|
||||
subdir('constraint-editor')
|
||||
subdir('gtk-demo')
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "gtkrendererpaintableprivate.h"
|
||||
|
||||
#include "gsk/gskrendernodeparserprivate.h"
|
||||
#include "gsk/gl/gskglrenderer.h"
|
||||
#include "gsk/ngl/gsknglrenderer.h"
|
||||
#ifdef GDK_WINDOWING_BROADWAY
|
||||
#include "gsk/broadway/gskbroadwayrenderer.h"
|
||||
@@ -61,7 +60,7 @@ struct _NodeEditorWindow
|
||||
|
||||
GtkWidget *renderer_listbox;
|
||||
GListStore *renderers;
|
||||
GdkPaintable *paintable;
|
||||
GskRenderNode *node;
|
||||
|
||||
GFileMonitor *file_monitor;
|
||||
|
||||
@@ -168,7 +167,6 @@ static void
|
||||
text_changed (GtkTextBuffer *buffer,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
GskRenderNode *node;
|
||||
char *text;
|
||||
GBytes *bytes;
|
||||
GtkTextIter iter;
|
||||
@@ -179,10 +177,12 @@ text_changed (GtkTextBuffer *buffer,
|
||||
text_buffer_remove_all_tags (self->text_buffer);
|
||||
bytes = g_bytes_new_take (text, strlen (text));
|
||||
|
||||
g_clear_pointer (&self->node, gsk_render_node_unref);
|
||||
|
||||
/* If this is too slow, go fix the parser performance */
|
||||
node = gsk_render_node_deserialize (bytes, deserialize_error_func, self);
|
||||
self->node = gsk_render_node_deserialize (bytes, deserialize_error_func, self);
|
||||
g_bytes_unref (bytes);
|
||||
if (node)
|
||||
if (self->node)
|
||||
{
|
||||
/* XXX: Is this code necessary or can we have API to turn nodes into paintables? */
|
||||
GtkSnapshot *snapshot;
|
||||
@@ -191,10 +191,9 @@ text_changed (GtkTextBuffer *buffer,
|
||||
guint i;
|
||||
|
||||
snapshot = gtk_snapshot_new ();
|
||||
gsk_render_node_get_bounds (node, &bounds);
|
||||
gsk_render_node_get_bounds (self->node, &bounds);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- bounds.origin.x, - bounds.origin.y));
|
||||
gtk_snapshot_append_node (snapshot, node);
|
||||
gsk_render_node_unref (node);
|
||||
gtk_snapshot_append_node (snapshot, self->node);
|
||||
paintable = gtk_snapshot_free_to_paintable (snapshot, &bounds.size);
|
||||
gtk_picture_set_paintable (GTK_PICTURE (self->picture), paintable);
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->renderers)); i++)
|
||||
@@ -338,15 +337,9 @@ text_view_query_tooltip_cb (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_file_contents (NodeEditorWindow *self,
|
||||
GFile *file)
|
||||
load_bytes (NodeEditorWindow *self,
|
||||
GBytes *bytes)
|
||||
{
|
||||
GBytes *bytes;
|
||||
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, NULL);
|
||||
if (bytes == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL))
|
||||
{
|
||||
g_bytes_unref (bytes);
|
||||
@@ -362,6 +355,105 @@ load_file_contents (NodeEditorWindow *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_file_contents (NodeEditorWindow *self,
|
||||
GFile *file)
|
||||
{
|
||||
GBytes *bytes;
|
||||
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, NULL);
|
||||
if (bytes == NULL)
|
||||
return FALSE;
|
||||
|
||||
return load_bytes (self, bytes);
|
||||
}
|
||||
|
||||
static GdkContentProvider *
|
||||
on_picture_drag_prepare_cb (GtkDragSource *source,
|
||||
double x,
|
||||
double y,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
if (self->node == NULL)
|
||||
return NULL;
|
||||
|
||||
return gdk_content_provider_new_typed (GSK_TYPE_RENDER_NODE, self->node);
|
||||
}
|
||||
|
||||
static void
|
||||
on_picture_drop_read_done_cb (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
NodeEditorWindow *self = data;
|
||||
GOutputStream *stream = G_OUTPUT_STREAM (source);
|
||||
GdkDrop *drop = g_object_get_data (source, "drop");
|
||||
GdkDragAction action = 0;
|
||||
GBytes *bytes;
|
||||
|
||||
if (g_output_stream_splice_finish (stream, res, NULL) >= 0)
|
||||
{
|
||||
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream));
|
||||
if (load_bytes (self, bytes))
|
||||
action = GDK_ACTION_COPY;
|
||||
}
|
||||
|
||||
g_object_unref (self);
|
||||
gdk_drop_finish (drop, action);
|
||||
g_object_unref (drop);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
on_picture_drop_read_cb (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
NodeEditorWindow *self = data;
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
GInputStream *input;
|
||||
GOutputStream *output;
|
||||
|
||||
input = gdk_drop_read_finish (drop, res, NULL, NULL);
|
||||
if (input == NULL)
|
||||
{
|
||||
g_object_unref (self);
|
||||
gdk_drop_finish (drop, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
output = g_memory_output_stream_new_resizable ();
|
||||
g_object_set_data (G_OBJECT (output), "drop", drop);
|
||||
g_object_ref (drop);
|
||||
|
||||
g_output_stream_splice_async (output,
|
||||
input,
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
on_picture_drop_read_done_cb,
|
||||
self);
|
||||
g_object_unref (output);
|
||||
g_object_unref (input);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_picture_drop_cb (GtkDropTargetAsync *dest,
|
||||
GdkDrop *drop,
|
||||
double x,
|
||||
double y,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
gdk_drop_read_async (drop,
|
||||
(const char *[2]) { "application/x-gtk-render-node", NULL },
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
on_picture_drop_read_cb,
|
||||
g_object_ref (self));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
file_changed_cb (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
@@ -736,6 +828,7 @@ node_editor_window_finalize (GObject *object)
|
||||
|
||||
g_array_free (self->errors, TRUE);
|
||||
|
||||
g_clear_pointer (&self->node, gsk_render_node_unref);
|
||||
g_clear_object (&self->renderers);
|
||||
|
||||
G_OBJECT_CLASS (node_editor_window_parent_class)->finalize (object);
|
||||
@@ -778,12 +871,9 @@ node_editor_window_realize (GtkWidget *widget)
|
||||
NULL,
|
||||
"Default");
|
||||
#endif
|
||||
node_editor_window_add_renderer (self,
|
||||
gsk_gl_renderer_new (),
|
||||
"OpenGL");
|
||||
node_editor_window_add_renderer (self,
|
||||
gsk_ngl_renderer_new (),
|
||||
"NGL");
|
||||
"OpenGL");
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
node_editor_window_add_renderer (self,
|
||||
gsk_vulkan_renderer_new (),
|
||||
@@ -848,6 +938,8 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
|
||||
gtk_widget_class_bind_template_callback (widget_class, testcase_save_clicked_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, testcase_name_entry_changed_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, dark_mode_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, on_picture_drag_prepare_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, on_picture_drop_cb);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
|
||||
@@ -200,6 +200,19 @@
|
||||
<property name="can-shrink">0</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<property name="actions">copy</property>
|
||||
<signal name="prepare" handler="on_picture_drag_prepare_cb" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropTargetAsync">
|
||||
<property name="actions">copy</property>
|
||||
<property name="formats">application/x-gtk-render-node</property>
|
||||
<signal name="drop" handler="on_picture_drop_cb" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<developer_name>Matthias Clasen and others</developer_name>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<releases>
|
||||
<release version="@BUILD_VERSION@">
|
||||
<release version="@BUILD_VERSION@" date="@BUILD_DATE@">
|
||||
<description>
|
||||
<p>A new build of GTK.</p>
|
||||
</description>
|
||||
|
||||
@@ -162,6 +162,8 @@ done with
|
||||
|caret-color|[CSS Basic User Interface Level 3](https://www.w3.org/TR/css3-ui/#caret-color) | CSS allows an auto value |
|
||||
|-gtk-secondary-caret-color|[Color](https://www.w3.org/TR/css-color-3/#valuea-def-color) | used for the secondary caret in bidirectional text |
|
||||
|letter-spacing| [CSS Text Level 3](https://www.w3.org/TR/css3-text/#letter-spacing) | |
|
||||
|text-transform| [CSS Text Level 3](https://www.w3.org/TR/css-text-3/#text-transform-property) | CSS allows full-width and full-size-kana. Since 4.6 |
|
||||
|line-height| [CSS Inline Layout Level 3](https://www.w3.org/TR/css-inline-3/#line-height-property) | Since 4.6 |
|
||||
|text-decoration-line| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-line-property) | |
|
||||
|text-decoration-color| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-color-property) | |
|
||||
|text-decoration-style| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-style-property) | CSS allows dashed and dotted |
|
||||
|
||||
@@ -1332,18 +1332,6 @@ pointer coordinates as inout arguments any more, but as normal in ones.
|
||||
|
||||
See: [method@Gtk.TreeView.get_tooltip_context], [method@Gtk.IconView.get_tooltip_context]
|
||||
|
||||
### Adapt to GtkPopover changes
|
||||
|
||||
In GTK 3, a `GtkPopover` could be attached to any widget, using the `relative-to`
|
||||
property. This is no longer possible in GTK 4. The parent widget has to be aware
|
||||
of its popover children, and manage their size allocation. Therefore, only widgets
|
||||
with dedicated popover support can have them, such as [class@Gtk.MenuButton] or
|
||||
[class@Gtk.PopoverMenuBar].
|
||||
|
||||
If you want to make a custom widget that has an attached popover, you need to call
|
||||
[method@Gtk.Popover.present] in your [vfunc@Gtk.Widget.size_allocate] vfunc, in order
|
||||
to update the positioning of the popover.
|
||||
|
||||
### Stop using GtkFileChooserButton
|
||||
|
||||
The `GtkFileChooserButton` widget was removed, due to its shortcomings in
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
struct _ExampleAppPrefs
|
||||
{
|
||||
GtkDialog parent;
|
||||
|
||||
GSettings *settings;
|
||||
GtkWidget *font;
|
||||
GtkWidget *transition;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ExampleAppPrefs, example_app_prefs, GTK_TYPE_DIALOG)
|
||||
@@ -19,41 +15,20 @@ static void
|
||||
example_app_prefs_init (ExampleAppPrefs *prefs)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (prefs));
|
||||
prefs->settings = g_settings_new ("org.gtk.exampleapp");
|
||||
|
||||
g_settings_bind (prefs->settings, "font",
|
||||
prefs->font, "font",
|
||||
G_SETTINGS_BIND_DEFAULT);
|
||||
g_settings_bind (prefs->settings, "transition",
|
||||
prefs->transition, "active-id",
|
||||
G_SETTINGS_BIND_DEFAULT);
|
||||
}
|
||||
|
||||
static void
|
||||
example_app_prefs_dispose (GObject *object)
|
||||
{
|
||||
ExampleAppPrefs *prefs;
|
||||
|
||||
prefs = EXAMPLE_APP_PREFS (object);
|
||||
|
||||
g_clear_object (&prefs->settings);
|
||||
|
||||
G_OBJECT_CLASS (example_app_prefs_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
example_app_prefs_class_init (ExampleAppPrefsClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS (class)->dispose = example_app_prefs_dispose;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/exampleapp/prefs.ui");
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppPrefs, font);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppPrefs, transition);
|
||||
}
|
||||
|
||||
ExampleAppPrefs *
|
||||
example_app_prefs_new (ExampleAppWindow *win)
|
||||
{
|
||||
return g_object_new (EXAMPLE_APP_PREFS_TYPE, "transient-for", win, "use-header-bar", TRUE, NULL);
|
||||
return g_object_new (EXAMPLE_APP_PREFS_TYPE,
|
||||
"transient-for", win,
|
||||
"use-header-bar", TRUE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFontButton" id="font">
|
||||
<property name="font" bind-settings-schema="org.gtk.exampleapp" bind-settings-key="font"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">0</property>
|
||||
@@ -48,6 +49,7 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="transition">
|
||||
<property name="active-id" bind-settings-schema="org.gtk.exampleapp" bind-settings-key="transition"/>
|
||||
<items>
|
||||
<item translatable="yes" id="none">None</item>
|
||||
<item translatable="yes" id="crossfade">Fade</item>
|
||||
|
||||
@@ -214,7 +214,7 @@ _gdk_broadway_display_open (const char *display_name)
|
||||
broadway_display->server = _gdk_broadway_server_new (display, display_name, &error);
|
||||
if (broadway_display->server == NULL)
|
||||
{
|
||||
GDK_NOTE (MISC, g_message ("Unable to init Broadway server: %s\n", error->message));
|
||||
g_printerr ("Unable to init Broadway server: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -553,6 +553,8 @@ gdk_content_deserialize_async (GInputStream *stream,
|
||||
Deserializer *deserializer;
|
||||
|
||||
g_return_if_fail (G_IS_INPUT_STREAM (stream));
|
||||
g_return_if_fail (mime_type != NULL);
|
||||
g_return_if_fail (G_TYPE_IS_VALUE_TYPE (type));
|
||||
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
|
||||
g_return_if_fail (callback != NULL);
|
||||
|
||||
@@ -591,7 +593,10 @@ gdk_content_deserialize_finish (GAsyncResult *result,
|
||||
g_return_val_if_fail (GDK_IS_CONTENT_DESERIALIZER (result), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
deserializer = GDK_CONTENT_DESERIALIZER (result);
|
||||
g_return_val_if_fail (G_VALUE_HOLDS (value, G_VALUE_TYPE (&deserializer->value)), FALSE);
|
||||
if (G_VALUE_TYPE (value) == 0)
|
||||
g_value_init (value, G_VALUE_TYPE (&deserializer->value));
|
||||
else
|
||||
g_return_val_if_fail (G_VALUE_HOLDS (value, G_VALUE_TYPE (&deserializer->value)), FALSE);
|
||||
|
||||
if (deserializer->error)
|
||||
{
|
||||
@@ -928,13 +933,11 @@ init (void)
|
||||
if (!g_get_charset (&charset))
|
||||
{
|
||||
char *mime = g_strdup_printf ("text/plain;charset=%s", charset);
|
||||
|
||||
gdk_content_register_deserializer (mime,
|
||||
G_TYPE_STRING,
|
||||
string_deserializer,
|
||||
(gpointer) charset,
|
||||
g_free);
|
||||
g_free (mime);
|
||||
}
|
||||
gdk_content_register_deserializer ("text/plain",
|
||||
G_TYPE_STRING,
|
||||
|
||||
@@ -1233,8 +1233,6 @@ gdk_display_init_gl (GdkDisplay *self)
|
||||
*/
|
||||
priv->gl_context = context;
|
||||
|
||||
gdk_gl_backend_use (GDK_GL_CONTEXT_GET_CLASS (context)->backend_type);
|
||||
|
||||
gdk_profiler_end_mark (before, "initialize OpenGL", NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,13 +75,11 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkglcontextprivate.h"
|
||||
|
||||
#include "gdkdebug.h"
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkinternals.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdkinternals.h"
|
||||
|
||||
#include "gdkintl.h"
|
||||
#include "gdk-private.h"
|
||||
|
||||
#ifdef GDK_WINDOWING_WIN32
|
||||
@@ -1337,68 +1335,3 @@ gdk_gl_context_use_es_bgra (GdkGLContext *context)
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GdkGLBackend the_gl_backend_type = GDK_GL_NONE;
|
||||
|
||||
static const char *gl_backend_names[] = {
|
||||
[GDK_GL_NONE] = "No GL (You should never read this)",
|
||||
[GDK_GL_EGL] = "EGL",
|
||||
[GDK_GL_GLX] = "X11 GLX",
|
||||
[GDK_GL_WGL] = "Windows WGL",
|
||||
[GDK_GL_CGL] = "Apple CGL"
|
||||
};
|
||||
|
||||
/*<private>
|
||||
* gdk_gl_backend_can_be_used:
|
||||
* @backend_type: Type of backend to check
|
||||
* @error: Return location for an error
|
||||
*
|
||||
* Checks if this backend type can be used. When multiple displays
|
||||
* are opened that use different GL backends, conflicts can arise,
|
||||
* so this function checks that all displays use compatible GL
|
||||
* backends.
|
||||
*
|
||||
* Returns: %TRUE if the backend can still be used
|
||||
*/
|
||||
gboolean
|
||||
gdk_gl_backend_can_be_used (GdkGLBackend backend_type,
|
||||
GError **error)
|
||||
{
|
||||
if (the_gl_backend_type == GDK_GL_NONE ||
|
||||
the_gl_backend_type == backend_type)
|
||||
return TRUE;
|
||||
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
|
||||
/* translators: This is about OpenGL backend names, like
|
||||
* "Trying to use X11 GLX, but EGL is already in use" */
|
||||
_("Trying to use %s, but %s is already in use"),
|
||||
gl_backend_names[backend_type],
|
||||
gl_backend_names[the_gl_backend_type]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gdk_gl_backend_use:
|
||||
* @backend_type: Type of backend
|
||||
*
|
||||
* Ensures that the backend in use is the given one. If another backend
|
||||
* is already in use, this function will abort the program. It should
|
||||
* have previously checked via gdk_gl_backend_can_be_used().
|
||||
**/
|
||||
void
|
||||
gdk_gl_backend_use (GdkGLBackend backend_type)
|
||||
{
|
||||
/* Check that the context class is properly initializing its backend type */
|
||||
g_assert (backend_type != GDK_GL_NONE);
|
||||
|
||||
if (the_gl_backend_type == GDK_GL_NONE)
|
||||
{
|
||||
the_gl_backend_type = backend_type;
|
||||
/* This is important!!!11eleven
|
||||
* (But really: How do I print a message in 2 categories?) */
|
||||
GDK_NOTE (OPENGL, g_print ("Using OpenGL backend %s\n", gl_backend_names[the_gl_backend_type]));
|
||||
GDK_NOTE (MISC, g_message ("Using Opengl backend %s", gl_backend_names[the_gl_backend_type]));
|
||||
}
|
||||
|
||||
g_assert (the_gl_backend_type == backend_type);
|
||||
}
|
||||
|
||||
@@ -34,14 +34,6 @@ G_BEGIN_DECLS
|
||||
#define GDK_EGL_MIN_VERSION_MAJOR (1)
|
||||
#define GDK_EGL_MIN_VERSION_MINOR (4)
|
||||
|
||||
typedef enum {
|
||||
GDK_GL_NONE = 0,
|
||||
GDK_GL_EGL,
|
||||
GDK_GL_GLX,
|
||||
GDK_GL_WGL,
|
||||
GDK_GL_CGL
|
||||
} GdkGLBackend;
|
||||
|
||||
#define GDK_GL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_GL_CONTEXT, GdkGLContextClass))
|
||||
#define GDK_IS_GL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_GL_CONTEXT))
|
||||
#define GDK_GL_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_GL_CONTEXT, GdkGLContextClass))
|
||||
@@ -60,8 +52,6 @@ struct _GdkGLContextClass
|
||||
{
|
||||
GdkDrawContextClass parent_class;
|
||||
|
||||
GdkGLBackend backend_type;
|
||||
|
||||
gboolean (* realize) (GdkGLContext *context,
|
||||
GError **error);
|
||||
|
||||
@@ -96,10 +86,6 @@ typedef struct {
|
||||
guint use_es : 1;
|
||||
} GdkGLContextPaintData;
|
||||
|
||||
gboolean gdk_gl_backend_can_be_used (GdkGLBackend backend_type,
|
||||
GError **error);
|
||||
void gdk_gl_backend_use (GdkGLBackend backend_type);
|
||||
|
||||
GdkGLContext * gdk_gl_context_new_for_surface (GdkSurface *surface);
|
||||
|
||||
void gdk_gl_context_set_is_legacy (GdkGLContext *context,
|
||||
|
||||
@@ -94,6 +94,14 @@
|
||||
*/
|
||||
#define GDK_VERSION_4_4 (G_ENCODE_VERSION (4, 4))
|
||||
|
||||
/**
|
||||
* GDK_VERSION_4_6:
|
||||
*
|
||||
* A macro that evaluates to the 4.6 version of GDK, in a format
|
||||
* that can be used by the C pre-processor.
|
||||
*/
|
||||
#define GDK_VERSION_4_6 (G_ENCODE_VERSION (4, 6))
|
||||
|
||||
|
||||
/* evaluates to the current stable version; for development cycles,
|
||||
* this means the next stable target, with a hard backstop to the
|
||||
@@ -221,4 +229,18 @@
|
||||
# define GDK_DEPRECATED_IN_4_4_FOR(f) _GDK_EXTERN
|
||||
#endif
|
||||
|
||||
#if GDK_VERSION_MAX_ALLOWED < GDK_VERSION_4_6
|
||||
# define GDK_AVAILABLE_IN_4_6 GDK_UNAVAILABLE(4, 6)
|
||||
#else
|
||||
# define GDK_AVAILABLE_IN_4_6 _GDK_EXTERN
|
||||
#endif
|
||||
|
||||
#if GDK_VERSION_MIN_REQUIRED >= GDK_VERSION_4_6
|
||||
# define GDK_DEPRECATED_IN_4_6 GDK_DEPRECATED
|
||||
# define GDK_DEPRECATED_IN_4_6_FOR(f) GDK_DEPRECATED_FOR(f)
|
||||
#else
|
||||
# define GDK_DEPRECATED_IN_4_6 _GDK_EXTERN
|
||||
# define GDK_DEPRECATED_IN_4_6_FOR(f) _GDK_EXTERN
|
||||
#endif
|
||||
|
||||
#endif /* __GDK_VERSION_MACROS_H__ */
|
||||
|
||||
@@ -641,9 +641,6 @@ static GdkGLContext *
|
||||
gdk_macos_display_init_gl (GdkDisplay *display,
|
||||
GError **error)
|
||||
{
|
||||
if (!gdk_gl_backend_can_be_used (GDK_GL_CGL, error))
|
||||
return FALSE;
|
||||
|
||||
return g_object_new (GDK_TYPE_MACOS_GL_CONTEXT,
|
||||
"display", display,
|
||||
NULL);
|
||||
|
||||
@@ -514,11 +514,7 @@ gdk_macos_gl_context_class_init (GdkMacosGLContextClass *klass)
|
||||
draw_context_class->surface_resized = gdk_macos_gl_context_surface_resized;
|
||||
|
||||
gl_class->get_damage = gdk_macos_gl_context_get_damage;
|
||||
gl_class->clear_current = gdk_macos_gl_context_clear_current;
|
||||
gl_class->make_current = gdk_macos_gl_context_make_current;
|
||||
gl_class->realize = gdk_macos_gl_context_real_realize;
|
||||
|
||||
gl_class->backend_type = GDK_GL_CGL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -807,7 +807,7 @@ _gdk_macos_surface_acquire_context (GdkMacosSurface *self,
|
||||
scale = CGSizeMake (1.0, 1.0);
|
||||
scale = CGContextConvertSizeToDeviceSpace (cg_context, scale);
|
||||
|
||||
CGContextScaleCTM (cg_context, 1.0 / fabs (scale.width), 1.0 / fabs (scale.height));
|
||||
CGContextScaleCTM (cg_context, 1.0 / scale.width, 1.0 / scale.height);
|
||||
}
|
||||
|
||||
return cg_context;
|
||||
|
||||
@@ -358,8 +358,6 @@ gdk_wayland_gl_context_class_init (GdkWaylandGLContextClass *klass)
|
||||
context_class->make_current = gdk_wayland_gl_context_make_current;
|
||||
context_class->clear_current = gdk_wayland_gl_context_clear_current;
|
||||
context_class->get_damage = gdk_wayland_gl_context_get_damage;
|
||||
|
||||
context_class->backend_type = GDK_GL_EGL;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -477,9 +475,6 @@ gdk_wayland_display_init_gl (GdkDisplay *display,
|
||||
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
|
||||
G_GNUC_UNUSED gint64 start_time2;
|
||||
|
||||
if (!gdk_gl_backend_can_be_used (GDK_GL_EGL, error))
|
||||
return FALSE;
|
||||
|
||||
if (!epoxy_has_egl ())
|
||||
{
|
||||
gboolean sandboxed = gdk_running_in_sandbox ();
|
||||
|
||||
@@ -3009,7 +3009,6 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
|
||||
|
||||
impl->has_uncommitted_ack_configure = FALSE;
|
||||
impl->input_region_dirty = TRUE;
|
||||
impl->opaque_region_dirty = TRUE;
|
||||
|
||||
unset_transient_for_exported (surface);
|
||||
|
||||
|
||||
@@ -1150,8 +1150,6 @@ static gboolean
|
||||
gdk_win32_display_init_gl_backend (GdkDisplay *display,
|
||||
GError **error)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
if (GDK_DISPLAY_DEBUG_CHECK (display, GL_EGL))
|
||||
return gdk_win32_display_init_egl (display, error);
|
||||
@@ -1163,17 +1161,17 @@ gdk_win32_display_init_gl_backend (GdkDisplay *display,
|
||||
* as WGL is the more tried-and-tested configuration.
|
||||
*/
|
||||
|
||||
result = gdk_win32_display_init_wgl (display, error);
|
||||
if (gdk_win32_display_init_wgl (display, error))
|
||||
return TRUE;
|
||||
g_clear_error (error);
|
||||
|
||||
#ifdef GDK_WIN32_ENABLE_EGL
|
||||
if (!result)
|
||||
{
|
||||
g_clear_error (error);
|
||||
result = gdk_win32_display_init_egl (display, error);
|
||||
}
|
||||
if (gdk_win32_display_init_egl (display, error))
|
||||
return TRUE;
|
||||
#endif
|
||||
g_clear_error (error);
|
||||
|
||||
return result;
|
||||
return gdk_win32_display_init_wgl (display, error);
|
||||
}
|
||||
|
||||
static GdkGLContext *
|
||||
|
||||
@@ -2081,8 +2081,8 @@ gdk_dnd_handle_motion_event (GdkDrag *drag,
|
||||
API_CALL (PostThreadMessage, (clipdrop->dnd_thread_id,
|
||||
WM_MOUSEMOVE,
|
||||
key_state,
|
||||
MAKELPARAM (x_root * drag_win32->scale - _gdk_offset_x,
|
||||
y_root * drag_win32->scale - _gdk_offset_y)));
|
||||
MAKELPARAM (x * drag_win32->scale,
|
||||
y * drag_win32->scale)));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -426,31 +426,6 @@ set_source_actions_helper (GdkDrop *drop,
|
||||
return actions;
|
||||
}
|
||||
|
||||
/* Utility function to translate win32 screen coordinates to
|
||||
* client coordinates (i.e. relative to the surface origin)
|
||||
*
|
||||
* Note that input is expected to be:
|
||||
* a) NOT scaled by dpi_scale
|
||||
* b) NOT translated by the GDK screen offset (gdk_offset_x / y)
|
||||
*
|
||||
* This utility function preserves subpixel precision
|
||||
*/
|
||||
static void
|
||||
unscaled_screen_to_client (GdkSurface* surface,
|
||||
double screen_x,
|
||||
double screen_y,
|
||||
double *client_x,
|
||||
double *client_y)
|
||||
{
|
||||
POINT client_origin;
|
||||
|
||||
client_origin.x = 0;
|
||||
client_origin.y = 0;
|
||||
ClientToScreen (GDK_SURFACE_HWND (surface), &client_origin);
|
||||
*client_x = screen_x - client_origin.x;
|
||||
*client_y = screen_y - client_origin.y;
|
||||
}
|
||||
|
||||
/* The pdwEffect here initially points
|
||||
* to a DWORD that contains the value of dwOKEffects argument in DoDragDrop,
|
||||
* i.e. the drag action that the drag source deems acceptable.
|
||||
@@ -471,8 +446,6 @@ idroptarget_dragenter (LPDROPTARGET This,
|
||||
GdkDisplay *display;
|
||||
int pt_x;
|
||||
int pt_y;
|
||||
double x = 0.0;
|
||||
double y = 0.0;
|
||||
GdkDrag *drag;
|
||||
GdkDragAction source_actions;
|
||||
GdkDragAction dest_actions;
|
||||
@@ -517,12 +490,7 @@ idroptarget_dragenter (LPDROPTARGET This,
|
||||
set_data_object (&ctx->data_object, pDataObj);
|
||||
pt_x = pt.x / drop_win32->scale + _gdk_offset_x;
|
||||
pt_y = pt.y / drop_win32->scale + _gdk_offset_y;
|
||||
|
||||
unscaled_screen_to_client (ctx->surface, pt.x, pt.y, &x, &y);
|
||||
x /= drop_win32->scale;
|
||||
y /= drop_win32->scale;
|
||||
|
||||
gdk_drop_emit_enter_event (drop, TRUE, x, y, GDK_CURRENT_TIME);
|
||||
gdk_drop_emit_enter_event (drop, TRUE, pt_x, pt_y, GDK_CURRENT_TIME);
|
||||
drop_win32->last_key_state = grfKeyState;
|
||||
drop_win32->last_x = pt_x;
|
||||
drop_win32->last_y = pt_y;
|
||||
@@ -577,14 +545,7 @@ idroptarget_dragover (LPDROPTARGET This,
|
||||
pt_y != drop_win32->last_y ||
|
||||
grfKeyState != drop_win32->last_key_state)
|
||||
{
|
||||
double x = 0.0;
|
||||
double y = 0.0;
|
||||
|
||||
unscaled_screen_to_client (ctx->surface, pt.x, pt.y, &x, &y);
|
||||
x /= drop_win32->scale;
|
||||
y /= drop_win32->scale;
|
||||
|
||||
gdk_drop_emit_motion_event (ctx->drop, TRUE, x, y, GDK_CURRENT_TIME);
|
||||
gdk_drop_emit_motion_event (ctx->drop, TRUE, pt_x, pt_y, GDK_CURRENT_TIME);
|
||||
drop_win32->last_key_state = grfKeyState;
|
||||
drop_win32->last_x = pt_x;
|
||||
drop_win32->last_y = pt_y;
|
||||
@@ -627,8 +588,6 @@ idroptarget_drop (LPDROPTARGET This,
|
||||
GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (ctx->drop);
|
||||
int pt_x = pt.x / drop_win32->scale + _gdk_offset_x;
|
||||
int pt_y = pt.y / drop_win32->scale + _gdk_offset_y;
|
||||
double x = 0.0;
|
||||
double y = 0.0;
|
||||
GdkDragAction dest_action;
|
||||
|
||||
GDK_NOTE (DND, g_print ("idroptarget_drop %p ", This));
|
||||
@@ -648,12 +607,7 @@ idroptarget_drop (LPDROPTARGET This,
|
||||
grfKeyState);
|
||||
|
||||
drop_win32->drop_finished = FALSE;
|
||||
|
||||
unscaled_screen_to_client (ctx->surface, pt.x, pt.y, &x, &y);
|
||||
x /= drop_win32->scale;
|
||||
y /= drop_win32->scale;
|
||||
|
||||
gdk_drop_emit_drop_event (ctx->drop, TRUE, x, y, GDK_CURRENT_TIME);
|
||||
gdk_drop_emit_drop_event (ctx->drop, TRUE, pt_x, pt_y, GDK_CURRENT_TIME);
|
||||
|
||||
while (!drop_win32->drop_finished)
|
||||
g_main_context_iteration (NULL, FALSE);
|
||||
|
||||
@@ -256,9 +256,6 @@ gdk_win32_display_init_egl (GdkDisplay *display,
|
||||
int best_idx = 0;
|
||||
EGLDisplay egl_disp;
|
||||
|
||||
if (!gdk_gl_backend_can_be_used (GDK_GL_EGL, error))
|
||||
return FALSE;
|
||||
|
||||
if (display_win32->egl_disp != EGL_NO_DISPLAY)
|
||||
return TRUE;
|
||||
|
||||
@@ -491,8 +488,6 @@ gdk_win32_gl_context_egl_class_init (GdkWin32GLContextClass *klass)
|
||||
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS(klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
context_class->backend_type = GDK_GL_EGL;
|
||||
|
||||
context_class->realize = gdk_win32_gl_context_egl_realize;
|
||||
context_class->make_current = gdk_win32_gl_context_egl_make_current;
|
||||
context_class->clear_current = gdk_win32_gl_context_egl_clear_current;
|
||||
|
||||
@@ -265,9 +265,6 @@ gdk_win32_display_init_wgl (GdkDisplay *display,
|
||||
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
|
||||
HDC hdc;
|
||||
|
||||
if (!gdk_gl_backend_can_be_used (GDK_GL_WGL, error))
|
||||
return FALSE;
|
||||
|
||||
if (display_win32->wgl_pixel_format != 0)
|
||||
return TRUE;
|
||||
|
||||
@@ -291,6 +288,7 @@ gdk_win32_display_init_wgl (GdkDisplay *display,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
display_win32->wgl_pixel_format = best_idx;
|
||||
display_win32->gl_version = epoxy_gl_version ();
|
||||
|
||||
/* We must have OpenGL/WGL 2.0 or later, or have the GL_ARB_shader_objects extension */
|
||||
@@ -309,8 +307,6 @@ gdk_win32_display_init_wgl (GdkDisplay *display,
|
||||
}
|
||||
}
|
||||
|
||||
display_win32->wgl_pixel_format = best_idx;
|
||||
|
||||
display_win32->hasWglARBCreateContext =
|
||||
epoxy_has_wgl_extension (hdc, "WGL_ARB_create_context");
|
||||
display_win32->hasWglEXTSwapControl =
|
||||
@@ -701,8 +697,6 @@ gdk_win32_gl_context_wgl_class_init (GdkWin32GLContextWGLClass *klass)
|
||||
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
context_class->backend_type = GDK_GL_WGL;
|
||||
|
||||
context_class->realize = gdk_win32_gl_context_wgl_realize;
|
||||
context_class->make_current = gdk_win32_gl_context_wgl_make_current;
|
||||
context_class->clear_current = gdk_win32_gl_context_wgl_clear_current;
|
||||
|
||||
@@ -583,6 +583,12 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
|
||||
if (!title || !*title)
|
||||
title = "";
|
||||
|
||||
/* WS_EX_TRANSPARENT means "try draw this window last, and ignore input".
|
||||
* It's the last part we're after. We don't want DND indicator to accept
|
||||
* input, because that will make it a potential drop target, and if it's
|
||||
* under the mouse cursor, this will kill any DND.
|
||||
*/
|
||||
|
||||
klass = RegisterGdkClass (surface_type);
|
||||
|
||||
wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
|
||||
@@ -645,7 +651,6 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
|
||||
|
||||
_gdk_win32_surface_enable_transparency (surface);
|
||||
_gdk_win32_surface_register_dnd (surface);
|
||||
_gdk_win32_surface_update_style_bits (surface);
|
||||
|
||||
g_signal_connect (frame_clock,
|
||||
"after-paint",
|
||||
@@ -1836,8 +1841,6 @@ _gdk_win32_surface_update_style_bits (GdkSurface *window)
|
||||
RECT rect, before, after;
|
||||
gboolean was_topmost;
|
||||
gboolean will_be_topmost;
|
||||
gboolean was_layered;
|
||||
gboolean will_be_layered;
|
||||
HWND insert_after;
|
||||
UINT flags;
|
||||
|
||||
@@ -1852,9 +1855,7 @@ _gdk_win32_surface_update_style_bits (GdkSurface *window)
|
||||
AdjustWindowRectEx (&before, old_style, FALSE, old_exstyle);
|
||||
|
||||
was_topmost = (old_exstyle & WS_EX_TOPMOST) ? TRUE : FALSE;
|
||||
was_layered = (old_exstyle & WS_EX_LAYERED) ? TRUE : FALSE;
|
||||
will_be_topmost = was_topmost;
|
||||
will_be_layered = was_layered;
|
||||
|
||||
old_exstyle &= ~WS_EX_TOPMOST;
|
||||
|
||||
@@ -1864,14 +1865,7 @@ _gdk_win32_surface_update_style_bits (GdkSurface *window)
|
||||
if (GDK_IS_DRAG_SURFACE (window))
|
||||
{
|
||||
new_exstyle |= WS_EX_TOOLWINDOW;
|
||||
|
||||
/* WS_EX_LAYERED | WS_EX_TRANSPARENT makes the drag surface behave
|
||||
* in pointer input passthrough mode, so it doesn't interfere with
|
||||
* the drag and drop operation.
|
||||
*/
|
||||
new_exstyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
|
||||
will_be_topmost = TRUE;
|
||||
will_be_layered = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1916,14 +1910,6 @@ _gdk_win32_surface_update_style_bits (GdkSurface *window)
|
||||
_gdk_win32_surface_exstyle_to_string (new_exstyle)));
|
||||
|
||||
SetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE, new_exstyle);
|
||||
|
||||
if (!was_layered && will_be_layered)
|
||||
{
|
||||
/* We have to call SetLayeredWindowAttributes when setting the
|
||||
* WS_EX_LAYERED style anew, otherwise the window won't show up
|
||||
*/
|
||||
API_CALL (SetLayeredWindowAttributes, (GDK_SURFACE_HWND (window), 0, 255, LWA_ALPHA));
|
||||
}
|
||||
}
|
||||
|
||||
AdjustWindowRectEx (&after, new_style, FALSE, new_exstyle);
|
||||
|
||||
@@ -642,8 +642,6 @@ gdk_x11_gl_context_egl_class_init (GdkX11GLContextEGLClass *klass)
|
||||
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
context_class->backend_type = GDK_GL_EGL;
|
||||
|
||||
context_class->realize = gdk_x11_gl_context_egl_realize;
|
||||
context_class->make_current = gdk_x11_gl_context_egl_make_current;
|
||||
context_class->clear_current = gdk_x11_gl_context_egl_clear_current;
|
||||
@@ -672,9 +670,6 @@ gdk_x11_display_init_egl (GdkX11Display *self,
|
||||
Display *dpy;
|
||||
int major, minor;
|
||||
|
||||
if (!gdk_gl_backend_can_be_used (GDK_GL_EGL, error))
|
||||
return FALSE;
|
||||
|
||||
dpy = gdk_x11_display_get_xdisplay (display);
|
||||
|
||||
if (!epoxy_has_egl ())
|
||||
|
||||
@@ -692,8 +692,6 @@ gdk_x11_gl_context_glx_class_init (GdkX11GLContextGLXClass *klass)
|
||||
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
context_class->backend_type = GDK_GL_GLX;
|
||||
|
||||
context_class->realize = gdk_x11_gl_context_glx_realize;
|
||||
context_class->make_current = gdk_x11_gl_context_glx_make_current;
|
||||
context_class->clear_current = gdk_x11_gl_context_glx_clear_current;
|
||||
@@ -907,9 +905,6 @@ gdk_x11_display_init_glx (GdkX11Display *display_x11,
|
||||
Display *dpy;
|
||||
int screen_num;
|
||||
|
||||
if (!gdk_gl_backend_can_be_used (GDK_GL_GLX, error))
|
||||
return FALSE;
|
||||
|
||||
dpy = gdk_x11_display_get_xdisplay (display);
|
||||
|
||||
if (!epoxy_has_glx (dpy))
|
||||
|
||||
@@ -1923,13 +1923,8 @@ gdk_x11_surface_update_popups (GdkSurface *parent)
|
||||
{
|
||||
GdkX11Surface *popup_impl = l->data;
|
||||
GdkSurface *popup = GDK_SURFACE (popup_impl);
|
||||
int new_x, new_y;
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (popup))
|
||||
continue;
|
||||
|
||||
new_x = GDK_X11_SURFACE (parent)->abs_x + popup->x;
|
||||
new_y = GDK_X11_SURFACE (parent)->abs_y + popup->y;
|
||||
int new_x = GDK_X11_SURFACE (parent)->abs_x + popup->x;
|
||||
int new_y = GDK_X11_SURFACE (parent)->abs_y + popup->y;
|
||||
|
||||
if (new_x != popup_impl->abs_x || new_y != popup_impl->abs_y)
|
||||
x11_surface_move (popup, new_x, new_y);
|
||||
|
||||
@@ -1,317 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define SANITY_CHECKS 0
|
||||
|
||||
|
||||
|
||||
#define rounded_rect_top_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
|
||||
r->bounds.origin.y, \
|
||||
r->corner[0].width, r->corner[0].height))
|
||||
|
||||
#define rounded_rect_top_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[1].width, \
|
||||
r->bounds.origin.y, \
|
||||
r->corner[1].width, r->corner[1].height))
|
||||
|
||||
#define rounded_rect_bottom_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[2].width, \
|
||||
r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
|
||||
r->corner[2].width, r->corner[2].height))
|
||||
|
||||
#define rounded_rect_bottom_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
|
||||
r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
|
||||
r->corner[3].width, r->corner[3].height))
|
||||
|
||||
|
||||
#define rounded_rect_corner0(r) rounded_rect_top_left(r)
|
||||
#define rounded_rect_corner1(r) rounded_rect_top_right(r)
|
||||
#define rounded_rect_corner2(r) rounded_rect_bottom_right(r)
|
||||
#define rounded_rect_corner3(r) rounded_rect_bottom_left(r)
|
||||
|
||||
#define rounded_rect_corner(r, i) (rounded_rect_corner ##i(r))
|
||||
#define graphene_size_non_zero(s) (s->width > 0 && s->height > 0)
|
||||
#define rounded_rect_has_corner(r, i) (r->corner[i].width > 0 && r->corner[i].height > 0)
|
||||
|
||||
#define rect_contains_point(r, _x, _y) (_x >= (r)->origin.x && _x <= (r)->origin.x + (r)->size.width && \
|
||||
_y >= (r)->origin.y && _y <= (r)->origin.y + (r)->size.height)
|
||||
|
||||
enum {
|
||||
NINE_SLICE_TOP_LEFT = 0,
|
||||
NINE_SLICE_TOP_CENTER = 1,
|
||||
NINE_SLICE_TOP_RIGHT = 2,
|
||||
NINE_SLICE_LEFT_CENTER = 3,
|
||||
NINE_SLICE_CENTER = 4,
|
||||
NINE_SLICE_RIGHT_CENTER = 5,
|
||||
NINE_SLICE_BOTTOM_LEFT = 6,
|
||||
NINE_SLICE_BOTTOM_CENTER = 7,
|
||||
NINE_SLICE_BOTTOM_RIGHT = 8,
|
||||
};
|
||||
#define NINE_SLICE_SIZE 9 /* Hah. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int texture_id;
|
||||
float x;
|
||||
float y;
|
||||
float x2;
|
||||
float y2;
|
||||
} TextureRegion;
|
||||
|
||||
static inline bool G_GNUC_PURE
|
||||
slice_is_visible (const cairo_rectangle_int_t *r)
|
||||
{
|
||||
return (r->width > 0 && r->height > 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
nine_slice_rounded_rect (const GskRoundedRect *rect,
|
||||
cairo_rectangle_int_t *out_rects)
|
||||
{
|
||||
const graphene_point_t *origin = &rect->bounds.origin;
|
||||
const graphene_size_t *size = &rect->bounds.size;
|
||||
const int top_height = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].height,
|
||||
rect->corner[GSK_CORNER_TOP_RIGHT].height));
|
||||
const int bottom_height = ceilf (MAX (rect->corner[GSK_CORNER_BOTTOM_LEFT].height,
|
||||
rect->corner[GSK_CORNER_BOTTOM_RIGHT].height));
|
||||
const int right_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_RIGHT].width,
|
||||
rect->corner[GSK_CORNER_BOTTOM_RIGHT].width));
|
||||
const int left_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].width,
|
||||
rect->corner[GSK_CORNER_BOTTOM_LEFT].width));
|
||||
|
||||
/* Top left */
|
||||
out_rects[0] = (cairo_rectangle_int_t) {
|
||||
origin->x, origin->y,
|
||||
left_width, top_height,
|
||||
};
|
||||
|
||||
/* Top center */
|
||||
out_rects[1] = (cairo_rectangle_int_t) {
|
||||
origin->x + size->width / 2.0 - 0.5, origin->y,
|
||||
1, top_height,
|
||||
};
|
||||
|
||||
/* Top right */
|
||||
out_rects[2] = (cairo_rectangle_int_t) {
|
||||
origin->x + size->width - right_width, origin->y,
|
||||
right_width, top_height
|
||||
};
|
||||
|
||||
/* Left center */
|
||||
out_rects[3] = (cairo_rectangle_int_t) {
|
||||
origin->x, origin->y + size->height / 2,
|
||||
left_width, 1,
|
||||
};
|
||||
|
||||
/* center */
|
||||
out_rects[4] = (cairo_rectangle_int_t) {
|
||||
origin->x + size->width / 2.0 - 0.5,
|
||||
origin->y + size->height / 2.0 - 0.5,
|
||||
1, 1
|
||||
};
|
||||
|
||||
/* Right center */
|
||||
out_rects[5] = (cairo_rectangle_int_t) {
|
||||
origin->x + size->width - right_width,
|
||||
origin->y + (size->height / 2.0) - 0.5,
|
||||
right_width,
|
||||
1,
|
||||
};
|
||||
|
||||
/* Bottom Left */
|
||||
out_rects[6] = (cairo_rectangle_int_t) {
|
||||
origin->x, origin->y + size->height - bottom_height,
|
||||
left_width, bottom_height,
|
||||
};
|
||||
|
||||
/* Bottom center */
|
||||
out_rects[7] = (cairo_rectangle_int_t) {
|
||||
origin->x + (size->width / 2.0) - 0.5,
|
||||
origin->y + size->height - bottom_height,
|
||||
1, bottom_height,
|
||||
};
|
||||
|
||||
/* Bottom right */
|
||||
out_rects[8] = (cairo_rectangle_int_t) {
|
||||
origin->x + size->width - right_width,
|
||||
origin->y + size->height - bottom_height,
|
||||
right_width, bottom_height,
|
||||
};
|
||||
|
||||
#if SANITY_CHECKS
|
||||
g_assert_cmpfloat (size->width, >=, left_width + right_width);
|
||||
g_assert_cmpfloat (size->height, >=, top_height + bottom_height);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
nine_slice_grow (cairo_rectangle_int_t *slices,
|
||||
const int amount)
|
||||
{
|
||||
/* top left */
|
||||
slices[0].x -= amount;
|
||||
slices[0].y -= amount;
|
||||
if (amount > slices[0].width)
|
||||
slices[0].width += amount * 2;
|
||||
else
|
||||
slices[0].width += amount;
|
||||
|
||||
if (amount > slices[0].height)
|
||||
slices[0].height += amount * 2;
|
||||
else
|
||||
slices[0].height += amount;
|
||||
|
||||
|
||||
/* Top center */
|
||||
slices[1].y -= amount;
|
||||
if (amount > slices[1].height)
|
||||
slices[1].height += amount * 2;
|
||||
else
|
||||
slices[1].height += amount;
|
||||
|
||||
/* top right */
|
||||
slices[2].y -= amount;
|
||||
if (amount > slices[2].width)
|
||||
{
|
||||
slices[2].x -= amount;
|
||||
slices[2].width += amount * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
slices[2].width += amount;
|
||||
}
|
||||
|
||||
if (amount > slices[2].height)
|
||||
slices[2].height += amount * 2;
|
||||
else
|
||||
slices[2].height += amount;
|
||||
|
||||
|
||||
|
||||
slices[3].x -= amount;
|
||||
if (amount > slices[3].width)
|
||||
slices[3].width += amount * 2;
|
||||
else
|
||||
slices[3].width += amount;
|
||||
|
||||
/* Leave Britney^Wcenter alone */
|
||||
|
||||
if (amount > slices[5].width)
|
||||
{
|
||||
slices[5].x -= amount;
|
||||
slices[5].width += amount * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
slices[5].width += amount;
|
||||
}
|
||||
|
||||
|
||||
/* Bottom left */
|
||||
slices[6].x -= amount;
|
||||
if (amount > slices[6].width)
|
||||
{
|
||||
slices[6].width += amount * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
slices[6].width += amount;
|
||||
}
|
||||
|
||||
if (amount > slices[6].height)
|
||||
{
|
||||
slices[6].y -= amount;
|
||||
slices[6].height += amount * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
slices[6].height += amount;
|
||||
}
|
||||
|
||||
|
||||
/* Bottom center */
|
||||
if (amount > slices[7].height)
|
||||
{
|
||||
slices[7].y -= amount;
|
||||
slices[7].height += amount * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
slices[7].height += amount;
|
||||
}
|
||||
|
||||
if (amount > slices[8].width)
|
||||
{
|
||||
slices[8].x -= amount;
|
||||
slices[8].width += amount * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
slices[8].width += amount;
|
||||
}
|
||||
|
||||
if (amount > slices[8].height)
|
||||
{
|
||||
slices[8].y -= amount;
|
||||
slices[8].height += amount * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
slices[8].height += amount;
|
||||
}
|
||||
|
||||
#if SANITY_CHECKS
|
||||
{
|
||||
for (int i = 0; i < 9; i ++)
|
||||
{
|
||||
g_assert_cmpint (slices[i].x, >=, 0);
|
||||
g_assert_cmpint (slices[i].y, >=, 0);
|
||||
g_assert_cmpint (slices[i].width, >=, 0);
|
||||
g_assert_cmpint (slices[i].height, >=, 0);
|
||||
}
|
||||
|
||||
/* Rows don't overlap */
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
g_assert_cmpint (slices[i * 3 + 0].x + slices[i * 3 + 0].width, <, slices[i * 3 + 1].x);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static inline void
|
||||
nine_slice_to_texture_coords (const cairo_rectangle_int_t *slices,
|
||||
const int texture_width,
|
||||
const int texture_height,
|
||||
TextureRegion *out_regions)
|
||||
{
|
||||
const float fw = (float)texture_width;
|
||||
const float fh = (float)texture_height;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
out_regions[i] = (TextureRegion) {
|
||||
0, /* Texture id */
|
||||
slices[i].x / fw,
|
||||
1.0 - ((slices[i].y + slices[i].height) / fh),
|
||||
(slices[i].x + slices[i].width) / fw,
|
||||
1.0 - (slices[i].y / fh),
|
||||
};
|
||||
}
|
||||
|
||||
#if SANITY_CHECKS
|
||||
{
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
const TextureRegion *r = &out_regions[i];
|
||||
g_assert_cmpfloat (r->x, >=, 0);
|
||||
g_assert_cmpfloat (r->x, <=, 1);
|
||||
g_assert_cmpfloat (r->y, >=, 0);
|
||||
g_assert_cmpfloat (r->y, <=, 1);
|
||||
|
||||
g_assert_cmpfloat (r->x, <, r->x2);
|
||||
g_assert_cmpfloat (r->y, <, r->y2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,849 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskgldriverprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskprofilerprivate.h"
|
||||
#include "gdk/gdkglcontextprivate.h"
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
#include "gdk/gdkgltextureprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
typedef struct {
|
||||
GLuint fbo_id;
|
||||
GLuint depth_stencil_id;
|
||||
} Fbo;
|
||||
|
||||
typedef struct {
|
||||
GLuint texture_id;
|
||||
int width;
|
||||
int height;
|
||||
GLuint min_filter;
|
||||
GLuint mag_filter;
|
||||
Fbo fbo;
|
||||
GdkTexture *user;
|
||||
guint in_use : 1;
|
||||
guint permanent : 1;
|
||||
|
||||
/* TODO: Make this optional and not for every texture... */
|
||||
TextureSlice *slices;
|
||||
guint n_slices;
|
||||
} Texture;
|
||||
|
||||
struct _GskGLDriver
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GdkGLContext *gl_context;
|
||||
GskProfiler *profiler;
|
||||
struct {
|
||||
GQuark created_textures;
|
||||
GQuark reused_textures;
|
||||
GQuark surface_uploads;
|
||||
} counters;
|
||||
|
||||
Fbo default_fbo;
|
||||
|
||||
GHashTable *textures; /* texture_id -> Texture */
|
||||
GHashTable *pointer_textures; /* pointer -> texture_id */
|
||||
|
||||
const Texture *bound_source_texture;
|
||||
|
||||
int max_texture_size;
|
||||
|
||||
gboolean in_frame : 1;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
upload_gdk_texture (GdkTexture *source_texture,
|
||||
int target,
|
||||
int x_offset,
|
||||
int y_offset,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
cairo_surface_t *surface = NULL;
|
||||
GdkMemoryFormat data_format;
|
||||
const guchar *data;
|
||||
gsize data_stride;
|
||||
gsize bpp;
|
||||
|
||||
g_return_if_fail (source_texture != NULL);
|
||||
g_return_if_fail (x_offset + width <= gdk_texture_get_width (source_texture));
|
||||
g_return_if_fail (y_offset + height <= gdk_texture_get_height (source_texture));
|
||||
|
||||
/* Note: GdkGLTextures are already handled before we reach this and reused as-is */
|
||||
|
||||
if (GDK_IS_MEMORY_TEXTURE (source_texture))
|
||||
{
|
||||
GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (source_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 (source_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);
|
||||
}
|
||||
|
||||
bpp = gdk_memory_format_bytes_per_pixel (data_format);
|
||||
|
||||
gdk_gl_context_upload_texture (gdk_gl_context_get_current (),
|
||||
data + x_offset * bpp + y_offset * data_stride,
|
||||
width, height, data_stride,
|
||||
data_format, target);
|
||||
|
||||
if (surface)
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
static Texture *
|
||||
texture_new (void)
|
||||
{
|
||||
return g_slice_new0 (Texture);
|
||||
}
|
||||
|
||||
static inline void
|
||||
fbo_clear (const Fbo *f)
|
||||
{
|
||||
if (f->depth_stencil_id != 0)
|
||||
glDeleteRenderbuffers (1, &f->depth_stencil_id);
|
||||
|
||||
glDeleteFramebuffers (1, &f->fbo_id);
|
||||
}
|
||||
|
||||
static void
|
||||
texture_free (gpointer data)
|
||||
{
|
||||
Texture *t = data;
|
||||
guint i;
|
||||
|
||||
if (t->user)
|
||||
gdk_texture_clear_render_data (t->user);
|
||||
|
||||
if (t->fbo.fbo_id != 0)
|
||||
fbo_clear (&t->fbo);
|
||||
|
||||
if (t->texture_id != 0)
|
||||
{
|
||||
glDeleteTextures (1, &t->texture_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert_cmpint (t->n_slices, >, 0);
|
||||
|
||||
for (i = 0; i < t->n_slices; i ++)
|
||||
glDeleteTextures (1, &t->slices[i].texture_id);
|
||||
}
|
||||
|
||||
g_slice_free (Texture, t);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_set_texture_parameters (GskGLDriver *self,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
|
||||
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_finalize (GObject *gobject)
|
||||
{
|
||||
GskGLDriver *self = GSK_GL_DRIVER (gobject);
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
g_clear_pointer (&self->textures, g_hash_table_unref);
|
||||
g_clear_pointer (&self->pointer_textures, g_hash_table_unref);
|
||||
g_clear_object (&self->profiler);
|
||||
|
||||
if (self->gl_context == gdk_gl_context_get_current ())
|
||||
gdk_gl_context_clear_current ();
|
||||
|
||||
G_OBJECT_CLASS (gsk_gl_driver_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_class_init (GskGLDriverClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = gsk_gl_driver_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_init (GskGLDriver *self)
|
||||
{
|
||||
self->textures = g_hash_table_new_full (NULL, NULL, NULL, texture_free);
|
||||
|
||||
self->max_texture_size = -1;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
self->profiler = gsk_profiler_new ();
|
||||
self->counters.created_textures = gsk_profiler_add_counter (self->profiler,
|
||||
"created_textures",
|
||||
"Textures created this frame",
|
||||
TRUE);
|
||||
self->counters.reused_textures = gsk_profiler_add_counter (self->profiler,
|
||||
"reused_textures",
|
||||
"Textures reused this frame",
|
||||
TRUE);
|
||||
self->counters.surface_uploads = gsk_profiler_add_counter (self->profiler,
|
||||
"surface_uploads",
|
||||
"Texture uploads from surfaces this frame",
|
||||
TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
GskGLDriver *
|
||||
gsk_gl_driver_new (GdkGLContext *context)
|
||||
{
|
||||
GskGLDriver *self;
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
|
||||
|
||||
self = (GskGLDriver *) g_object_new (GSK_TYPE_GL_DRIVER, NULL);
|
||||
self->gl_context = context;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_begin_frame (GskGLDriver *self)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (self));
|
||||
g_return_if_fail (!self->in_frame);
|
||||
|
||||
self->in_frame = TRUE;
|
||||
|
||||
if (self->max_texture_size < 0)
|
||||
{
|
||||
glGetIntegerv (GL_MAX_TEXTURE_SIZE, (GLint *) &self->max_texture_size);
|
||||
GSK_NOTE (OPENGL, g_message ("GL max texture size: %d", self->max_texture_size));
|
||||
}
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, 0);
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
|
||||
glActiveTexture (GL_TEXTURE0 + 1);
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
|
||||
glBindVertexArray (0);
|
||||
glUseProgram (0);
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_reset (self->profiler);
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_gl_driver_in_frame (GskGLDriver *self)
|
||||
{
|
||||
return self->in_frame;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_end_frame (GskGLDriver *self)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (self));
|
||||
g_return_if_fail (self->in_frame);
|
||||
|
||||
self->bound_source_texture = NULL;
|
||||
|
||||
self->default_fbo.fbo_id = 0;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
GSK_NOTE (OPENGL,
|
||||
g_message ("Textures created: %" G_GINT64_FORMAT "\n"
|
||||
" Textures reused: %" G_GINT64_FORMAT "\n"
|
||||
" Surface uploads: %" G_GINT64_FORMAT,
|
||||
gsk_profiler_counter_get (self->profiler, self->counters.created_textures),
|
||||
gsk_profiler_counter_get (self->profiler, self->counters.reused_textures),
|
||||
gsk_profiler_counter_get (self->profiler, self->counters.surface_uploads)));
|
||||
#endif
|
||||
|
||||
GSK_NOTE (OPENGL,
|
||||
g_message ("*** Frame end: textures=%d",
|
||||
g_hash_table_size (self->textures)));
|
||||
|
||||
self->in_frame = FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_collect_textures (GskGLDriver *self)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value_p = NULL;
|
||||
int old_size;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
|
||||
g_return_val_if_fail (!self->in_frame, 0);
|
||||
|
||||
old_size = g_hash_table_size (self->textures);
|
||||
|
||||
g_hash_table_iter_init (&iter, self->textures);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value_p))
|
||||
{
|
||||
Texture *t = value_p;
|
||||
|
||||
if (t->user || t->permanent)
|
||||
continue;
|
||||
|
||||
if (t->in_use)
|
||||
{
|
||||
t->in_use = FALSE;
|
||||
|
||||
if (t->fbo.fbo_id != 0)
|
||||
{
|
||||
fbo_clear (&t->fbo);
|
||||
t->fbo.fbo_id = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove from self->pointer_textures. */
|
||||
/* TODO: Is there a better way for this? */
|
||||
if (self->pointer_textures)
|
||||
{
|
||||
GHashTableIter pointer_iter;
|
||||
gpointer value;
|
||||
gpointer p;
|
||||
|
||||
g_hash_table_iter_init (&pointer_iter, self->pointer_textures);
|
||||
while (g_hash_table_iter_next (&pointer_iter, &p, &value))
|
||||
{
|
||||
if (GPOINTER_TO_INT (value) == t->texture_id)
|
||||
{
|
||||
g_hash_table_iter_remove (&pointer_iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_iter_remove (&iter);
|
||||
}
|
||||
}
|
||||
|
||||
return old_size - g_hash_table_size (self->textures);
|
||||
}
|
||||
|
||||
|
||||
GdkGLContext *
|
||||
gsk_gl_driver_get_gl_context (GskGLDriver *self)
|
||||
{
|
||||
return self->gl_context;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_get_max_texture_size (GskGLDriver *self)
|
||||
{
|
||||
if (self->max_texture_size < 0)
|
||||
{
|
||||
if (gdk_gl_context_get_use_es (self->gl_context))
|
||||
return 2048;
|
||||
|
||||
return 1024;
|
||||
}
|
||||
|
||||
return self->max_texture_size;
|
||||
}
|
||||
|
||||
static Texture *
|
||||
gsk_gl_driver_get_texture (GskGLDriver *self,
|
||||
int texture_id)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
if (g_hash_table_lookup_extended (self->textures, GINT_TO_POINTER (texture_id), NULL, (gpointer *) &t))
|
||||
return t;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Texture *
|
||||
create_texture (GskGLDriver *self,
|
||||
float fwidth,
|
||||
float fheight)
|
||||
{
|
||||
guint texture_id;
|
||||
Texture *t;
|
||||
int width = ceilf (fwidth);
|
||||
int height = ceilf (fheight);
|
||||
|
||||
g_assert (width > 0);
|
||||
g_assert (height > 0);
|
||||
|
||||
if (width > self->max_texture_size ||
|
||||
height > self->max_texture_size)
|
||||
{
|
||||
g_critical ("Texture %d x %d is bigger than supported texture limit of %d; clipping...",
|
||||
width, height,
|
||||
self->max_texture_size);
|
||||
|
||||
width = MIN (width, self->max_texture_size);
|
||||
height = MIN (height, self->max_texture_size);
|
||||
}
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
t = texture_new ();
|
||||
t->texture_id = texture_id;
|
||||
t->width = width;
|
||||
t->height = height;
|
||||
t->min_filter = GL_NEAREST;
|
||||
t->mag_filter = GL_NEAREST;
|
||||
t->in_use = TRUE;
|
||||
g_hash_table_insert (self->textures, GINT_TO_POINTER (texture_id), t);
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_counter_inc (self->profiler, self->counters.created_textures);
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_driver_release_texture (gpointer data)
|
||||
{
|
||||
Texture *t = data;
|
||||
|
||||
t->user = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_slice_texture (GskGLDriver *self,
|
||||
GdkTexture *texture,
|
||||
TextureSlice **out_slices,
|
||||
guint *out_n_slices)
|
||||
{
|
||||
const int max_texture_size = gsk_gl_driver_get_max_texture_size (self) / 4; // XXX Too much?
|
||||
const int cols = (texture->width / max_texture_size) + 1;
|
||||
const int rows = (texture->height / max_texture_size) + 1;
|
||||
int col, row;
|
||||
int x = 0, y = 0; /* Position in the texture */
|
||||
TextureSlice *slices;
|
||||
Texture *tex;
|
||||
|
||||
g_assert (texture->width > max_texture_size || texture->height > max_texture_size);
|
||||
|
||||
|
||||
tex = gdk_texture_get_render_data (texture, self);
|
||||
|
||||
if (tex != NULL)
|
||||
{
|
||||
g_assert (tex->n_slices > 0);
|
||||
*out_slices = tex->slices;
|
||||
*out_n_slices = tex->n_slices;
|
||||
return;
|
||||
}
|
||||
|
||||
slices = g_new0 (TextureSlice, cols * rows);
|
||||
|
||||
for (col = 0; col < cols; col ++)
|
||||
{
|
||||
const int slice_width = MIN (max_texture_size, texture->width - x);
|
||||
|
||||
for (row = 0; row < rows; row ++)
|
||||
{
|
||||
const int slice_height = MIN (max_texture_size, texture->height - y);
|
||||
const int slice_index = (col * rows) + row;
|
||||
guint texture_id;
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_counter_inc (self->profiler, self->counters.created_textures);
|
||||
#endif
|
||||
glBindTexture (GL_TEXTURE_2D, texture_id);
|
||||
gsk_gl_driver_set_texture_parameters (self, GL_NEAREST, GL_NEAREST);
|
||||
upload_gdk_texture (texture, GL_TEXTURE_2D, x, y, slice_width, slice_height);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads);
|
||||
#endif
|
||||
|
||||
slices[slice_index].rect = (GdkRectangle){x, y, slice_width, slice_height};
|
||||
slices[slice_index].texture_id = texture_id;
|
||||
|
||||
y += slice_height;
|
||||
}
|
||||
|
||||
y = 0;
|
||||
x += slice_width;
|
||||
}
|
||||
|
||||
/* Allocate one Texture for the entire thing. */
|
||||
tex = texture_new ();
|
||||
tex->width = texture->width;
|
||||
tex->height = texture->height;
|
||||
tex->min_filter = GL_NEAREST;
|
||||
tex->mag_filter = GL_NEAREST;
|
||||
tex->in_use = TRUE;
|
||||
tex->slices = slices;
|
||||
tex->n_slices = cols * rows;
|
||||
|
||||
/* Use texture_free as destroy notify here since we are not inserting this Texture
|
||||
* into self->textures! */
|
||||
gdk_texture_set_render_data (texture, self, tex, texture_free);
|
||||
|
||||
*out_slices = slices;
|
||||
*out_n_slices = cols * rows;
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
|
||||
GdkTexture *texture,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
Texture *t;
|
||||
GdkTexture *downloaded_texture = NULL;
|
||||
GdkTexture *source_texture;
|
||||
|
||||
if (GDK_IS_GL_TEXTURE (texture))
|
||||
{
|
||||
GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
|
||||
GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
|
||||
|
||||
if (gdk_gl_context_is_shared (self->gl_context, texture_context))
|
||||
{
|
||||
/* A GL texture from the same GL context is a simple task... */
|
||||
return gdk_gl_texture_get_id (gl_texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
|
||||
/* In this case, we have to temporarily make the texture's context the current one,
|
||||
* download its data into our context and then create a texture from it. */
|
||||
if (texture_context)
|
||||
gdk_gl_context_make_current (texture_context);
|
||||
|
||||
surface = gdk_texture_download_surface (texture);
|
||||
downloaded_texture = gdk_texture_new_for_surface (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
source_texture = downloaded_texture;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t = gdk_texture_get_render_data (texture, self);
|
||||
|
||||
if (t)
|
||||
{
|
||||
if (t->min_filter == min_filter && t->mag_filter == mag_filter)
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
source_texture = texture;
|
||||
}
|
||||
|
||||
t = create_texture (self, gdk_texture_get_width (texture), gdk_texture_get_height (texture));
|
||||
|
||||
if (gdk_texture_set_render_data (texture, self, t, gsk_gl_driver_release_texture))
|
||||
t->user = texture;
|
||||
|
||||
gsk_gl_driver_bind_source_texture (self, t->texture_id);
|
||||
gsk_gl_driver_init_texture (self,
|
||||
t->texture_id,
|
||||
source_texture,
|
||||
min_filter,
|
||||
mag_filter);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id,
|
||||
"GdkTexture<%p> %d", texture, t->texture_id);
|
||||
|
||||
if (downloaded_texture)
|
||||
g_object_unref (downloaded_texture);
|
||||
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
static guint
|
||||
texture_key_hash (gconstpointer v)
|
||||
{
|
||||
const GskTextureKey *k = (GskTextureKey *)v;
|
||||
|
||||
return GPOINTER_TO_UINT (k->pointer)
|
||||
+ (guint)(k->scale_x * 100)
|
||||
+ (guint)(k->scale_y * 100)
|
||||
+ (guint)k->filter * 2 +
|
||||
+ (guint)k->pointer_is_child;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
texture_key_equal (gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
const GskTextureKey *k1 = (GskTextureKey *)v1;
|
||||
const GskTextureKey *k2 = (GskTextureKey *)v2;
|
||||
|
||||
return k1->pointer == k2->pointer &&
|
||||
k1->scale_x == k2->scale_x &&
|
||||
k1->scale_y == k2->scale_y &&
|
||||
k1->filter == k2->filter &&
|
||||
k1->pointer_is_child == k2->pointer_is_child &&
|
||||
(!k1->pointer_is_child || graphene_rect_equal (&k1->parent_rect, &k2->parent_rect));
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_get_texture_for_key (GskGLDriver *self,
|
||||
GskTextureKey *key)
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
if (G_UNLIKELY (self->pointer_textures == NULL))
|
||||
self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
|
||||
|
||||
id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, key));
|
||||
|
||||
if (id != 0)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
t = g_hash_table_lookup (self->textures, GINT_TO_POINTER (id));
|
||||
|
||||
if (t != NULL)
|
||||
t->in_use = TRUE;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_set_texture_for_key (GskGLDriver *self,
|
||||
GskTextureKey *key,
|
||||
int texture_id)
|
||||
{
|
||||
GskTextureKey *k;
|
||||
|
||||
if (G_UNLIKELY (self->pointer_textures == NULL))
|
||||
self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
|
||||
|
||||
k = g_new (GskTextureKey, 1);
|
||||
*k = *key;
|
||||
|
||||
g_hash_table_insert (self->pointer_textures, k, GINT_TO_POINTER (texture_id));
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_driver_create_texture (GskGLDriver *self,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), -1);
|
||||
|
||||
t = create_texture (self, width, height);
|
||||
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_create_render_target (GskGLDriver *self,
|
||||
int width,
|
||||
int height,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
int *out_texture_id,
|
||||
int *out_render_target_id)
|
||||
{
|
||||
GLuint fbo_id;
|
||||
Texture *texture;
|
||||
|
||||
g_return_if_fail (self->in_frame);
|
||||
|
||||
texture = create_texture (self, width, height);
|
||||
gsk_gl_driver_bind_source_texture (self, texture->texture_id);
|
||||
gsk_gl_driver_init_texture_empty (self, texture->texture_id, min_filter, mag_filter);
|
||||
|
||||
glGenFramebuffers (1, &fbo_id);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
|
||||
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture_id, 0);
|
||||
|
||||
#if 0
|
||||
if (add_depth_buffer || add_stencil_buffer)
|
||||
{
|
||||
glGenRenderbuffersEXT (1, &depth_stencil_buffer_id);
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_RENDERBUFFER, depth_stencil_buffer_id,
|
||||
"%s buffer for %d", add_depth_buffer ? "Depth" : "Stencil", texture_id);
|
||||
}
|
||||
else
|
||||
depth_stencil_buffer_id = 0;
|
||||
|
||||
glBindRenderbuffer (GL_RENDERBUFFER, depth_stencil_buffer_id);
|
||||
|
||||
if (add_depth_buffer || add_stencil_buffer)
|
||||
{
|
||||
if (add_stencil_buffer)
|
||||
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, t->width, t->height);
|
||||
else
|
||||
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, t->width, t->height);
|
||||
|
||||
if (add_depth_buffer)
|
||||
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
||||
GL_RENDERBUFFER, depth_stencil_buffer_id);
|
||||
|
||||
if (add_stencil_buffer)
|
||||
glFramebufferRenderbufferEXT (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, depth_stencil_buffer_id);
|
||||
texture->fbo.depth_stencil_id = depth_stencil_buffer_id;
|
||||
}
|
||||
#endif
|
||||
|
||||
texture->fbo.fbo_id = fbo_id;
|
||||
|
||||
g_assert_cmphex (glCheckFramebufferStatus (GL_FRAMEBUFFER), ==, GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, self->default_fbo.fbo_id);
|
||||
|
||||
*out_texture_id = texture->texture_id;
|
||||
*out_render_target_id = fbo_id;
|
||||
}
|
||||
|
||||
/* Mark the texture permanent, meaning it won'e be reused by the GLDriver.
|
||||
* E.g. to store it in some other cache. */
|
||||
void
|
||||
gsk_gl_driver_mark_texture_permanent (GskGLDriver *self,
|
||||
int texture_id)
|
||||
{
|
||||
Texture *t = gsk_gl_driver_get_texture (self, texture_id);
|
||||
|
||||
g_assert (t != NULL);
|
||||
|
||||
t->permanent = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_bind_source_texture (GskGLDriver *self,
|
||||
int texture_id)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (self));
|
||||
g_return_if_fail (self->in_frame);
|
||||
|
||||
t = gsk_gl_driver_get_texture (self, texture_id);
|
||||
if (t == NULL)
|
||||
{
|
||||
g_critical ("No texture %d found.", texture_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->bound_source_texture != t)
|
||||
{
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, t->texture_id);
|
||||
|
||||
self->bound_source_texture = t;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_destroy_texture (GskGLDriver *self,
|
||||
int texture_id)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (self));
|
||||
|
||||
g_hash_table_remove (self->textures, GINT_TO_POINTER (texture_id));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gsk_gl_driver_init_texture_empty (GskGLDriver *self,
|
||||
int texture_id,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (self));
|
||||
|
||||
t = gsk_gl_driver_get_texture (self, texture_id);
|
||||
if (t == NULL)
|
||||
{
|
||||
g_critical ("No texture %d found.", texture_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->bound_source_texture != t)
|
||||
{
|
||||
g_critical ("You must bind the texture before initializing it.");
|
||||
return;
|
||||
}
|
||||
|
||||
t->min_filter = min_filter;
|
||||
t->mag_filter = mag_filter;
|
||||
|
||||
gsk_gl_driver_set_texture_parameters (self, t->min_filter, t->mag_filter);
|
||||
|
||||
if (gdk_gl_context_get_use_es (self->gl_context))
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
else
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, t->width, t->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
filter_uses_mipmaps (int filter)
|
||||
{
|
||||
return filter != GL_NEAREST && filter != GL_LINEAR;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_driver_init_texture (GskGLDriver *self,
|
||||
int texture_id,
|
||||
GdkTexture *texture,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
Texture *t;
|
||||
|
||||
g_return_if_fail (GSK_IS_GL_DRIVER (self));
|
||||
|
||||
t = gsk_gl_driver_get_texture (self, texture_id);
|
||||
if (t == NULL)
|
||||
{
|
||||
g_critical ("No texture %d found.", texture_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->bound_source_texture != t)
|
||||
{
|
||||
g_critical ("You must bind the texture before initializing it.");
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_gl_driver_set_texture_parameters (self, min_filter, mag_filter);
|
||||
|
||||
upload_gdk_texture (texture, GL_TEXTURE_2D, 0, 0, t->width, t->height);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
gsk_profiler_counter_inc (self->profiler, self->counters.surface_uploads);
|
||||
#endif
|
||||
|
||||
t->min_filter = min_filter;
|
||||
t->mag_filter = mag_filter;
|
||||
|
||||
if (filter_uses_mipmaps (t->min_filter))
|
||||
glGenerateMipmap (GL_TEXTURE_2D);
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
#ifndef __GSK_GL_DRIVER_PRIVATE_H__
|
||||
#define __GSK_GL_DRIVER_PRIVATE_H__
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <graphene.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GL_DRIVER (gsk_gl_driver_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GskGLDriver, gsk_gl_driver, GSK, GL_DRIVER, GObject)
|
||||
|
||||
typedef struct {
|
||||
float position[2];
|
||||
float uv[2];
|
||||
} GskQuadVertex;
|
||||
|
||||
typedef struct {
|
||||
cairo_rectangle_int_t rect;
|
||||
guint texture_id;
|
||||
} TextureSlice;
|
||||
|
||||
typedef struct {
|
||||
gpointer pointer;
|
||||
float scale_x;
|
||||
float scale_y;
|
||||
int filter;
|
||||
int pointer_is_child;
|
||||
graphene_rect_t parent_rect; /* Only set if pointer_is_child */
|
||||
} GskTextureKey;
|
||||
|
||||
GskGLDriver * gsk_gl_driver_new (GdkGLContext *context);
|
||||
GdkGLContext *gsk_gl_driver_get_gl_context (GskGLDriver *driver);
|
||||
|
||||
int gsk_gl_driver_get_max_texture_size (GskGLDriver *driver);
|
||||
|
||||
void gsk_gl_driver_begin_frame (GskGLDriver *driver);
|
||||
void gsk_gl_driver_end_frame (GskGLDriver *driver);
|
||||
gboolean gsk_gl_driver_in_frame (GskGLDriver *driver);
|
||||
int gsk_gl_driver_get_texture_for_texture (GskGLDriver *driver,
|
||||
GdkTexture *texture,
|
||||
int min_filter,
|
||||
int mag_filter);
|
||||
int gsk_gl_driver_get_texture_for_key (GskGLDriver *driver,
|
||||
GskTextureKey *key);
|
||||
void gsk_gl_driver_set_texture_for_key (GskGLDriver *driver,
|
||||
GskTextureKey *key,
|
||||
int texture_id);
|
||||
int gsk_gl_driver_create_texture (GskGLDriver *driver,
|
||||
float width,
|
||||
float height);
|
||||
void gsk_gl_driver_create_render_target (GskGLDriver *driver,
|
||||
int width,
|
||||
int height,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
int *out_texture_id,
|
||||
int *out_render_target_id);
|
||||
void gsk_gl_driver_mark_texture_permanent (GskGLDriver *self,
|
||||
int texture_id);
|
||||
void gsk_gl_driver_bind_source_texture (GskGLDriver *driver,
|
||||
int texture_id);
|
||||
|
||||
void gsk_gl_driver_init_texture_empty (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
int min_filter,
|
||||
int max_filter);
|
||||
void gsk_gl_driver_init_texture (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
GdkTexture *texture,
|
||||
int min_filter,
|
||||
int mag_filter);
|
||||
|
||||
void gsk_gl_driver_destroy_texture (GskGLDriver *driver,
|
||||
int texture_id);
|
||||
|
||||
int gsk_gl_driver_collect_textures (GskGLDriver *driver);
|
||||
void gsk_gl_driver_slice_texture (GskGLDriver *self,
|
||||
GdkTexture *texture,
|
||||
TextureSlice **out_slices,
|
||||
guint *out_n_slices);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_DRIVER_PRIVATE_H__ */
|
||||
@@ -1,397 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglglyphcacheprivate.h"
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskprivate.h"
|
||||
#include "gskgltextureatlasprivate.h"
|
||||
|
||||
#include "gdk/gdkglcontextprivate.h"
|
||||
#include "gdk/gdkmemorytextureprivate.h"
|
||||
|
||||
#include <graphene.h>
|
||||
#include <cairo.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Cache eviction strategy
|
||||
*
|
||||
* We mark glyphs as accessed every time we use them.
|
||||
* Every few frames, we mark glyphs that haven't been
|
||||
* accessed since the last check as old.
|
||||
*
|
||||
* We keep count of the pixels of each atlas that are
|
||||
* taken up by old data. When the fraction of old pixels
|
||||
* gets too high, we drop the atlas and all the items it
|
||||
* contained.
|
||||
*
|
||||
* Big glyphs are not stored in the atlas, they get their
|
||||
* own texture, but they are still cached.
|
||||
*/
|
||||
|
||||
#define MAX_FRAME_AGE (60)
|
||||
#define MAX_GLYPH_SIZE 128 /* Will get its own texture if bigger */
|
||||
|
||||
static guint glyph_cache_hash (gconstpointer v);
|
||||
static gboolean glyph_cache_equal (gconstpointer v1,
|
||||
gconstpointer v2);
|
||||
static void glyph_cache_key_free (gpointer v);
|
||||
static void glyph_cache_value_free (gpointer v);
|
||||
|
||||
GskGLGlyphCache *
|
||||
gsk_gl_glyph_cache_new (GdkDisplay *display,
|
||||
GskGLTextureAtlases *atlases)
|
||||
{
|
||||
GskGLGlyphCache *glyph_cache;
|
||||
|
||||
glyph_cache = g_new0 (GskGLGlyphCache, 1);
|
||||
|
||||
glyph_cache->display = display;
|
||||
glyph_cache->hash_table = g_hash_table_new_full (glyph_cache_hash, glyph_cache_equal,
|
||||
glyph_cache_key_free, glyph_cache_value_free);
|
||||
|
||||
glyph_cache->atlases = gsk_gl_texture_atlases_ref (atlases);
|
||||
|
||||
glyph_cache->ref_count = 1;
|
||||
|
||||
return glyph_cache;
|
||||
}
|
||||
|
||||
GskGLGlyphCache *
|
||||
gsk_gl_glyph_cache_ref (GskGLGlyphCache *self)
|
||||
{
|
||||
self->ref_count++;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_glyph_cache_unref (GskGLGlyphCache *self)
|
||||
{
|
||||
g_assert (self->ref_count > 0);
|
||||
|
||||
if (self->ref_count == 1)
|
||||
{
|
||||
gsk_gl_texture_atlases_unref (self->atlases);
|
||||
g_hash_table_unref (self->hash_table);
|
||||
g_free (self);
|
||||
return;
|
||||
}
|
||||
|
||||
self->ref_count--;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
glyph_cache_equal (gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
return memcmp (v1, v2, sizeof (CacheKeyData)) == 0;
|
||||
}
|
||||
|
||||
static guint
|
||||
glyph_cache_hash (gconstpointer v)
|
||||
{
|
||||
const GlyphCacheKey *key = v;
|
||||
|
||||
return key->hash;
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_cache_key_free (gpointer v)
|
||||
{
|
||||
GlyphCacheKey *f = v;
|
||||
|
||||
g_object_unref (f->data.font);
|
||||
g_free (f);
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_cache_value_free (gpointer v)
|
||||
{
|
||||
g_free (v);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
render_glyph (GlyphCacheKey *key,
|
||||
GskGLCachedGlyph *value,
|
||||
GskImageRegion *region)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
PangoGlyphString glyph_string;
|
||||
PangoGlyphInfo glyph_info;
|
||||
int surface_width, surface_height;
|
||||
int stride;
|
||||
unsigned char *data;
|
||||
|
||||
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)key->data.font);
|
||||
if (G_UNLIKELY (!scaled_font || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
|
||||
{
|
||||
g_warning ("Failed to get a font");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
surface_width = value->draw_width * key->data.scale / 1024;
|
||||
surface_height = value->draw_height * key->data.scale / 1024;
|
||||
|
||||
stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, surface_width);
|
||||
data = g_malloc0 (stride * surface_height);
|
||||
surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32,
|
||||
surface_width, surface_height,
|
||||
stride);
|
||||
cairo_surface_set_device_scale (surface, key->data.scale / 1024.0, key->data.scale / 1024.0);
|
||||
|
||||
cr = cairo_create (surface);
|
||||
|
||||
cairo_set_scaled_font (cr, scaled_font);
|
||||
cairo_set_source_rgba (cr, 1, 1, 1, 1);
|
||||
|
||||
glyph_info.glyph = key->data.glyph;
|
||||
glyph_info.geometry.width = value->draw_width * 1024;
|
||||
if (glyph_info.glyph & PANGO_GLYPH_UNKNOWN_FLAG)
|
||||
glyph_info.geometry.x_offset = 256 * key->data.xshift;
|
||||
else
|
||||
glyph_info.geometry.x_offset = 256 * key->data.xshift - value->draw_x * 1024;
|
||||
glyph_info.geometry.y_offset = 256 * key->data.yshift - value->draw_y * 1024;
|
||||
|
||||
glyph_string.num_glyphs = 1;
|
||||
glyph_string.glyphs = &glyph_info;
|
||||
|
||||
pango_cairo_show_glyph_string (cr, key->data.font, &glyph_string);
|
||||
cairo_destroy (cr);
|
||||
|
||||
cairo_surface_flush (surface);
|
||||
|
||||
region->width = cairo_image_surface_get_width (surface);
|
||||
region->height = cairo_image_surface_get_height (surface);
|
||||
region->stride = cairo_image_surface_get_stride (surface);
|
||||
region->data = data;
|
||||
if (value->atlas)
|
||||
{
|
||||
region->x = (gsize)(value->tx * value->atlas->width);
|
||||
region->y = (gsize)(value->ty * value->atlas->height);
|
||||
}
|
||||
else
|
||||
{
|
||||
region->x = 0;
|
||||
region->y = 0;
|
||||
}
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
upload_glyph (GlyphCacheKey *key,
|
||||
GskGLCachedGlyph *value)
|
||||
{
|
||||
GskImageRegion r;
|
||||
guchar *pixel_data;
|
||||
guchar *free_data = NULL;
|
||||
guint gl_format;
|
||||
guint gl_type;
|
||||
|
||||
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
|
||||
"Uploading glyph %d",
|
||||
key->data.glyph);
|
||||
|
||||
if (render_glyph (key, value, &r))
|
||||
{
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, r.stride / 4);
|
||||
glBindTexture (GL_TEXTURE_2D, value->texture_id);
|
||||
|
||||
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
|
||||
{
|
||||
pixel_data = free_data = g_malloc (r.width * r.height * 4);
|
||||
gdk_memory_convert (pixel_data, r.width * 4,
|
||||
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
||||
r.data, r.width * 4,
|
||||
GDK_MEMORY_DEFAULT, r.width, r.height);
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel_data = r.data;
|
||||
gl_format = GL_BGRA;
|
||||
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
}
|
||||
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height,
|
||||
gl_format, gl_type, pixel_data);
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
g_free (r.data);
|
||||
g_free (free_data);
|
||||
}
|
||||
|
||||
gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
|
||||
}
|
||||
|
||||
static void
|
||||
add_to_cache (GskGLGlyphCache *self,
|
||||
GlyphCacheKey *key,
|
||||
GskGLDriver *driver,
|
||||
GskGLCachedGlyph *value)
|
||||
{
|
||||
const int width = value->draw_width * key->data.scale / 1024;
|
||||
const int height = value->draw_height * key->data.scale / 1024;
|
||||
|
||||
if (width < MAX_GLYPH_SIZE && height < MAX_GLYPH_SIZE)
|
||||
{
|
||||
GskGLTextureAtlas *atlas = NULL;
|
||||
int packed_x = 0;
|
||||
int packed_y = 0;
|
||||
|
||||
gsk_gl_texture_atlases_pack (self->atlases, width + 2, height + 2, &atlas, &packed_x, &packed_y);
|
||||
|
||||
value->tx = (float)(packed_x + 1) / atlas->width;
|
||||
value->ty = (float)(packed_y + 1) / atlas->height;
|
||||
value->tw = (float)width / atlas->width;
|
||||
value->th = (float)height / atlas->height;
|
||||
value->used = TRUE;
|
||||
|
||||
value->atlas = atlas;
|
||||
value->texture_id = atlas->texture_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
value->atlas = NULL;
|
||||
value->texture_id = gsk_gl_driver_create_texture (driver, width, height);
|
||||
gsk_gl_driver_mark_texture_permanent (driver, value->texture_id);
|
||||
|
||||
gsk_gl_driver_bind_source_texture (driver, value->texture_id);
|
||||
gsk_gl_driver_init_texture_empty (driver, value->texture_id, GL_LINEAR, GL_LINEAR);
|
||||
|
||||
value->tx = 0.0f;
|
||||
value->ty = 0.0f;
|
||||
value->tw = 1.0f;
|
||||
value->th = 1.0f;
|
||||
}
|
||||
|
||||
upload_glyph (key, value);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache *cache,
|
||||
GlyphCacheKey *lookup,
|
||||
GskGLDriver *driver,
|
||||
const GskGLCachedGlyph **cached_glyph_out)
|
||||
{
|
||||
GskGLCachedGlyph *value;
|
||||
|
||||
value = g_hash_table_lookup (cache->hash_table, lookup);
|
||||
|
||||
if (value)
|
||||
{
|
||||
if (value->atlas && !value->used)
|
||||
{
|
||||
gsk_gl_texture_atlas_mark_used (value->atlas, value->draw_width, value->draw_height);
|
||||
value->used = TRUE;
|
||||
}
|
||||
value->accessed = TRUE;
|
||||
|
||||
*cached_glyph_out = value;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
GlyphCacheKey *key;
|
||||
PangoRectangle ink_rect;
|
||||
|
||||
pango_font_get_glyph_extents (lookup->data.font, lookup->data.glyph, &ink_rect, NULL);
|
||||
pango_extents_to_pixels (&ink_rect, NULL);
|
||||
if (lookup->data.xshift != 0)
|
||||
ink_rect.width += 1;
|
||||
if (lookup->data.yshift != 0)
|
||||
ink_rect.height += 1;
|
||||
|
||||
value = g_new0 (GskGLCachedGlyph, 1);
|
||||
|
||||
value->draw_x = ink_rect.x;
|
||||
value->draw_y = ink_rect.y;
|
||||
value->draw_width = ink_rect.width;
|
||||
value->draw_height = ink_rect.height;
|
||||
value->accessed = TRUE;
|
||||
value->atlas = NULL; /* For now */
|
||||
|
||||
key = g_new0 (GlyphCacheKey, 1);
|
||||
|
||||
key->data.font = g_object_ref (lookup->data.font);
|
||||
key->data.glyph = lookup->data.glyph;
|
||||
key->data.xshift = lookup->data.xshift;
|
||||
key->data.yshift = lookup->data.yshift;
|
||||
key->data.scale = lookup->data.scale;
|
||||
key->hash = lookup->hash;
|
||||
|
||||
if (key->data.scale > 0 &&
|
||||
value->draw_width * key->data.scale / 1024 > 0 &&
|
||||
value->draw_height * key->data.scale / 1024 > 0)
|
||||
add_to_cache (cache, key, driver, value);
|
||||
|
||||
*cached_glyph_out = value;
|
||||
g_hash_table_insert (cache->hash_table, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self,
|
||||
GskGLDriver *driver,
|
||||
GPtrArray *removed_atlases)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
GlyphCacheKey *key;
|
||||
GskGLCachedGlyph *value;
|
||||
guint dropped = 0;
|
||||
|
||||
self->timestamp++;
|
||||
|
||||
if (removed_atlases->len > 0)
|
||||
{
|
||||
g_hash_table_iter_init (&iter, self->hash_table);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
|
||||
{
|
||||
if (g_ptr_array_find (removed_atlases, value->atlas, NULL))
|
||||
{
|
||||
g_hash_table_iter_remove (&iter);
|
||||
dropped++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self->timestamp % MAX_FRAME_AGE == 30)
|
||||
{
|
||||
g_hash_table_iter_init (&iter, self->hash_table);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
|
||||
{
|
||||
if (!value->accessed)
|
||||
{
|
||||
if (value->atlas)
|
||||
{
|
||||
if (value->used)
|
||||
{
|
||||
gsk_gl_texture_atlas_mark_unused (value->atlas, value->draw_width, value->draw_height);
|
||||
value->used = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gsk_gl_driver_destroy_texture (driver, value->texture_id);
|
||||
g_hash_table_iter_remove (&iter);
|
||||
|
||||
/* Sadly, if we drop an atlas-less cached glyph, we
|
||||
* have to treat it like a dropped atlas and purge
|
||||
* text node render data.
|
||||
*/
|
||||
dropped++;
|
||||
}
|
||||
}
|
||||
else
|
||||
value->accessed = FALSE;
|
||||
}
|
||||
|
||||
GSK_NOTE(GLYPH_CACHE, g_message ("%d glyphs cached", g_hash_table_size (self->hash_table)));
|
||||
}
|
||||
|
||||
GSK_NOTE(GLYPH_CACHE, if (dropped > 0) g_message ("Dropped %d glyphs", dropped));
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
#ifndef __GSK_GL_GLYPH_CACHE_PRIVATE_H__
|
||||
#define __GSK_GL_GLYPH_CACHE_PRIVATE_H__
|
||||
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskglimageprivate.h"
|
||||
#include "gskgltextureatlasprivate.h"
|
||||
#include <pango/pango.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ref_count;
|
||||
|
||||
GdkDisplay *display;
|
||||
GHashTable *hash_table;
|
||||
GskGLTextureAtlases *atlases;
|
||||
|
||||
int timestamp;
|
||||
} GskGLGlyphCache;
|
||||
|
||||
struct _CacheKeyData
|
||||
{
|
||||
PangoFont *font;
|
||||
PangoGlyph glyph;
|
||||
guint xshift : 3;
|
||||
guint yshift : 3;
|
||||
guint scale : 26; /* times 1024 */
|
||||
};
|
||||
|
||||
typedef struct _CacheKeyData CacheKeyData;
|
||||
|
||||
struct _GlyphCacheKey
|
||||
{
|
||||
CacheKeyData data;
|
||||
guint hash;
|
||||
};
|
||||
|
||||
typedef struct _GlyphCacheKey GlyphCacheKey;
|
||||
|
||||
#define PHASE(x) ((int)(floor (4 * (x + 0.125)) - 4 * floor (x + 0.125)))
|
||||
|
||||
static inline void
|
||||
glyph_cache_key_set_glyph_and_shift (GlyphCacheKey *key,
|
||||
PangoGlyph glyph,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
key->data.glyph = glyph;
|
||||
key->data.xshift = PHASE (x);
|
||||
key->data.yshift = PHASE (y);
|
||||
key->hash = GPOINTER_TO_UINT (key->data.font) ^
|
||||
key->data.glyph ^
|
||||
(key->data.xshift << 24) ^
|
||||
(key->data.yshift << 26) ^
|
||||
key->data.scale;
|
||||
}
|
||||
|
||||
typedef struct _GskGLCachedGlyph GskGLCachedGlyph;
|
||||
|
||||
struct _GskGLCachedGlyph
|
||||
{
|
||||
GskGLTextureAtlas *atlas;
|
||||
guint texture_id;
|
||||
|
||||
float tx;
|
||||
float ty;
|
||||
float tw;
|
||||
float th;
|
||||
|
||||
int draw_x;
|
||||
int draw_y;
|
||||
int draw_width;
|
||||
int draw_height;
|
||||
|
||||
guint accessed : 1; /* accessed since last check */
|
||||
guint used : 1; /* accounted as used in the atlas */
|
||||
};
|
||||
|
||||
|
||||
GskGLGlyphCache * gsk_gl_glyph_cache_new (GdkDisplay *display,
|
||||
GskGLTextureAtlases *atlases);
|
||||
GskGLGlyphCache * gsk_gl_glyph_cache_ref (GskGLGlyphCache *self);
|
||||
void gsk_gl_glyph_cache_unref (GskGLGlyphCache *self);
|
||||
void gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self,
|
||||
GskGLDriver *driver,
|
||||
GPtrArray *removed_atlases);
|
||||
void gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache *self,
|
||||
GlyphCacheKey *lookup,
|
||||
GskGLDriver *driver,
|
||||
const GskGLCachedGlyph **cached_glyph_out);
|
||||
|
||||
#endif
|
||||
@@ -1,275 +0,0 @@
|
||||
#include "gskgliconcacheprivate.h"
|
||||
#include "gskgltextureatlasprivate.h"
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
#include "gdk/gdkmemorytextureprivate.h"
|
||||
#include "gdk/gdkglcontextprivate.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#define MAX_FRAME_AGE 60
|
||||
|
||||
static void
|
||||
icon_data_free (gpointer p)
|
||||
{
|
||||
g_object_unref (((IconData *)p)->source_texture);
|
||||
g_free (p);
|
||||
}
|
||||
|
||||
GskGLIconCache *
|
||||
gsk_gl_icon_cache_new (GdkDisplay *display,
|
||||
GskGLTextureAtlases *atlases)
|
||||
{
|
||||
GskGLIconCache *self;
|
||||
|
||||
self = g_new0 (GskGLIconCache, 1);
|
||||
|
||||
self->display = display;
|
||||
self->icons = g_hash_table_new_full (NULL, NULL, NULL, icon_data_free);
|
||||
self->atlases = gsk_gl_texture_atlases_ref (atlases);
|
||||
self->ref_count = 1;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
GskGLIconCache *
|
||||
gsk_gl_icon_cache_ref (GskGLIconCache *self)
|
||||
{
|
||||
self->ref_count++;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_icon_cache_unref (GskGLIconCache *self)
|
||||
{
|
||||
g_assert (self->ref_count > 0);
|
||||
|
||||
if (self->ref_count == 1)
|
||||
{
|
||||
gsk_gl_texture_atlases_unref (self->atlases);
|
||||
g_hash_table_unref (self->icons);
|
||||
g_free (self);
|
||||
return;
|
||||
}
|
||||
|
||||
self->ref_count--;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_icon_cache_begin_frame (GskGLIconCache *self,
|
||||
GPtrArray *removed_atlases)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
GdkTexture *texture;
|
||||
IconData *icon_data;
|
||||
|
||||
self->timestamp++;
|
||||
|
||||
/* Drop icons on removed atlases */
|
||||
if (removed_atlases->len > 0)
|
||||
{
|
||||
guint dropped = 0;
|
||||
|
||||
g_hash_table_iter_init (&iter, self->icons);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *)&texture, (gpointer *)&icon_data))
|
||||
{
|
||||
if (g_ptr_array_find (removed_atlases, icon_data->atlas, NULL))
|
||||
{
|
||||
g_hash_table_iter_remove (&iter);
|
||||
dropped++;
|
||||
}
|
||||
}
|
||||
|
||||
GSK_NOTE(GLYPH_CACHE, if (dropped > 0) g_message ("Dropped %d icons", dropped));
|
||||
}
|
||||
|
||||
if (self->timestamp % MAX_FRAME_AGE == 0)
|
||||
{
|
||||
g_hash_table_iter_init (&iter, self->icons);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *)&texture, (gpointer *)&icon_data))
|
||||
{
|
||||
if (!icon_data->accessed)
|
||||
{
|
||||
if (icon_data->used)
|
||||
{
|
||||
const int width = icon_data->source_texture->width;
|
||||
const int height = icon_data->source_texture->height;
|
||||
gsk_gl_texture_atlas_mark_unused (icon_data->atlas, width + 2, height + 2);
|
||||
icon_data->used = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
icon_data->accessed = FALSE;
|
||||
}
|
||||
|
||||
GSK_NOTE(GLYPH_CACHE, g_message ("%d icons cached", g_hash_table_size (self->icons)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
|
||||
GdkTexture *texture,
|
||||
const IconData **out_icon_data)
|
||||
{
|
||||
IconData *icon_data = g_hash_table_lookup (self->icons, texture);
|
||||
|
||||
if (icon_data)
|
||||
{
|
||||
if (!icon_data->used)
|
||||
{
|
||||
gsk_gl_texture_atlas_mark_used (icon_data->atlas, texture->width + 2, texture->height + 2);
|
||||
icon_data->used = TRUE;
|
||||
}
|
||||
icon_data->accessed = TRUE;
|
||||
|
||||
*out_icon_data = icon_data;
|
||||
return;
|
||||
}
|
||||
|
||||
/* texture not on any atlas yet. Find a suitable one. */
|
||||
{
|
||||
const int width = texture->width;
|
||||
const int height = texture->height;
|
||||
GskGLTextureAtlas *atlas = NULL;
|
||||
int packed_x = 0;
|
||||
int packed_y = 0;
|
||||
cairo_surface_t *surface;
|
||||
unsigned char *surface_data;
|
||||
unsigned char *pixel_data;
|
||||
guchar *free_data = NULL;
|
||||
guint gl_format;
|
||||
guint gl_type;
|
||||
|
||||
gsk_gl_texture_atlases_pack (self->atlases, width + 2, height + 2, &atlas, &packed_x, &packed_y);
|
||||
|
||||
icon_data = g_new0 (IconData, 1);
|
||||
icon_data->atlas = atlas;
|
||||
icon_data->accessed = TRUE;
|
||||
icon_data->used = TRUE;
|
||||
icon_data->texture_id = atlas->texture_id;
|
||||
icon_data->source_texture = g_object_ref (texture);
|
||||
icon_data->x = (float)(packed_x + 1) / atlas->width;
|
||||
icon_data->y = (float)(packed_y + 1) / atlas->width;
|
||||
icon_data->x2 = icon_data->x + (float)width / atlas->width;
|
||||
icon_data->y2 = icon_data->y + (float)height / atlas->height;
|
||||
|
||||
g_hash_table_insert (self->icons, texture, icon_data);
|
||||
|
||||
/* actually upload the texture */
|
||||
surface = gdk_texture_download_surface (texture);
|
||||
surface_data = cairo_image_surface_get_data (surface);
|
||||
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
|
||||
"Uploading texture");
|
||||
|
||||
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_R8G8B8A8_PREMULTIPLIED,
|
||||
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;
|
||||
}
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
|
||||
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1, packed_y + 1,
|
||||
width, height,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
/* Padding top */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x + 1, packed_y,
|
||||
width, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
/* Padding left */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y + 1,
|
||||
1, height,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
/* Padding top left */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
|
||||
/* 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);
|
||||
/* Padding top right */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x + width + 1, packed_y,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
/* 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);
|
||||
/* Padding bottom left */
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0,
|
||||
packed_x, packed_y + 1 + height,
|
||||
1, 1,
|
||||
gl_format, gl_type,
|
||||
pixel_data);
|
||||
/* 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);
|
||||
/* Reset this */
|
||||
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
|
||||
|
||||
gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
|
||||
|
||||
*out_icon_data = icon_data;
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
g_free (free_data);
|
||||
|
||||
#if 0
|
||||
{
|
||||
static int k;
|
||||
const int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, atlas->width);
|
||||
guchar *data = g_malloc (atlas->height * stride);
|
||||
cairo_surface_t *s;
|
||||
char *filename = g_strdup_printf ("atlas_%u_%d.png", atlas->texture_id, k++);
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
|
||||
glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);
|
||||
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, atlas->width, atlas->height, stride);
|
||||
cairo_surface_write_to_png (s, filename);
|
||||
|
||||
cairo_surface_destroy (s);
|
||||
g_free (data);
|
||||
g_free (filename);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#ifndef __GSK_GL_ICON_CACHE_PRIVATE_H__
|
||||
#define __GSK_GL_ICON_CACHE_PRIVATE_H__
|
||||
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskglimageprivate.h"
|
||||
#include "gskrendererprivate.h"
|
||||
#include "gskgltextureatlasprivate.h"
|
||||
#include <pango/pango.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ref_count;
|
||||
|
||||
GdkDisplay *display;
|
||||
GskGLDriver *gl_driver;
|
||||
|
||||
GskGLTextureAtlases *atlases;
|
||||
GHashTable *icons; /* GdkTexture -> IconData */
|
||||
|
||||
int timestamp;
|
||||
} GskGLIconCache;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x, y, x2, y2;
|
||||
GskGLTextureAtlas *atlas;
|
||||
guint used : 1;
|
||||
guint accessed : 1;
|
||||
int texture_id;
|
||||
GdkTexture *source_texture;
|
||||
} IconData;
|
||||
|
||||
GskGLIconCache * gsk_gl_icon_cache_new (GdkDisplay *display,
|
||||
GskGLTextureAtlases *atlases);
|
||||
GskGLIconCache * gsk_gl_icon_cache_ref (GskGLIconCache *self);
|
||||
void gsk_gl_icon_cache_unref (GskGLIconCache *self);
|
||||
void gsk_gl_icon_cache_begin_frame (GskGLIconCache *self,
|
||||
GPtrArray *removed_atlases);
|
||||
void gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
|
||||
GdkTexture *texture,
|
||||
const IconData **out_icon_data);
|
||||
|
||||
#endif
|
||||
@@ -1,64 +0,0 @@
|
||||
|
||||
#include "gskglimageprivate.h"
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
void
|
||||
gsk_gl_image_create (GskGLImage *self,
|
||||
GskGLDriver *gl_driver,
|
||||
int width,
|
||||
int height,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
self->texture_id = gsk_gl_driver_create_texture (gl_driver, width, height);
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);
|
||||
gsk_gl_driver_init_texture_empty (gl_driver, self->texture_id, min_filter, mag_filter);
|
||||
gsk_gl_driver_mark_texture_permanent (gl_driver, self->texture_id);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_image_destroy (GskGLImage *self,
|
||||
GskGLDriver *gl_driver)
|
||||
{
|
||||
gsk_gl_driver_destroy_texture (gl_driver, self->texture_id);
|
||||
self->texture_id = 0;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_image_write_to_png (const GskGLImage *self,
|
||||
GskGLDriver *gl_driver,
|
||||
const char *filename)
|
||||
{
|
||||
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, self->width);
|
||||
guchar *data = g_malloc (self->height * stride);
|
||||
cairo_surface_t *s;
|
||||
|
||||
gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);
|
||||
glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
|
||||
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, self->width, self->height, stride);
|
||||
cairo_surface_write_to_png (s, filename);
|
||||
|
||||
cairo_surface_destroy (s);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_image_upload_region (GskGLImage *self,
|
||||
GskGLDriver *gl_driver,
|
||||
const GskImageRegion *region)
|
||||
{
|
||||
gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);
|
||||
glBindTexture (GL_TEXTURE_2D, self->texture_id);
|
||||
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0, region->x, region->y, region->width, region->height,
|
||||
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, region->data);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
/*gsk_gl_driver_bind_source_texture (gl_driver, self->texture_id);*/
|
||||
/*gsk_gl_image_dump (self, gl_driver, "/home/baedert/atlases/test_dump.png");*/
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef __GSK_GL_IMAGE_H__
|
||||
#define __GSK_GL_IMAGE_H__
|
||||
|
||||
#include "gskgldriverprivate.h"
|
||||
#include <cairo.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint texture_id;
|
||||
int width;
|
||||
int height;
|
||||
} GskGLImage;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guchar *data;
|
||||
gsize width;
|
||||
gsize height;
|
||||
gsize stride;
|
||||
gsize x;
|
||||
gsize y;
|
||||
} GskImageRegion;
|
||||
|
||||
void gsk_gl_image_create (GskGLImage *self,
|
||||
GskGLDriver *gl_driver,
|
||||
int width,
|
||||
int height,
|
||||
int min_filter,
|
||||
int mag_filter);
|
||||
void gsk_gl_image_destroy (GskGLImage *self,
|
||||
GskGLDriver *gl_driver);
|
||||
void gsk_gl_image_write_to_png (const GskGLImage *self,
|
||||
GskGLDriver *gl_driver,
|
||||
const char *filename);
|
||||
void gsk_gl_image_upload_region (GskGLImage *self,
|
||||
GskGLDriver *gl_driver,
|
||||
const GskImageRegion *region);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
#include <glib/gprintf.h>
|
||||
#include "gskglnodesampleprivate.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
void
|
||||
node_sample_init (NodeSample *self)
|
||||
{
|
||||
memset (self->nodes, 0, sizeof (self->nodes));
|
||||
self->count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
node_sample_reset (NodeSample *self)
|
||||
{
|
||||
node_sample_init (self);
|
||||
}
|
||||
|
||||
void
|
||||
node_sample_add (NodeSample *self,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
const guint node_type = gsk_render_node_get_node_type (node);
|
||||
|
||||
g_assert (node_type <= N_NODE_TYPES);
|
||||
|
||||
if (self->nodes[node_type].class_name == NULL)
|
||||
self->nodes[node_type].class_name = g_type_name_from_instance ((GTypeInstance *) node);
|
||||
|
||||
self->nodes[node_type].count ++;
|
||||
self->count ++;
|
||||
}
|
||||
|
||||
void
|
||||
node_sample_print (const NodeSample *self,
|
||||
const char *prefix)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_printf ("%s:\n", prefix);
|
||||
|
||||
for (i = 0; i < N_NODE_TYPES; i ++)
|
||||
{
|
||||
if (self->nodes[i].count > 0)
|
||||
{
|
||||
double p = (double)self->nodes[i].count / (double)self->count;
|
||||
|
||||
g_printf ("%s: %u (%.2f%%)\n", self->nodes[i].class_name, self->nodes[i].count, p * 100.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
#ifndef __GSK_GL_NODE_SAMPLE_PRIVATE_H__
|
||||
#define __GSK_GL_NODE_SAMPLE_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include "gskenums.h"
|
||||
#include "gskrendernode.h"
|
||||
|
||||
/* TODO: We have no other way for this...? */
|
||||
#define N_NODE_TYPES (GSK_DEBUG_NODE + 1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct {
|
||||
const char *class_name;
|
||||
guint count;
|
||||
} nodes[N_NODE_TYPES];
|
||||
guint count;
|
||||
} NodeSample;
|
||||
|
||||
void node_sample_init (NodeSample *self);
|
||||
void node_sample_reset (NodeSample *self);
|
||||
void node_sample_add (NodeSample *self,
|
||||
GskRenderNode *node);
|
||||
void node_sample_print (const NodeSample *self,
|
||||
const char *prefix);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2016 Endless
|
||||
* 2018 Timm Bäder <mail@baedert.org>
|
||||
*
|
||||
* 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: Timm Bäder <mail@baedert.org>
|
||||
*/
|
||||
|
||||
#ifndef __GSK_GL_RENDERER_H__
|
||||
#define __GSK_GL_RENDERER_H__
|
||||
|
||||
#include <gsk/gskrenderer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_GL_RENDERER (gsk_gl_renderer_get_type ())
|
||||
|
||||
#define GSK_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_RENDERER, GskGLRenderer))
|
||||
#define GSK_IS_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_RENDERER))
|
||||
#define GSK_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
|
||||
#define GSK_IS_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_RENDERER))
|
||||
#define GSK_GL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_RENDERER, GskGLRendererClass))
|
||||
|
||||
/**
|
||||
* GskGLRenderer:
|
||||
*
|
||||
* A GSK renderer that is using OpenGL.
|
||||
*/
|
||||
typedef struct _GskGLRenderer GskGLRenderer;
|
||||
typedef struct _GskGLRendererClass GskGLRendererClass;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_gl_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderer * gsk_gl_renderer_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_RENDERER_H__ */
|
||||
@@ -1,14 +0,0 @@
|
||||
#ifndef __GSK_GL_RENDERER_PRIVATE_H__
|
||||
#define __GSK_GL_RENDERER_PRIVATE_H__
|
||||
|
||||
#include "gskglrenderer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean gsk_gl_renderer_try_compile_gl_shader (GskGLRenderer *self,
|
||||
GskGLShader *shader,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_RENDERER_PRIVATE_H__ */
|
||||
@@ -1,976 +0,0 @@
|
||||
#include "gskglrenderopsprivate.h"
|
||||
#include "gsktransform.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskRoundedRect rect;
|
||||
bool is_rectilinear;
|
||||
} ClipStackEntry;
|
||||
|
||||
static inline gboolean
|
||||
rect_equal (const graphene_rect_t *a,
|
||||
const graphene_rect_t *b)
|
||||
{
|
||||
return memcmp (a, b, sizeof (graphene_rect_t)) == 0;
|
||||
}
|
||||
|
||||
static inline bool G_GNUC_PURE
|
||||
rounded_rect_equal (const GskRoundedRect *r1,
|
||||
const GskRoundedRect *r2)
|
||||
{
|
||||
if (r1 == r2)
|
||||
return true;
|
||||
|
||||
if (!r1)
|
||||
return false;
|
||||
|
||||
if (r1->bounds.origin.x != r2->bounds.origin.x ||
|
||||
r1->bounds.origin.y != r2->bounds.origin.y ||
|
||||
r1->bounds.size.width != r2->bounds.size.width ||
|
||||
r1->bounds.size.height != r2->bounds.size.height)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < 4; i ++)
|
||||
if (r1->corner[i].width != r2->corner[i].width ||
|
||||
r1->corner[i].height != r2->corner[i].height)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline gboolean G_GNUC_PURE
|
||||
rounded_rect_corners_equal (const GskRoundedRect *r1,
|
||||
const GskRoundedRect *r2)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!r1)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < 4; i ++)
|
||||
if (r1->corner[i].width != r2->corner[i].width ||
|
||||
r1->corner[i].height != r2->corner[i].height)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline ProgramState *
|
||||
get_current_program_state (RenderOpBuilder *builder)
|
||||
{
|
||||
if (!builder->current_program)
|
||||
return NULL;
|
||||
|
||||
return &builder->current_program->state;
|
||||
}
|
||||
|
||||
void
|
||||
ops_finish (RenderOpBuilder *builder)
|
||||
{
|
||||
if (builder->mv_stack)
|
||||
g_array_free (builder->mv_stack, TRUE);
|
||||
builder->mv_stack = NULL;
|
||||
|
||||
if (builder->clip_stack)
|
||||
g_array_free (builder->clip_stack, TRUE);
|
||||
builder->clip_stack = NULL;
|
||||
|
||||
builder->dx = 0;
|
||||
builder->dy = 0;
|
||||
builder->scale_x = 1;
|
||||
builder->scale_y = 1;
|
||||
builder->current_modelview = NULL;
|
||||
builder->current_clip = NULL;
|
||||
builder->clip_is_rectilinear = TRUE;
|
||||
builder->current_render_target = 0;
|
||||
builder->current_texture = 0;
|
||||
builder->current_program = NULL;
|
||||
graphene_matrix_init_identity (&builder->current_projection);
|
||||
builder->current_viewport = GRAPHENE_RECT_INIT (0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Debugging only! */
|
||||
void
|
||||
ops_dump_framebuffer (RenderOpBuilder *builder,
|
||||
const char *filename,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
OpDumpFrameBuffer *op;
|
||||
|
||||
op = ops_begin (builder, OP_DUMP_FRAMEBUFFER);
|
||||
op->filename = g_strdup (filename);
|
||||
op->width = width;
|
||||
op->height = height;
|
||||
}
|
||||
|
||||
void
|
||||
ops_push_debug_group (RenderOpBuilder *builder,
|
||||
const char *text)
|
||||
{
|
||||
OpDebugGroup *op;
|
||||
|
||||
op = ops_begin (builder, OP_PUSH_DEBUG_GROUP);
|
||||
strncpy (op->text, text, sizeof(op->text) - 1);
|
||||
op->text[sizeof(op->text) - 1] = 0; /* Ensure zero terminated */
|
||||
}
|
||||
|
||||
void
|
||||
ops_pop_debug_group (RenderOpBuilder *builder)
|
||||
{
|
||||
ops_begin (builder, OP_POP_DEBUG_GROUP);
|
||||
}
|
||||
|
||||
static void
|
||||
extract_matrix_metadata (GskTransform *transform,
|
||||
OpsMatrixMetadata *md)
|
||||
{
|
||||
float dummy;
|
||||
|
||||
switch (gsk_transform_get_category (transform))
|
||||
{
|
||||
case GSK_TRANSFORM_CATEGORY_IDENTITY:
|
||||
case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
|
||||
md->scale_x = 1;
|
||||
md->scale_y = 1;
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
|
||||
gsk_transform_to_affine (transform,
|
||||
&md->scale_x, &md->scale_y,
|
||||
&dummy, &dummy);
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
|
||||
case GSK_TRANSFORM_CATEGORY_ANY:
|
||||
case GSK_TRANSFORM_CATEGORY_3D:
|
||||
case GSK_TRANSFORM_CATEGORY_2D:
|
||||
{
|
||||
graphene_vec3_t col1;
|
||||
graphene_vec3_t col2;
|
||||
graphene_matrix_t m;
|
||||
|
||||
gsk_transform_to_matrix (transform, &m);
|
||||
|
||||
/* TODO: 90% sure this is incorrect. But we should never hit this code
|
||||
* path anyway. */
|
||||
graphene_vec3_init (&col1,
|
||||
graphene_matrix_get_value (&m, 0, 0),
|
||||
graphene_matrix_get_value (&m, 1, 0),
|
||||
graphene_matrix_get_value (&m, 2, 0));
|
||||
|
||||
graphene_vec3_init (&col2,
|
||||
graphene_matrix_get_value (&m, 0, 1),
|
||||
graphene_matrix_get_value (&m, 1, 1),
|
||||
graphene_matrix_get_value (&m, 2, 1));
|
||||
|
||||
md->scale_x = graphene_vec3_length (&col1);
|
||||
md->scale_y = graphene_vec3_length (&col2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ops_transform_bounds_modelview (const RenderOpBuilder *builder,
|
||||
const graphene_rect_t *src,
|
||||
graphene_rect_t *dst)
|
||||
{
|
||||
graphene_rect_t r = *src;
|
||||
|
||||
g_assert (builder->mv_stack != NULL);
|
||||
g_assert (builder->mv_stack->len >= 1);
|
||||
|
||||
r.origin.x += builder->dx;
|
||||
r.origin.y += builder->dy;
|
||||
|
||||
gsk_transform_transform_bounds (builder->current_modelview, &r, dst);
|
||||
}
|
||||
|
||||
void
|
||||
ops_init (RenderOpBuilder *builder)
|
||||
{
|
||||
memset (builder, 0, sizeof (*builder));
|
||||
|
||||
builder->current_opacity = 1.0f;
|
||||
|
||||
op_buffer_init (&builder->render_ops);
|
||||
builder->vertices = g_array_new (FALSE, TRUE, sizeof (GskQuadVertex));
|
||||
}
|
||||
|
||||
void
|
||||
ops_free (RenderOpBuilder *builder)
|
||||
{
|
||||
g_array_unref (builder->vertices);
|
||||
op_buffer_destroy (&builder->render_ops);
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_program (RenderOpBuilder *builder,
|
||||
Program *program)
|
||||
{
|
||||
OpProgram *op;
|
||||
|
||||
if (builder->current_program == program)
|
||||
return;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_PROGRAM);
|
||||
op->program = program;
|
||||
|
||||
builder->current_program = program;
|
||||
}
|
||||
|
||||
void
|
||||
ops_push_clip (RenderOpBuilder *self,
|
||||
const GskRoundedRect *clip)
|
||||
{
|
||||
ClipStackEntry entry;
|
||||
|
||||
if (G_UNLIKELY (self->clip_stack == NULL))
|
||||
self->clip_stack = g_array_new (FALSE, TRUE, sizeof (ClipStackEntry));
|
||||
|
||||
g_assert (self->clip_stack != NULL);
|
||||
|
||||
entry.rect = *clip;
|
||||
entry.is_rectilinear = gsk_rounded_rect_is_rectilinear (clip);
|
||||
g_array_append_val (self->clip_stack, entry);
|
||||
self->current_clip = &g_array_index (self->clip_stack, ClipStackEntry, self->clip_stack->len - 1).rect;
|
||||
self->clip_is_rectilinear = entry.is_rectilinear;
|
||||
}
|
||||
|
||||
void
|
||||
ops_pop_clip (RenderOpBuilder *self)
|
||||
{
|
||||
const ClipStackEntry *head;
|
||||
|
||||
g_assert (self->clip_stack);
|
||||
g_assert (self->clip_stack->len >= 1);
|
||||
|
||||
self->clip_stack->len --;
|
||||
head = &g_array_index (self->clip_stack, ClipStackEntry, self->clip_stack->len - 1);
|
||||
|
||||
if (self->clip_stack->len >= 1)
|
||||
{
|
||||
self->current_clip = &head->rect;
|
||||
self->clip_is_rectilinear = head->is_rectilinear;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->current_clip = NULL;
|
||||
self->clip_is_rectilinear = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
ops_has_clip (RenderOpBuilder *self)
|
||||
{
|
||||
return self->clip_stack != NULL &&
|
||||
self->clip_stack->len > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ops_set_modelview:
|
||||
* @builder
|
||||
* @transform: (transfer full): The new modelview transform
|
||||
*
|
||||
* This sets the modelview to the given one without looking at the
|
||||
* one that's currently set */
|
||||
void
|
||||
ops_set_modelview (RenderOpBuilder *builder,
|
||||
GskTransform *transform)
|
||||
{
|
||||
MatrixStackEntry *entry;
|
||||
|
||||
if (G_UNLIKELY (builder->mv_stack == NULL))
|
||||
builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
|
||||
|
||||
g_assert (builder->mv_stack != NULL);
|
||||
|
||||
g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1);
|
||||
entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
|
||||
|
||||
entry->transform = transform;
|
||||
|
||||
entry->metadata.dx_before = builder->dx;
|
||||
entry->metadata.dy_before = builder->dy;
|
||||
extract_matrix_metadata (entry->transform, &entry->metadata);
|
||||
|
||||
builder->dx = 0;
|
||||
builder->dy = 0;
|
||||
builder->current_modelview = entry->transform;
|
||||
builder->scale_x = entry->metadata.scale_x;
|
||||
builder->scale_y = entry->metadata.scale_y;
|
||||
}
|
||||
|
||||
/* This sets the given modelview to the one we get when multiplying
|
||||
* the given modelview with the current one. */
|
||||
void
|
||||
ops_push_modelview (RenderOpBuilder *builder,
|
||||
GskTransform *transform)
|
||||
{
|
||||
MatrixStackEntry *entry;
|
||||
|
||||
if (G_UNLIKELY (builder->mv_stack == NULL))
|
||||
builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
|
||||
|
||||
g_assert (builder->mv_stack != NULL);
|
||||
|
||||
g_array_set_size (builder->mv_stack, builder->mv_stack->len + 1);
|
||||
entry = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
|
||||
|
||||
if (G_LIKELY (builder->mv_stack->len >= 2))
|
||||
{
|
||||
const MatrixStackEntry *cur;
|
||||
GskTransform *t = NULL;
|
||||
|
||||
cur = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 2);
|
||||
/* Multiply given matrix with current modelview */
|
||||
|
||||
t = gsk_transform_translate (gsk_transform_ref (cur->transform),
|
||||
&(graphene_point_t) { builder->dx, builder->dy});
|
||||
t = gsk_transform_transform (t, transform);
|
||||
entry->transform = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->transform = gsk_transform_ref (transform);
|
||||
}
|
||||
|
||||
entry->metadata.dx_before = builder->dx;
|
||||
entry->metadata.dy_before = builder->dy;
|
||||
extract_matrix_metadata (entry->transform, &entry->metadata);
|
||||
|
||||
builder->dx = 0;
|
||||
builder->dy = 0;
|
||||
builder->scale_x = entry->metadata.scale_x;
|
||||
builder->scale_y = entry->metadata.scale_y;
|
||||
builder->current_modelview = entry->transform;
|
||||
}
|
||||
|
||||
void
|
||||
ops_pop_modelview (RenderOpBuilder *builder)
|
||||
{
|
||||
const MatrixStackEntry *head;
|
||||
|
||||
g_assert (builder->mv_stack);
|
||||
g_assert (builder->mv_stack->len >= 1);
|
||||
|
||||
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
|
||||
builder->dx = head->metadata.dx_before;
|
||||
builder->dy = head->metadata.dy_before;
|
||||
gsk_transform_unref (head->transform);
|
||||
|
||||
builder->mv_stack->len --;
|
||||
head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1);
|
||||
|
||||
if (builder->mv_stack->len >= 1)
|
||||
{
|
||||
builder->scale_x = head->metadata.scale_x;
|
||||
builder->scale_y = head->metadata.scale_y;
|
||||
builder->current_modelview = head->transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
builder->current_modelview = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
graphene_matrix_t
|
||||
ops_set_projection (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *projection)
|
||||
{
|
||||
graphene_matrix_t prev_mv;
|
||||
|
||||
prev_mv = builder->current_projection;
|
||||
builder->current_projection = *projection;
|
||||
|
||||
return prev_mv;
|
||||
}
|
||||
|
||||
graphene_rect_t
|
||||
ops_set_viewport (RenderOpBuilder *builder,
|
||||
const graphene_rect_t *viewport)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (builder);
|
||||
OpViewport *op;
|
||||
graphene_rect_t prev_viewport;
|
||||
|
||||
if (rect_equal (&builder->current_viewport, viewport))
|
||||
return *viewport;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_VIEWPORT);
|
||||
op->viewport = *viewport;
|
||||
|
||||
if (current_program_state != NULL)
|
||||
current_program_state->viewport = *viewport;
|
||||
|
||||
prev_viewport = builder->current_viewport;
|
||||
builder->current_viewport = *viewport;
|
||||
|
||||
return prev_viewport;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_texture (RenderOpBuilder *builder,
|
||||
int texture_id)
|
||||
{
|
||||
OpTexture *op;
|
||||
|
||||
if (builder->current_texture == texture_id)
|
||||
return;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_SOURCE_TEXTURE);
|
||||
op->texture_id = texture_id;
|
||||
builder->current_texture = texture_id;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_extra_texture (RenderOpBuilder *builder,
|
||||
int texture_id,
|
||||
int idx)
|
||||
{
|
||||
OpExtraTexture *op;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_EXTRA_SOURCE_TEXTURE);
|
||||
op->texture_id = texture_id;
|
||||
op->idx = idx;
|
||||
}
|
||||
|
||||
int
|
||||
ops_set_render_target (RenderOpBuilder *builder,
|
||||
int render_target_id)
|
||||
{
|
||||
OpRenderTarget *op;
|
||||
int prev_render_target;
|
||||
|
||||
if (builder->current_render_target == render_target_id)
|
||||
return render_target_id;
|
||||
|
||||
prev_render_target = builder->current_render_target;
|
||||
|
||||
if (!(op = op_buffer_peek_tail_checked (&builder->render_ops, OP_CHANGE_RENDER_TARGET)))
|
||||
op = op_buffer_add (&builder->render_ops, OP_CHANGE_RENDER_TARGET);
|
||||
|
||||
op->render_target_id = render_target_id;
|
||||
|
||||
builder->current_render_target = render_target_id;
|
||||
|
||||
return prev_render_target;
|
||||
}
|
||||
|
||||
float
|
||||
ops_set_opacity (RenderOpBuilder *builder,
|
||||
float opacity)
|
||||
{
|
||||
float prev_opacity;
|
||||
|
||||
if (builder->current_opacity == opacity)
|
||||
return opacity;
|
||||
|
||||
prev_opacity = builder->current_opacity;
|
||||
builder->current_opacity = opacity;
|
||||
|
||||
return prev_opacity;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_color (RenderOpBuilder *builder,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (builder);
|
||||
OpColor *op;
|
||||
|
||||
if (gdk_rgba_equal (color, ¤t_program_state->color))
|
||||
return;
|
||||
|
||||
current_program_state->color = *color;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_COLOR);
|
||||
op->rgba = color;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_gl_shader_args (RenderOpBuilder *builder,
|
||||
GskGLShader *shader,
|
||||
float width,
|
||||
float height,
|
||||
const guchar *uniform_data)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (builder);
|
||||
OpGLShader *op;
|
||||
gsize args_size = gsk_gl_shader_get_args_size (shader);
|
||||
|
||||
if (current_program_state)
|
||||
{
|
||||
if (current_program_state->gl_shader.width == width &&
|
||||
current_program_state->gl_shader.height == height &&
|
||||
current_program_state->gl_shader.uniform_data_len == args_size &&
|
||||
memcmp (current_program_state->gl_shader.uniform_data, uniform_data, args_size) == 0)
|
||||
return;
|
||||
|
||||
current_program_state->gl_shader.width = width;
|
||||
current_program_state->gl_shader.height = height;
|
||||
if (args_size > sizeof (current_program_state->gl_shader.uniform_data))
|
||||
current_program_state->gl_shader.uniform_data_len = 0;
|
||||
else
|
||||
{
|
||||
current_program_state->gl_shader.uniform_data_len = args_size;
|
||||
memcpy (current_program_state->gl_shader.uniform_data, uniform_data, args_size);
|
||||
}
|
||||
}
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_GL_SHADER_ARGS);
|
||||
op->shader = shader;
|
||||
op->size[0] = width;
|
||||
op->size[1] = height;
|
||||
op->uniform_data = uniform_data;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_color_matrix (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *matrix,
|
||||
const graphene_vec4_t *offset)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (builder);
|
||||
const bool offset_equal = graphene_vec4_equal (offset, ¤t_program_state->color_matrix.offset);
|
||||
const bool matrix_equal = graphene_matrix_equal_fast (matrix,
|
||||
¤t_program_state->color_matrix.matrix);
|
||||
OpColorMatrix *op;
|
||||
|
||||
if (offset_equal && matrix_equal)
|
||||
return;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_COLOR_MATRIX);
|
||||
|
||||
if (!matrix_equal)
|
||||
{
|
||||
current_program_state->color_matrix.matrix = *matrix;
|
||||
op->matrix.value = matrix;
|
||||
op->matrix.send = TRUE;
|
||||
}
|
||||
else
|
||||
op->matrix.send = FALSE;
|
||||
|
||||
if (!offset_equal)
|
||||
{
|
||||
current_program_state->color_matrix.offset = *offset;
|
||||
op->offset.value = offset;
|
||||
op->offset.send = TRUE;
|
||||
}
|
||||
else
|
||||
op->offset.send = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_border (RenderOpBuilder *builder,
|
||||
const GskRoundedRect *outline)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (builder);
|
||||
OpBorder *op;
|
||||
|
||||
if (memcmp (¤t_program_state->border.outline,
|
||||
outline, sizeof (GskRoundedRect)) == 0)
|
||||
return;
|
||||
|
||||
current_program_state->border.outline = *outline;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_BORDER);
|
||||
op->outline = *outline;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_border_width (RenderOpBuilder *builder,
|
||||
const float *widths)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (builder);
|
||||
OpBorder *op;
|
||||
|
||||
g_assert (current_program_state);
|
||||
|
||||
if (memcmp (current_program_state->border.widths,
|
||||
widths, sizeof (float) * 4) == 0)
|
||||
return;
|
||||
|
||||
memcpy (¤t_program_state->border.widths,
|
||||
widths, sizeof (float) * 4);
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_BORDER_WIDTH);
|
||||
op->widths[0] = widths[0];
|
||||
op->widths[1] = widths[1];
|
||||
op->widths[2] = widths[2];
|
||||
op->widths[3] = widths[3];
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_border_color (RenderOpBuilder *builder,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (builder);
|
||||
OpBorder *op;
|
||||
|
||||
if (gdk_rgba_equal (color, ¤t_program_state->border.color))
|
||||
return;
|
||||
|
||||
op = op_buffer_add (&builder->render_ops, OP_CHANGE_BORDER_COLOR);
|
||||
op->color = color;
|
||||
|
||||
current_program_state->border.color = *color;
|
||||
}
|
||||
|
||||
GskQuadVertex *
|
||||
ops_draw (RenderOpBuilder *builder,
|
||||
const GskQuadVertex vertex_data[GL_N_VERTICES])
|
||||
{
|
||||
ProgramState *program_state = get_current_program_state (builder);
|
||||
OpDraw *op;
|
||||
|
||||
if (memcmp (&builder->current_projection, &program_state->projection, sizeof (graphene_matrix_t)) != 0)
|
||||
{
|
||||
OpMatrix *opm;
|
||||
|
||||
opm = ops_begin (builder, OP_CHANGE_PROJECTION);
|
||||
opm->matrix = builder->current_projection;
|
||||
program_state->projection = builder->current_projection;
|
||||
}
|
||||
|
||||
if (program_state->modelview == NULL ||
|
||||
!gsk_transform_equal (builder->current_modelview, program_state->modelview))
|
||||
{
|
||||
OpMatrix *opm;
|
||||
|
||||
opm = ops_begin (builder, OP_CHANGE_MODELVIEW);
|
||||
gsk_transform_to_matrix (builder->current_modelview, &opm->matrix);
|
||||
gsk_transform_unref (program_state->modelview);
|
||||
program_state->modelview = gsk_transform_ref (builder->current_modelview);
|
||||
}
|
||||
|
||||
if (!rect_equal (&builder->current_viewport, &program_state->viewport))
|
||||
{
|
||||
OpViewport *opv;
|
||||
|
||||
opv = ops_begin (builder, OP_CHANGE_VIEWPORT);
|
||||
opv->viewport = builder->current_viewport;
|
||||
program_state->viewport = builder->current_viewport;
|
||||
}
|
||||
|
||||
if (!rounded_rect_equal (builder->current_clip, &program_state->clip))
|
||||
{
|
||||
OpClip *opc;
|
||||
|
||||
opc = ops_begin (builder, OP_CHANGE_CLIP);
|
||||
opc->clip = *builder->current_clip;
|
||||
opc->send_corners = !rounded_rect_corners_equal (builder->current_clip, &program_state->clip);
|
||||
program_state->clip = *builder->current_clip;
|
||||
}
|
||||
|
||||
if (program_state->opacity != builder->current_opacity)
|
||||
{
|
||||
OpOpacity *opo;
|
||||
|
||||
opo = ops_begin (builder, OP_CHANGE_OPACITY);
|
||||
opo->opacity = builder->current_opacity;
|
||||
program_state->opacity = builder->current_opacity;
|
||||
}
|
||||
|
||||
/* TODO: Did the additions above break the following optimization? */
|
||||
if ((op = op_buffer_peek_tail_checked (&builder->render_ops, OP_DRAW)))
|
||||
{
|
||||
op->vao_size += GL_N_VERTICES;
|
||||
}
|
||||
else
|
||||
{
|
||||
op = op_buffer_add (&builder->render_ops, OP_DRAW);
|
||||
op->vao_offset = builder->vertices->len;
|
||||
op->vao_size = GL_N_VERTICES;
|
||||
}
|
||||
|
||||
if (vertex_data)
|
||||
{
|
||||
g_array_append_vals (builder->vertices, vertex_data, GL_N_VERTICES);
|
||||
return NULL; /* Better not use this on the caller side */
|
||||
}
|
||||
|
||||
g_array_set_size (builder->vertices, builder->vertices->len + GL_N_VERTICES);
|
||||
return &g_array_index (builder->vertices, GskQuadVertex, builder->vertices->len - GL_N_VERTICES);
|
||||
}
|
||||
|
||||
/* The offset is only valid for the current modelview.
|
||||
* Setting a new modelview will add the offset to that matrix
|
||||
* and reset the internal offset to 0. */
|
||||
void
|
||||
ops_offset (RenderOpBuilder *builder,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
builder->dx += x;
|
||||
builder->dy += y;
|
||||
}
|
||||
|
||||
gpointer
|
||||
ops_begin (RenderOpBuilder *builder,
|
||||
OpKind kind)
|
||||
{
|
||||
return op_buffer_add (&builder->render_ops, kind);
|
||||
}
|
||||
|
||||
void
|
||||
ops_reset (RenderOpBuilder *builder)
|
||||
{
|
||||
op_buffer_clear (&builder->render_ops);
|
||||
g_array_set_size (builder->vertices, 0);
|
||||
}
|
||||
|
||||
OpBuffer *
|
||||
ops_get_buffer (RenderOpBuilder *builder)
|
||||
{
|
||||
return &builder->render_ops;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_inset_shadow (RenderOpBuilder *self,
|
||||
const GskRoundedRect outline,
|
||||
float spread,
|
||||
const GdkRGBA *color,
|
||||
float dx,
|
||||
float dy)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (self);
|
||||
OpShadow *op;
|
||||
|
||||
g_assert (current_program_state);
|
||||
|
||||
op = ops_begin (self, OP_CHANGE_INSET_SHADOW);
|
||||
|
||||
if (!rounded_rect_equal (&outline, ¤t_program_state->inset_shadow.outline))
|
||||
{
|
||||
op->outline.value = outline;
|
||||
op->outline.send = TRUE;
|
||||
op->outline.send_corners = !rounded_rect_corners_equal (¤t_program_state->inset_shadow.outline,
|
||||
&outline);
|
||||
current_program_state->inset_shadow.outline = outline;
|
||||
}
|
||||
else
|
||||
op->outline.send = FALSE;
|
||||
|
||||
if (spread != current_program_state->inset_shadow.spread)
|
||||
{
|
||||
op->spread.value = spread;
|
||||
op->spread.send = TRUE;
|
||||
|
||||
current_program_state->inset_shadow.spread = spread;
|
||||
}
|
||||
else
|
||||
op->spread.send = FALSE;
|
||||
|
||||
if (!gdk_rgba_equal (color, ¤t_program_state->inset_shadow.color))
|
||||
{
|
||||
op->color.value = color;
|
||||
op->color.send = TRUE;
|
||||
|
||||
current_program_state->inset_shadow.color = *color;
|
||||
}
|
||||
else
|
||||
op->color.send = FALSE;
|
||||
|
||||
if (dx != current_program_state->inset_shadow.dx ||
|
||||
dy != current_program_state->inset_shadow.dy)
|
||||
{
|
||||
op->offset.value[0] = dx;
|
||||
op->offset.value[1] = dy;
|
||||
op->offset.send = TRUE;
|
||||
|
||||
current_program_state->inset_shadow.dx = dx;
|
||||
current_program_state->inset_shadow.dy = dy;
|
||||
}
|
||||
else
|
||||
op->offset.send = FALSE;
|
||||
|
||||
if (!op->outline.send &&
|
||||
!op->spread.send &&
|
||||
!op->offset.send &&
|
||||
!op->color.send)
|
||||
{
|
||||
op_buffer_pop_tail (&self->render_ops);
|
||||
}
|
||||
}
|
||||
void
|
||||
ops_set_unblurred_outset_shadow (RenderOpBuilder *self,
|
||||
const GskRoundedRect outline,
|
||||
float spread,
|
||||
const GdkRGBA *color,
|
||||
float dx,
|
||||
float dy)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (self);
|
||||
OpShadow *op;
|
||||
|
||||
g_assert (current_program_state);
|
||||
|
||||
op = ops_begin (self, OP_CHANGE_UNBLURRED_OUTSET_SHADOW);
|
||||
|
||||
if (!rounded_rect_equal (&outline, ¤t_program_state->unblurred_outset_shadow.outline))
|
||||
{
|
||||
op->outline.value = outline;
|
||||
op->outline.send = TRUE;
|
||||
op->outline.send_corners = !rounded_rect_corners_equal (¤t_program_state->unblurred_outset_shadow.outline,
|
||||
&outline);
|
||||
current_program_state->unblurred_outset_shadow.outline = outline;
|
||||
}
|
||||
else
|
||||
op->outline.send = FALSE;
|
||||
|
||||
if (spread != current_program_state->unblurred_outset_shadow.spread)
|
||||
{
|
||||
op->spread.value = spread;
|
||||
op->spread.send = TRUE;
|
||||
|
||||
current_program_state->unblurred_outset_shadow.spread = spread;
|
||||
}
|
||||
else
|
||||
op->spread.send = FALSE;
|
||||
|
||||
if (!gdk_rgba_equal (color, ¤t_program_state->unblurred_outset_shadow.color))
|
||||
{
|
||||
op->color.value = color;
|
||||
op->color.send = TRUE;
|
||||
|
||||
current_program_state->unblurred_outset_shadow.color = *color;
|
||||
}
|
||||
else
|
||||
op->color.send = FALSE;
|
||||
|
||||
if (dx != current_program_state->unblurred_outset_shadow.dx ||
|
||||
dy != current_program_state->unblurred_outset_shadow.dy)
|
||||
{
|
||||
op->offset.value[0] = dx;
|
||||
op->offset.value[1] = dy;
|
||||
op->offset.send = TRUE;
|
||||
|
||||
current_program_state->unblurred_outset_shadow.dx = dx;
|
||||
current_program_state->unblurred_outset_shadow.dy = dy;
|
||||
}
|
||||
else
|
||||
op->offset.send = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_linear_gradient (RenderOpBuilder *self,
|
||||
guint n_color_stops,
|
||||
const GskColorStop *color_stops,
|
||||
gboolean repeat,
|
||||
float start_x,
|
||||
float start_y,
|
||||
float end_x,
|
||||
float end_y)
|
||||
{
|
||||
ProgramState *current_program_state = get_current_program_state (self);
|
||||
OpLinearGradient *op;
|
||||
const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
|
||||
|
||||
g_assert (current_program_state);
|
||||
|
||||
op = ops_begin (self, OP_CHANGE_LINEAR_GRADIENT);
|
||||
|
||||
/* We always save the n_color_stops value in the op so the renderer can use it in
|
||||
* cases where we send the color stops, but not n_color_stops */
|
||||
op->n_color_stops.value = real_n_color_stops;
|
||||
if (current_program_state->linear_gradient.n_color_stops != real_n_color_stops)
|
||||
{
|
||||
op->n_color_stops.send = TRUE;
|
||||
current_program_state->linear_gradient.n_color_stops = real_n_color_stops;
|
||||
}
|
||||
else
|
||||
op->n_color_stops.send = FALSE;
|
||||
|
||||
op->color_stops.send = FALSE;
|
||||
if (!op->n_color_stops.send)
|
||||
{
|
||||
g_assert (current_program_state->linear_gradient.n_color_stops == real_n_color_stops);
|
||||
|
||||
for (guint i = 0; i < real_n_color_stops; i ++)
|
||||
{
|
||||
const GskColorStop *s1 = &color_stops[i];
|
||||
const GskColorStop *s2 = ¤t_program_state->linear_gradient.color_stops[i];
|
||||
|
||||
if (s1->offset != s2->offset ||
|
||||
!gdk_rgba_equal (&s1->color, &s2->color))
|
||||
{
|
||||
op->color_stops.send = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
op->color_stops.send = TRUE;
|
||||
|
||||
if (op->color_stops.send)
|
||||
{
|
||||
op->color_stops.value = color_stops;
|
||||
memcpy (¤t_program_state->linear_gradient.color_stops,
|
||||
color_stops,
|
||||
sizeof (GskColorStop) * real_n_color_stops);
|
||||
}
|
||||
|
||||
op->repeat = repeat;
|
||||
op->start_point[0] = start_x;
|
||||
op->start_point[1] = start_y;
|
||||
op->end_point[0] = end_x;
|
||||
op->end_point[1] = end_y;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_radial_gradient (RenderOpBuilder *self,
|
||||
guint n_color_stops,
|
||||
const GskColorStop *color_stops,
|
||||
gboolean repeat,
|
||||
float center_x,
|
||||
float center_y,
|
||||
float start,
|
||||
float end,
|
||||
float hradius,
|
||||
float vradius)
|
||||
{
|
||||
const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
|
||||
OpRadialGradient *op;
|
||||
|
||||
/* TODO: State tracking? */
|
||||
|
||||
op = ops_begin (self, OP_CHANGE_RADIAL_GRADIENT);
|
||||
op->n_color_stops.value = real_n_color_stops;
|
||||
op->n_color_stops.send = true;
|
||||
op->color_stops.value = color_stops;
|
||||
op->color_stops.send = true;
|
||||
op->center[0] = center_x;
|
||||
op->center[1] = center_y;
|
||||
op->radius[0] = hradius;
|
||||
op->radius[1] = vradius;
|
||||
op->start = start;
|
||||
op->end = end;
|
||||
op->repeat = repeat;
|
||||
}
|
||||
|
||||
void
|
||||
ops_set_conic_gradient (RenderOpBuilder *self,
|
||||
guint n_color_stops,
|
||||
const GskColorStop *color_stops,
|
||||
float center_x,
|
||||
float center_y,
|
||||
float angle)
|
||||
{
|
||||
const guint real_n_color_stops = MIN (GL_MAX_GRADIENT_STOPS, n_color_stops);
|
||||
OpConicGradient *op;
|
||||
|
||||
/* TODO: State tracking? */
|
||||
|
||||
op = ops_begin (self, OP_CHANGE_CONIC_GRADIENT);
|
||||
op->n_color_stops.value = real_n_color_stops;
|
||||
op->n_color_stops.send = true;
|
||||
op->color_stops.value = color_stops;
|
||||
op->color_stops.send = true;
|
||||
op->center[0] = center_x;
|
||||
op->center[1] = center_y;
|
||||
op->angle = angle;
|
||||
}
|
||||
|
||||
@@ -1,353 +0,0 @@
|
||||
#ifndef __GSK_GL_RENDER_OPS_H__
|
||||
#define __GSK_GL_RENDER_OPS_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <graphene.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskroundedrectprivate.h"
|
||||
#include "gskglrenderer.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
|
||||
#include "opbuffer.h"
|
||||
|
||||
#define GL_N_VERTICES 6
|
||||
#define GL_N_PROGRAMS 15
|
||||
#define GL_MAX_GRADIENT_STOPS 6
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float scale_x;
|
||||
float scale_y;
|
||||
|
||||
float dx_before;
|
||||
float dy_before;
|
||||
} OpsMatrixMetadata;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskTransform *transform;
|
||||
OpsMatrixMetadata metadata;
|
||||
} MatrixStackEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskTransform *modelview;
|
||||
GskRoundedRect clip;
|
||||
graphene_matrix_t projection;
|
||||
int source_texture;
|
||||
graphene_rect_t viewport;
|
||||
float opacity;
|
||||
/* Per-program state */
|
||||
union {
|
||||
GdkRGBA color;
|
||||
struct {
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
} color_matrix;
|
||||
struct {
|
||||
float widths[4];
|
||||
GdkRGBA color;
|
||||
GskRoundedRect outline;
|
||||
} border;
|
||||
struct {
|
||||
GskRoundedRect outline;
|
||||
float dx;
|
||||
float dy;
|
||||
float spread;
|
||||
GdkRGBA color;
|
||||
} inset_shadow;
|
||||
struct {
|
||||
GskRoundedRect outline;
|
||||
float dx;
|
||||
float dy;
|
||||
float spread;
|
||||
GdkRGBA color;
|
||||
} unblurred_outset_shadow;
|
||||
struct {
|
||||
int n_color_stops;
|
||||
GskColorStop color_stops[GL_MAX_GRADIENT_STOPS];
|
||||
float start_point[2];
|
||||
float end_point[2];
|
||||
} linear_gradient;
|
||||
struct {
|
||||
int n_color_stops;
|
||||
GskColorStop color_stops[GL_MAX_GRADIENT_STOPS];
|
||||
float center[2];
|
||||
float start;
|
||||
float end;
|
||||
float radius[2]; /* h/v */
|
||||
} radial_gradient;
|
||||
struct {
|
||||
float width;
|
||||
float height;
|
||||
int uniform_data_len;
|
||||
guchar uniform_data[32];
|
||||
} gl_shader;
|
||||
};
|
||||
} ProgramState;
|
||||
|
||||
struct _Program
|
||||
{
|
||||
const char *name;
|
||||
|
||||
int index; /* Into the renderer's program array -1 for custom */
|
||||
|
||||
int id;
|
||||
/* Common locations (gl_common)*/
|
||||
int source_location;
|
||||
int position_location;
|
||||
int uv_location;
|
||||
int alpha_location;
|
||||
int viewport_location;
|
||||
int projection_location;
|
||||
int modelview_location;
|
||||
int clip_rect_location;
|
||||
union {
|
||||
struct {
|
||||
int color_location;
|
||||
} color;
|
||||
struct {
|
||||
int color_location;
|
||||
} coloring;
|
||||
struct {
|
||||
int color_matrix_location;
|
||||
int color_offset_location;
|
||||
} color_matrix;
|
||||
struct {
|
||||
int num_color_stops_location;
|
||||
int color_stops_location;
|
||||
int points_location;
|
||||
int repeat_location;
|
||||
} linear_gradient;
|
||||
struct {
|
||||
int num_color_stops_location;
|
||||
int color_stops_location;
|
||||
int geometry_location;
|
||||
int range_location;
|
||||
int repeat_location;
|
||||
} radial_gradient;
|
||||
struct {
|
||||
int num_color_stops_location;
|
||||
int color_stops_location;
|
||||
int geometry_location;
|
||||
} conic_gradient;
|
||||
struct {
|
||||
int blur_radius_location;
|
||||
int blur_size_location;
|
||||
int blur_dir_location;
|
||||
} blur;
|
||||
struct {
|
||||
int color_location;
|
||||
int spread_location;
|
||||
int offset_location;
|
||||
int outline_rect_location;
|
||||
} inset_shadow;
|
||||
struct {
|
||||
int color_location;
|
||||
int outline_rect_location;
|
||||
} outset_shadow;
|
||||
struct {
|
||||
int outline_rect_location;
|
||||
int color_location;
|
||||
int spread_location;
|
||||
int offset_location;
|
||||
} unblurred_outset_shadow;
|
||||
struct {
|
||||
int color_location;
|
||||
int widths_location;
|
||||
int outline_rect_location;
|
||||
} border;
|
||||
struct {
|
||||
int source2_location;
|
||||
int progress_location;
|
||||
} cross_fade;
|
||||
struct {
|
||||
int source2_location;
|
||||
int mode_location;
|
||||
} blend;
|
||||
struct {
|
||||
int child_bounds_location;
|
||||
int texture_rect_location;
|
||||
} repeat;
|
||||
struct {
|
||||
int size_location;
|
||||
int args_locations[8];
|
||||
int texture_locations[4];
|
||||
GError *compile_error;
|
||||
} glshader;
|
||||
};
|
||||
ProgramState state;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int ref_count;
|
||||
union {
|
||||
Program programs[GL_N_PROGRAMS];
|
||||
struct {
|
||||
Program blend_program;
|
||||
Program blit_program;
|
||||
Program blur_program;
|
||||
Program border_program;
|
||||
Program color_matrix_program;
|
||||
Program color_program;
|
||||
Program coloring_program;
|
||||
Program cross_fade_program;
|
||||
Program inset_shadow_program;
|
||||
Program linear_gradient_program;
|
||||
Program radial_gradient_program;
|
||||
Program conic_gradient_program;
|
||||
Program outset_shadow_program;
|
||||
Program repeat_program;
|
||||
Program unblurred_outset_shadow_program;
|
||||
};
|
||||
};
|
||||
GHashTable *custom_programs; /* GskGLShader -> Program* */
|
||||
} GskGLRendererPrograms;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskGLRendererPrograms *programs;
|
||||
Program *current_program;
|
||||
int current_render_target;
|
||||
int current_texture;
|
||||
|
||||
graphene_matrix_t current_projection;
|
||||
graphene_rect_t current_viewport;
|
||||
float current_opacity;
|
||||
float dx, dy;
|
||||
float scale_x, scale_y;
|
||||
|
||||
OpBuffer render_ops;
|
||||
GArray *vertices;
|
||||
|
||||
GskGLRenderer *renderer;
|
||||
|
||||
/* Stack of modelview matrices */
|
||||
GArray *mv_stack;
|
||||
GskTransform *current_modelview;
|
||||
|
||||
/* Same thing */
|
||||
GArray *clip_stack;
|
||||
/* Pointer into clip_stack */
|
||||
const GskRoundedRect *current_clip;
|
||||
bool clip_is_rectilinear;
|
||||
} RenderOpBuilder;
|
||||
|
||||
|
||||
void ops_dump_framebuffer (RenderOpBuilder *builder,
|
||||
const char *filename,
|
||||
int width,
|
||||
int height);
|
||||
void ops_init (RenderOpBuilder *builder);
|
||||
void ops_free (RenderOpBuilder *builder);
|
||||
void ops_reset (RenderOpBuilder *builder);
|
||||
void ops_push_debug_group (RenderOpBuilder *builder,
|
||||
const char *text);
|
||||
void ops_pop_debug_group (RenderOpBuilder *builder);
|
||||
|
||||
void ops_finish (RenderOpBuilder *builder);
|
||||
void ops_push_modelview (RenderOpBuilder *builder,
|
||||
GskTransform *transform);
|
||||
void ops_set_modelview (RenderOpBuilder *builder,
|
||||
GskTransform *transform);
|
||||
void ops_pop_modelview (RenderOpBuilder *builder);
|
||||
void ops_set_program (RenderOpBuilder *builder,
|
||||
Program *program);
|
||||
|
||||
void ops_push_clip (RenderOpBuilder *builder,
|
||||
const GskRoundedRect *clip);
|
||||
void ops_pop_clip (RenderOpBuilder *builder);
|
||||
gboolean ops_has_clip (RenderOpBuilder *builder);
|
||||
|
||||
void ops_transform_bounds_modelview (const RenderOpBuilder *builder,
|
||||
const graphene_rect_t *src,
|
||||
graphene_rect_t *dst);
|
||||
|
||||
graphene_matrix_t ops_set_projection (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *projection);
|
||||
|
||||
graphene_rect_t ops_set_viewport (RenderOpBuilder *builder,
|
||||
const graphene_rect_t *viewport);
|
||||
|
||||
void ops_set_texture (RenderOpBuilder *builder,
|
||||
int texture_id);
|
||||
void ops_set_extra_texture (RenderOpBuilder *builder,
|
||||
int texture_id,
|
||||
int idx);
|
||||
|
||||
int ops_set_render_target (RenderOpBuilder *builder,
|
||||
int render_target_id);
|
||||
|
||||
float ops_set_opacity (RenderOpBuilder *builder,
|
||||
float opacity);
|
||||
void ops_set_color (RenderOpBuilder *builder,
|
||||
const GdkRGBA *color);
|
||||
|
||||
void ops_set_color_matrix (RenderOpBuilder *builder,
|
||||
const graphene_matrix_t *matrix,
|
||||
const graphene_vec4_t *offset);
|
||||
|
||||
void ops_set_border (RenderOpBuilder *builder,
|
||||
const GskRoundedRect *outline);
|
||||
void ops_set_border_width (RenderOpBuilder *builder,
|
||||
const float *widths);
|
||||
|
||||
void ops_set_border_color (RenderOpBuilder *builder,
|
||||
const GdkRGBA *color);
|
||||
void ops_set_inset_shadow (RenderOpBuilder *self,
|
||||
const GskRoundedRect outline,
|
||||
float spread,
|
||||
const GdkRGBA *color,
|
||||
float dx,
|
||||
float dy);
|
||||
void ops_set_gl_shader_args (RenderOpBuilder *builder,
|
||||
GskGLShader *shader,
|
||||
float width,
|
||||
float height,
|
||||
const guchar *uniform_data);
|
||||
void ops_set_unblurred_outset_shadow (RenderOpBuilder *self,
|
||||
const GskRoundedRect outline,
|
||||
float spread,
|
||||
const GdkRGBA *color,
|
||||
float dx,
|
||||
float dy);
|
||||
|
||||
void ops_set_linear_gradient (RenderOpBuilder *self,
|
||||
guint n_color_stops,
|
||||
const GskColorStop *color_stops,
|
||||
gboolean repeat,
|
||||
float start_x,
|
||||
float start_y,
|
||||
float end_x,
|
||||
float end_y);
|
||||
void ops_set_radial_gradient (RenderOpBuilder *self,
|
||||
guint n_color_stops,
|
||||
const GskColorStop *color_stops,
|
||||
gboolean repeat,
|
||||
float center_x,
|
||||
float center_y,
|
||||
float start,
|
||||
float end,
|
||||
float hradius,
|
||||
float vradius);
|
||||
void ops_set_conic_gradient (RenderOpBuilder *self,
|
||||
guint n_color_stops,
|
||||
const GskColorStop *color_stops,
|
||||
float center_x,
|
||||
float center_y,
|
||||
float angle);
|
||||
|
||||
GskQuadVertex * ops_draw (RenderOpBuilder *builder,
|
||||
const GskQuadVertex vertex_data[GL_N_VERTICES]);
|
||||
|
||||
void ops_offset (RenderOpBuilder *builder,
|
||||
float x,
|
||||
float y);
|
||||
|
||||
gpointer ops_begin (RenderOpBuilder *builder,
|
||||
OpKind kind);
|
||||
OpBuffer *ops_get_buffer (RenderOpBuilder *builder);
|
||||
|
||||
#endif
|
||||
@@ -1,271 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglshaderbuilderprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
void
|
||||
gsk_gl_shader_builder_init (GskGLShaderBuilder *self,
|
||||
const char *common_preamble_resource_path,
|
||||
const char *vs_preamble_resource_path,
|
||||
const char *fs_preamble_resource_path)
|
||||
{
|
||||
memset (self, 0, sizeof (*self));
|
||||
|
||||
self->preamble = g_resources_lookup_data (common_preamble_resource_path, 0, NULL);
|
||||
self->vs_preamble = g_resources_lookup_data (vs_preamble_resource_path, 0, NULL);
|
||||
self->fs_preamble = g_resources_lookup_data (fs_preamble_resource_path, 0, NULL);
|
||||
|
||||
g_assert (self->preamble);
|
||||
g_assert (self->vs_preamble);
|
||||
g_assert (self->fs_preamble);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_shader_builder_finish (GskGLShaderBuilder *self)
|
||||
{
|
||||
g_bytes_unref (self->preamble);
|
||||
g_bytes_unref (self->vs_preamble);
|
||||
g_bytes_unref (self->fs_preamble);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder *self,
|
||||
int version)
|
||||
{
|
||||
self->version = version;
|
||||
}
|
||||
|
||||
static void
|
||||
prepend_line_numbers (char *code,
|
||||
GString *s)
|
||||
{
|
||||
char *p;
|
||||
int line;
|
||||
|
||||
p = code;
|
||||
line = 1;
|
||||
while (*p)
|
||||
{
|
||||
char *end = strchr (p, '\n');
|
||||
if (end)
|
||||
end = end + 1; /* Include newline */
|
||||
else
|
||||
end = p + strlen (p);
|
||||
|
||||
g_string_append_printf (s, "%3d| ", line++);
|
||||
g_string_append_len (s, p, end - p);
|
||||
|
||||
p = end;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_shader_error (int shader_id,
|
||||
int shader_type,
|
||||
const char *resource_path,
|
||||
GError **error)
|
||||
{
|
||||
int status;
|
||||
int log_len;
|
||||
char *buffer;
|
||||
int code_len;
|
||||
char *code;
|
||||
GString *s;
|
||||
|
||||
glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
|
||||
|
||||
if (G_LIKELY (status == GL_TRUE))
|
||||
return TRUE;
|
||||
|
||||
glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
|
||||
buffer = g_malloc0 (log_len + 1);
|
||||
glGetShaderInfoLog (shader_id, log_len, NULL, buffer);
|
||||
|
||||
glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
|
||||
code = g_malloc0 (code_len + 1);
|
||||
glGetShaderSource (shader_id, code_len, NULL, code);
|
||||
|
||||
s = g_string_new ("");
|
||||
prepend_line_numbers (code, s);
|
||||
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_COMPILATION_FAILED,
|
||||
"Compilation failure in %s shader %s.\nSource Code:\n%s\n\nError Message:\n%s\n\n",
|
||||
(shader_type == GL_FRAGMENT_SHADER ? "fragment" : "vertex"),
|
||||
resource_path,
|
||||
s->str,
|
||||
buffer);
|
||||
|
||||
g_string_free (s, TRUE);
|
||||
g_free (buffer);
|
||||
g_free (code);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
print_shader_info (const char *prefix,
|
||||
int shader_id,
|
||||
const char *resource_path)
|
||||
{
|
||||
if (GSK_DEBUG_CHECK(SHADERS))
|
||||
{
|
||||
int code_len;
|
||||
char *code;
|
||||
GString *s;
|
||||
|
||||
glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
|
||||
code = g_malloc0 (code_len + 1);
|
||||
glGetShaderSource (shader_id, code_len, NULL, code);
|
||||
|
||||
s = g_string_new ("");
|
||||
prepend_line_numbers (code, s);
|
||||
|
||||
g_message ("%s %d, %s:\n%s", prefix, shader_id, resource_path, s->str);
|
||||
g_string_free (s, TRUE);
|
||||
g_free (code);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
const char *resource_path,
|
||||
const char *extra_fragment_snippet,
|
||||
gsize extra_fragment_length,
|
||||
GError **error)
|
||||
{
|
||||
|
||||
GBytes *source_bytes = g_resources_lookup_data (resource_path, 0, NULL);
|
||||
char version_buffer[64];
|
||||
const char *source;
|
||||
const char *vertex_shader_start;
|
||||
const char *fragment_shader_start;
|
||||
int vertex_id;
|
||||
int fragment_id;
|
||||
int program_id = -1;
|
||||
int status;
|
||||
|
||||
g_assert (source_bytes);
|
||||
|
||||
source = g_bytes_get_data (source_bytes, NULL);
|
||||
vertex_shader_start = strstr (source, "VERTEX_SHADER");
|
||||
fragment_shader_start = strstr (source, "FRAGMENT_SHADER");
|
||||
|
||||
g_assert (vertex_shader_start);
|
||||
g_assert (fragment_shader_start);
|
||||
|
||||
/* They both start at the next newline */
|
||||
vertex_shader_start = strstr (vertex_shader_start, "\n");
|
||||
fragment_shader_start = strstr (fragment_shader_start, "\n");
|
||||
|
||||
g_snprintf (version_buffer, sizeof (version_buffer),
|
||||
"#version %d\n", self->version);
|
||||
|
||||
vertex_id = glCreateShader (GL_VERTEX_SHADER);
|
||||
glShaderSource (vertex_id, 8,
|
||||
(const char *[]) {
|
||||
version_buffer,
|
||||
self->debugging ? "#define GSK_DEBUG 1\n" : "",
|
||||
self->legacy ? "#define GSK_LEGACY 1\n" : "",
|
||||
self->gl3 ? "#define GSK_GL3 1\n" : "",
|
||||
self->gles ? "#define GSK_GLES 1\n" : "",
|
||||
g_bytes_get_data (self->preamble, NULL),
|
||||
g_bytes_get_data (self->vs_preamble, NULL),
|
||||
vertex_shader_start
|
||||
},
|
||||
(int[]) {
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
fragment_shader_start - vertex_shader_start
|
||||
});
|
||||
glCompileShader (vertex_id);
|
||||
|
||||
if (!check_shader_error (vertex_id, GL_VERTEX_SHADER, resource_path, error))
|
||||
{
|
||||
glDeleteShader (vertex_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_shader_info ("Vertex shader", vertex_id, resource_path);
|
||||
|
||||
fragment_id = glCreateShader (GL_FRAGMENT_SHADER);
|
||||
glShaderSource (fragment_id, 9,
|
||||
(const char *[]) {
|
||||
version_buffer,
|
||||
self->debugging ? "#define GSK_DEBUG 1\n" : "",
|
||||
self->legacy ? "#define GSK_LEGACY 1\n" : "",
|
||||
self->gl3 ? "#define GSK_GL3 1\n" : "",
|
||||
self->gles ? "#define GSK_GLES 1\n" : "",
|
||||
g_bytes_get_data (self->preamble, NULL),
|
||||
g_bytes_get_data (self->fs_preamble, NULL),
|
||||
fragment_shader_start,
|
||||
extra_fragment_snippet ? extra_fragment_snippet : ""
|
||||
},
|
||||
(int[]) {
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
extra_fragment_length,
|
||||
});
|
||||
glCompileShader (fragment_id);
|
||||
|
||||
if (!check_shader_error (fragment_id, GL_FRAGMENT_SHADER, resource_path, error))
|
||||
{
|
||||
glDeleteShader (fragment_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_shader_info ("Fragment shader", fragment_id, resource_path);
|
||||
|
||||
program_id = glCreateProgram ();
|
||||
glAttachShader (program_id, vertex_id);
|
||||
glAttachShader (program_id, fragment_id);
|
||||
glBindAttribLocation (program_id, 0, "aPosition");
|
||||
glBindAttribLocation (program_id, 1, "aUv");
|
||||
glLinkProgram (program_id);
|
||||
glDetachShader (program_id, vertex_id);
|
||||
glDetachShader (program_id, fragment_id);
|
||||
|
||||
glGetProgramiv (program_id, GL_LINK_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
int log_len = 0;
|
||||
|
||||
glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
|
||||
|
||||
buffer = g_malloc0 (log_len + 1);
|
||||
glGetProgramInfoLog (program_id, log_len, NULL, buffer);
|
||||
|
||||
g_warning ("Linking failure in shader:\n%s", buffer);
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_LINK_FAILED,
|
||||
"Linking failure in shader: %s", buffer);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteProgram (program_id);
|
||||
program_id = -1;
|
||||
}
|
||||
|
||||
glDeleteShader (vertex_id);
|
||||
glDeleteShader (fragment_id);
|
||||
|
||||
out:
|
||||
g_bytes_unref (source_bytes);
|
||||
|
||||
return program_id;
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#ifndef __GSK_SHADER_BUILDER_PRIVATE_H__
|
||||
#define __GSK_SHADER_BUILDER_PRIVATE_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <graphene.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GBytes *preamble;
|
||||
GBytes *vs_preamble;
|
||||
GBytes *fs_preamble;
|
||||
|
||||
int version;
|
||||
|
||||
guint debugging: 1;
|
||||
guint gles: 1;
|
||||
guint gl3: 1;
|
||||
guint legacy: 1;
|
||||
|
||||
} GskGLShaderBuilder;
|
||||
|
||||
|
||||
void gsk_gl_shader_builder_init (GskGLShaderBuilder *self,
|
||||
const char *common_preamble_resource_path,
|
||||
const char *vs_preamble_resource_path,
|
||||
const char *fs_preamble_resource_path);
|
||||
void gsk_gl_shader_builder_finish (GskGLShaderBuilder *self);
|
||||
|
||||
void gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder *self,
|
||||
int version);
|
||||
|
||||
int gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
const char *resource_path,
|
||||
const char *extra_fragment_snippet,
|
||||
gsize extra_fragment_length,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_SHADER_BUILDER_PRIVATE_H__ */
|
||||
@@ -1,141 +0,0 @@
|
||||
|
||||
#include "gskglshadowcacheprivate.h"
|
||||
|
||||
#define MAX_UNUSED_FRAMES (16 * 5)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskRoundedRect outline;
|
||||
float blur_radius;
|
||||
} CacheKey;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskRoundedRect outline;
|
||||
float blur_radius;
|
||||
|
||||
int texture_id;
|
||||
int unused_frames;
|
||||
} CacheItem;
|
||||
|
||||
static gboolean
|
||||
key_equal (const void *x,
|
||||
const void *y)
|
||||
{
|
||||
const CacheKey *a = x;
|
||||
const CacheKey *b = y;
|
||||
|
||||
return a->blur_radius == b->blur_radius &&
|
||||
graphene_size_equal (&a->outline.corner[0], &b->outline.corner[0]) &&
|
||||
graphene_size_equal (&a->outline.corner[1], &b->outline.corner[1]) &&
|
||||
graphene_size_equal (&a->outline.corner[2], &b->outline.corner[2]) &&
|
||||
graphene_size_equal (&a->outline.corner[3], &b->outline.corner[3]) &&
|
||||
graphene_rect_equal (&a->outline.bounds, &b->outline.bounds);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_shadow_cache_init (GskGLShadowCache *self)
|
||||
{
|
||||
self->textures = g_array_new (FALSE, TRUE, sizeof (CacheItem));
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_shadow_cache_free (GskGLShadowCache *self,
|
||||
GskGLDriver *gl_driver)
|
||||
{
|
||||
guint i, p;
|
||||
|
||||
for (i = 0, p = self->textures->len; i < p; i ++)
|
||||
{
|
||||
const CacheItem *item = &g_array_index (self->textures, CacheItem, i);
|
||||
|
||||
gsk_gl_driver_destroy_texture (gl_driver, item->texture_id);
|
||||
}
|
||||
|
||||
g_array_free (self->textures, TRUE);
|
||||
self->textures = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_shadow_cache_begin_frame (GskGLShadowCache *self,
|
||||
GskGLDriver *gl_driver)
|
||||
{
|
||||
guint i, p;
|
||||
|
||||
for (i = 0, p = self->textures->len; i < p; i ++)
|
||||
{
|
||||
CacheItem *item = &g_array_index (self->textures, CacheItem, i);
|
||||
|
||||
if (item->unused_frames > MAX_UNUSED_FRAMES)
|
||||
{
|
||||
gsk_gl_driver_destroy_texture (gl_driver, item->texture_id);
|
||||
g_array_remove_index_fast (self->textures, i);
|
||||
p --;
|
||||
i --;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->unused_frames ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX
|
||||
* The offset origin should always be at 0/0, or the blur radius should just go
|
||||
* away since it defines the origin position anyway?
|
||||
*/
|
||||
int
|
||||
gsk_gl_shadow_cache_get_texture_id (GskGLShadowCache *self,
|
||||
GskGLDriver *gl_driver,
|
||||
const GskRoundedRect *shadow_rect,
|
||||
float blur_radius)
|
||||
{
|
||||
CacheItem *item= NULL;
|
||||
guint i;
|
||||
|
||||
g_assert (self != NULL);
|
||||
g_assert (gl_driver != NULL);
|
||||
g_assert (shadow_rect != NULL);
|
||||
|
||||
for (i = 0; i < self->textures->len; i ++)
|
||||
{
|
||||
CacheItem *k = &g_array_index (self->textures, CacheItem, i);
|
||||
|
||||
if (key_equal (&(CacheKey){*shadow_rect, blur_radius},
|
||||
&(CacheKey){k->outline, k->blur_radius}))
|
||||
{
|
||||
item = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (item == NULL)
|
||||
return 0;
|
||||
|
||||
item->unused_frames = 0;
|
||||
|
||||
g_assert (item->texture_id != 0);
|
||||
|
||||
return item->texture_id;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_shadow_cache_commit (GskGLShadowCache *self,
|
||||
const GskRoundedRect *shadow_rect,
|
||||
float blur_radius,
|
||||
int texture_id)
|
||||
{
|
||||
CacheItem *item;
|
||||
|
||||
g_assert (self != NULL);
|
||||
g_assert (shadow_rect != NULL);
|
||||
g_assert (texture_id > 0);
|
||||
|
||||
g_array_set_size (self->textures, self->textures->len + 1);
|
||||
item = &g_array_index (self->textures, CacheItem, self->textures->len - 1);
|
||||
|
||||
item->outline = *shadow_rect;
|
||||
item->blur_radius = blur_radius;
|
||||
item->unused_frames = 0;
|
||||
item->texture_id = texture_id;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
|
||||
#ifndef __GSK_GL_SHADOW_CACHE_H__
|
||||
#define __GSK_GL_SHADOW_CACHE_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskroundedrect.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GArray *textures;
|
||||
} GskGLShadowCache;
|
||||
|
||||
|
||||
void gsk_gl_shadow_cache_init (GskGLShadowCache *self);
|
||||
void gsk_gl_shadow_cache_free (GskGLShadowCache *self,
|
||||
GskGLDriver *gl_driver);
|
||||
void gsk_gl_shadow_cache_begin_frame (GskGLShadowCache *self,
|
||||
GskGLDriver *gl_driver);
|
||||
int gsk_gl_shadow_cache_get_texture_id (GskGLShadowCache *self,
|
||||
GskGLDriver *gl_driver,
|
||||
const GskRoundedRect *shadow_rect,
|
||||
float blur_radius);
|
||||
void gsk_gl_shadow_cache_commit (GskGLShadowCache *self,
|
||||
const GskRoundedRect *shadow_rect,
|
||||
float blur_radius,
|
||||
int texture_id);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,309 +0,0 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "gskgltextureatlasprivate.h"
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gdkglcontextprivate.h"
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#define ATLAS_SIZE (512)
|
||||
#define MAX_OLD_RATIO 0.5
|
||||
|
||||
static void
|
||||
free_atlas (gpointer v)
|
||||
{
|
||||
GskGLTextureAtlas *atlas = v;
|
||||
|
||||
gsk_gl_texture_atlas_free (atlas);
|
||||
|
||||
g_free (atlas);
|
||||
}
|
||||
|
||||
GskGLTextureAtlases *
|
||||
gsk_gl_texture_atlases_new (void)
|
||||
{
|
||||
GskGLTextureAtlases *self;
|
||||
|
||||
self = g_new (GskGLTextureAtlases, 1);
|
||||
self->atlases = g_ptr_array_new_with_free_func (free_atlas);
|
||||
|
||||
self->ref_count = 1;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
GskGLTextureAtlases *
|
||||
gsk_gl_texture_atlases_ref (GskGLTextureAtlases *self)
|
||||
{
|
||||
self->ref_count++;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_texture_atlases_unref (GskGLTextureAtlases *self)
|
||||
{
|
||||
g_assert (self->ref_count > 0);
|
||||
|
||||
if (self->ref_count == 1)
|
||||
{
|
||||
g_ptr_array_unref (self->atlases);
|
||||
g_free (self);
|
||||
return;
|
||||
}
|
||||
|
||||
self->ref_count--;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
write_atlas_to_png (GskGLTextureAtlas *atlas,
|
||||
const char *filename)
|
||||
{
|
||||
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, atlas->width);
|
||||
guchar *data = g_malloc (atlas->height * stride);
|
||||
cairo_surface_t *s;
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
|
||||
glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
|
||||
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, atlas->width, atlas->height, stride);
|
||||
cairo_surface_write_to_png (s, filename);
|
||||
|
||||
cairo_surface_destroy (s);
|
||||
g_free (data);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
gsk_gl_texture_atlases_begin_frame (GskGLTextureAtlases *self,
|
||||
GPtrArray *removed)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = self->atlases->len - 1; i >= 0; i--)
|
||||
{
|
||||
GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i);
|
||||
|
||||
if (gsk_gl_texture_atlas_get_unused_ratio (atlas) > MAX_OLD_RATIO)
|
||||
{
|
||||
GSK_NOTE(GLYPH_CACHE,
|
||||
g_message ("Dropping atlas %d (%g.2%% old)", i,
|
||||
100.0 * gsk_gl_texture_atlas_get_unused_ratio (atlas)));
|
||||
|
||||
if (atlas->texture_id != 0)
|
||||
{
|
||||
glDeleteTextures (1, &atlas->texture_id);
|
||||
atlas->texture_id = 0;
|
||||
}
|
||||
|
||||
g_ptr_array_add (removed, atlas);
|
||||
g_ptr_array_remove_index (self->atlases, i);
|
||||
}
|
||||
}
|
||||
|
||||
GSK_NOTE(GLYPH_CACHE, {
|
||||
static guint timestamp;
|
||||
if (timestamp++ % 60 == 0)
|
||||
g_message ("%d atlases", self->atlases->len);
|
||||
});
|
||||
|
||||
|
||||
#if 0
|
||||
{
|
||||
static guint timestamp;
|
||||
|
||||
timestamp++;
|
||||
if (timestamp % 10 == 0)
|
||||
for (i = 0; i < self->atlases->len; i++)
|
||||
{
|
||||
GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i);
|
||||
|
||||
if (atlas->texture_id)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
filename = g_strdup_printf ("textureatlas%d-%u.png", i, timestamp);
|
||||
write_atlas_to_png (atlas, filename);
|
||||
g_free (filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_gl_texture_atlases_pack (GskGLTextureAtlases *self,
|
||||
int width,
|
||||
int height,
|
||||
GskGLTextureAtlas **atlas_out,
|
||||
int *out_x,
|
||||
int *out_y)
|
||||
{
|
||||
GskGLTextureAtlas *atlas;
|
||||
int x, y;
|
||||
int i;
|
||||
|
||||
g_assert (width < ATLAS_SIZE);
|
||||
g_assert (height < ATLAS_SIZE);
|
||||
|
||||
atlas = NULL;
|
||||
|
||||
for (i = 0; i < self->atlases->len; i++)
|
||||
{
|
||||
atlas = g_ptr_array_index (self->atlases, i);
|
||||
|
||||
if (gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
|
||||
break;
|
||||
|
||||
atlas = NULL;
|
||||
}
|
||||
|
||||
if (atlas == NULL)
|
||||
{
|
||||
/* No atlas has enough space, so create a new one... */
|
||||
atlas = g_malloc (sizeof (GskGLTextureAtlas));
|
||||
gsk_gl_texture_atlas_init (atlas, ATLAS_SIZE, ATLAS_SIZE);
|
||||
gsk_gl_texture_atlas_realize (atlas);
|
||||
g_ptr_array_add (self->atlases, atlas);
|
||||
|
||||
/* Pack it onto that one, which surely has enough space... */
|
||||
if (!gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y))
|
||||
g_assert_not_reached ();
|
||||
|
||||
GSK_NOTE(GLYPH_CACHE, g_message ("adding new atlas"));
|
||||
}
|
||||
|
||||
*atlas_out = atlas;
|
||||
*out_x = x;
|
||||
*out_y = y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_texture_atlas_init (GskGLTextureAtlas *self,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
memset (self, 0, sizeof (*self));
|
||||
|
||||
self->texture_id = 0;
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
/* TODO: We might want to change the strategy about the amount of
|
||||
* nodes here? stb_rect_pack.h says with is optimal. */
|
||||
self->nodes = g_malloc0 (sizeof (struct stbrp_node) * width);
|
||||
stbrp_init_target (&self->context,
|
||||
width, height,
|
||||
self->nodes,
|
||||
width);
|
||||
|
||||
gsk_gl_texture_atlas_realize (self);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_texture_atlas_free (GskGLTextureAtlas *self)
|
||||
{
|
||||
if (self->texture_id != 0)
|
||||
{
|
||||
glDeleteTextures (1, &self->texture_id);
|
||||
self->texture_id = 0;
|
||||
}
|
||||
|
||||
g_clear_pointer (&self->nodes, g_free);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_texture_atlas_mark_unused (GskGLTextureAtlas *self,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
self->unused_pixels += (width * height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gsk_gl_texture_atlas_mark_used (GskGLTextureAtlas *self,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
self->unused_pixels -= (width * height);
|
||||
|
||||
g_assert (self->unused_pixels >= 0);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_gl_texture_atlas_pack (GskGLTextureAtlas *self,
|
||||
int width,
|
||||
int height,
|
||||
int *out_x,
|
||||
int *out_y)
|
||||
{
|
||||
stbrp_rect rect;
|
||||
|
||||
g_assert (out_x);
|
||||
g_assert (out_y);
|
||||
|
||||
rect.w = width;
|
||||
rect.h = height;
|
||||
|
||||
stbrp_pack_rects (&self->context, &rect, 1);
|
||||
|
||||
if (rect.was_packed)
|
||||
{
|
||||
*out_x = rect.x;
|
||||
*out_y = rect.y;
|
||||
}
|
||||
|
||||
return rect.was_packed;
|
||||
}
|
||||
|
||||
double
|
||||
gsk_gl_texture_atlas_get_unused_ratio (const GskGLTextureAtlas *self)
|
||||
{
|
||||
if (self->unused_pixels > 0)
|
||||
return (double)(self->unused_pixels) / (double)(self->width * self->height);
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* Not using gdk_gl_driver_create_texture here, since we want
|
||||
* this texture to survive the driver and stay around until
|
||||
* the display gets closed.
|
||||
*/
|
||||
static guint
|
||||
create_shared_texture (int width,
|
||||
int height)
|
||||
{
|
||||
guint texture_id;
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
glBindTexture (GL_TEXTURE_2D, texture_id);
|
||||
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, 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);
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_texture_atlas_realize (GskGLTextureAtlas *atlas)
|
||||
{
|
||||
if (atlas->texture_id)
|
||||
return;
|
||||
|
||||
atlas->texture_id = create_shared_texture (atlas->width, atlas->height);
|
||||
gdk_gl_context_label_object_printf (gdk_gl_context_get_current (),
|
||||
GL_TEXTURE, atlas->texture_id,
|
||||
"Texture atlas %d", atlas->texture_id);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
|
||||
#ifndef __GSK_GL_TEXTURE_ATLAS_H__
|
||||
#define __GSK_GL_TEXTURE_ATLAS_H__
|
||||
|
||||
#include "stb_rect_pack.h"
|
||||
#include "gskglimageprivate.h"
|
||||
#include "gskgldriverprivate.h"
|
||||
|
||||
struct _GskGLTextureAtlas
|
||||
{
|
||||
struct stbrp_context context;
|
||||
struct stbrp_node *nodes;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
guint texture_id;
|
||||
|
||||
int unused_pixels; /* Pixels of rects that have been used at some point,
|
||||
But are now unused. */
|
||||
|
||||
void *user_data;
|
||||
};
|
||||
typedef struct _GskGLTextureAtlas GskGLTextureAtlas;
|
||||
|
||||
struct _GskGLTextureAtlases
|
||||
{
|
||||
int ref_count;
|
||||
|
||||
GPtrArray *atlases;
|
||||
};
|
||||
typedef struct _GskGLTextureAtlases GskGLTextureAtlases;
|
||||
|
||||
GskGLTextureAtlases *gsk_gl_texture_atlases_new (void);
|
||||
GskGLTextureAtlases *gsk_gl_texture_atlases_ref (GskGLTextureAtlases *atlases);
|
||||
void gsk_gl_texture_atlases_unref (GskGLTextureAtlases *atlases);
|
||||
|
||||
void gsk_gl_texture_atlases_begin_frame (GskGLTextureAtlases *atlases,
|
||||
GPtrArray *removed);
|
||||
gboolean gsk_gl_texture_atlases_pack (GskGLTextureAtlases *atlases,
|
||||
int width,
|
||||
int height,
|
||||
GskGLTextureAtlas **atlas_out,
|
||||
int *out_x,
|
||||
int *out_y);
|
||||
|
||||
void gsk_gl_texture_atlas_init (GskGLTextureAtlas *self,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
void gsk_gl_texture_atlas_free (GskGLTextureAtlas *self);
|
||||
|
||||
void gsk_gl_texture_atlas_realize (GskGLTextureAtlas *self);
|
||||
|
||||
void gsk_gl_texture_atlas_mark_unused (GskGLTextureAtlas *self,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
void gsk_gl_texture_atlas_mark_used (GskGLTextureAtlas *self,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
|
||||
gboolean gsk_gl_texture_atlas_pack (GskGLTextureAtlas *self,
|
||||
int width,
|
||||
int height,
|
||||
int *out_x,
|
||||
int *out_y);
|
||||
|
||||
double gsk_gl_texture_atlas_get_unused_ratio (const GskGLTextureAtlas *self);
|
||||
|
||||
#endif
|
||||
@@ -1,137 +0,0 @@
|
||||
#include "opbuffer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static guint op_sizes[OP_LAST] = {
|
||||
0,
|
||||
sizeof (OpOpacity),
|
||||
sizeof (OpColor),
|
||||
sizeof (OpMatrix),
|
||||
sizeof (OpMatrix),
|
||||
sizeof (OpProgram),
|
||||
sizeof (OpRenderTarget),
|
||||
sizeof (OpClip),
|
||||
sizeof (OpViewport),
|
||||
sizeof (OpTexture),
|
||||
sizeof (OpRepeat),
|
||||
sizeof (OpLinearGradient),
|
||||
sizeof (OpRadialGradient),
|
||||
sizeof (OpColorMatrix),
|
||||
sizeof (OpBlur),
|
||||
sizeof (OpShadow),
|
||||
sizeof (OpOutsetShadow),
|
||||
sizeof (OpBorder),
|
||||
sizeof (OpBorder),
|
||||
sizeof (OpBorder),
|
||||
sizeof (OpCrossFade),
|
||||
sizeof (OpShadow),
|
||||
0,
|
||||
sizeof (OpDraw),
|
||||
sizeof (OpDumpFrameBuffer),
|
||||
sizeof (OpDebugGroup),
|
||||
0,
|
||||
sizeof (OpBlend),
|
||||
sizeof (OpGLShader),
|
||||
sizeof (OpExtraTexture),
|
||||
sizeof (OpConicGradient),
|
||||
};
|
||||
|
||||
void
|
||||
op_buffer_init (OpBuffer *buffer)
|
||||
{
|
||||
static gsize initialized = FALSE;
|
||||
|
||||
if (g_once_init_enter (&initialized))
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (op_sizes); i++)
|
||||
{
|
||||
guint size = op_sizes[i];
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
/* Round all op entry sizes to the nearest 16 to ensure
|
||||
* that we guarantee proper alignments for all op entries.
|
||||
* This is only done once on first use.
|
||||
*/
|
||||
#define CHECK_SIZE(s) else if (size < (s)) { size = s; }
|
||||
if (0) {}
|
||||
CHECK_SIZE (16)
|
||||
CHECK_SIZE (32)
|
||||
CHECK_SIZE (48)
|
||||
CHECK_SIZE (64)
|
||||
CHECK_SIZE (80)
|
||||
CHECK_SIZE (96)
|
||||
CHECK_SIZE (112)
|
||||
CHECK_SIZE (128)
|
||||
CHECK_SIZE (144)
|
||||
CHECK_SIZE (160)
|
||||
CHECK_SIZE (176)
|
||||
CHECK_SIZE (192)
|
||||
else g_assert_not_reached ();
|
||||
#undef CHECK_SIZE
|
||||
|
||||
op_sizes[i] = size;
|
||||
}
|
||||
}
|
||||
|
||||
g_once_init_leave (&initialized, TRUE);
|
||||
}
|
||||
|
||||
memset (buffer, 0, sizeof *buffer);
|
||||
|
||||
buffer->buflen = 4096;
|
||||
buffer->bufpos = 0;
|
||||
buffer->buf = g_malloc (buffer->buflen);
|
||||
buffer->index = g_array_new (FALSE, FALSE, sizeof (OpBufferEntry));
|
||||
|
||||
/* Add dummy entry to guarantee non-empty index */
|
||||
op_buffer_add (buffer, OP_NONE);
|
||||
}
|
||||
|
||||
void
|
||||
op_buffer_destroy (OpBuffer *buffer)
|
||||
{
|
||||
g_free (buffer->buf);
|
||||
g_array_unref (buffer->index);
|
||||
}
|
||||
|
||||
void
|
||||
op_buffer_clear (OpBuffer *buffer)
|
||||
{
|
||||
if (buffer->index->len > 1)
|
||||
g_array_remove_range (buffer->index, 1, buffer->index->len - 1);
|
||||
buffer->bufpos = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ensure_buffer_space_for (OpBuffer *buffer,
|
||||
guint size)
|
||||
{
|
||||
if G_UNLIKELY (buffer->bufpos + size >= buffer->buflen)
|
||||
{
|
||||
buffer->buflen *= 2;
|
||||
buffer->buf = g_realloc (buffer->buf, buffer->buflen);
|
||||
}
|
||||
}
|
||||
|
||||
gpointer
|
||||
op_buffer_add (OpBuffer *buffer,
|
||||
OpKind kind)
|
||||
{
|
||||
guint size = op_sizes[kind];
|
||||
OpBufferEntry entry;
|
||||
|
||||
entry.pos = buffer->bufpos;
|
||||
entry.kind = kind;
|
||||
|
||||
if (size > 0)
|
||||
ensure_buffer_space_for (buffer, size);
|
||||
|
||||
g_array_append_val (buffer->index, entry);
|
||||
|
||||
buffer->bufpos += size;
|
||||
|
||||
return &buffer->buf[entry.pos];
|
||||
}
|
||||
@@ -1,306 +0,0 @@
|
||||
#ifndef __OP_BUFFER_H__
|
||||
#define __OP_BUFFER_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gsk/gsk.h>
|
||||
#include <graphene.h>
|
||||
|
||||
#include "gskgldriverprivate.h"
|
||||
|
||||
typedef struct _Program Program;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OP_NONE = 0,
|
||||
OP_CHANGE_OPACITY = 1,
|
||||
OP_CHANGE_COLOR = 2,
|
||||
OP_CHANGE_PROJECTION = 3,
|
||||
OP_CHANGE_MODELVIEW = 4,
|
||||
OP_CHANGE_PROGRAM = 5,
|
||||
OP_CHANGE_RENDER_TARGET = 6,
|
||||
OP_CHANGE_CLIP = 7,
|
||||
OP_CHANGE_VIEWPORT = 8,
|
||||
OP_CHANGE_SOURCE_TEXTURE = 9,
|
||||
OP_CHANGE_REPEAT = 10,
|
||||
OP_CHANGE_LINEAR_GRADIENT = 11,
|
||||
OP_CHANGE_RADIAL_GRADIENT = 12,
|
||||
OP_CHANGE_COLOR_MATRIX = 13,
|
||||
OP_CHANGE_BLUR = 14,
|
||||
OP_CHANGE_INSET_SHADOW = 15,
|
||||
OP_CHANGE_OUTSET_SHADOW = 16,
|
||||
OP_CHANGE_BORDER = 17,
|
||||
OP_CHANGE_BORDER_COLOR = 18,
|
||||
OP_CHANGE_BORDER_WIDTH = 19,
|
||||
OP_CHANGE_CROSS_FADE = 20,
|
||||
OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 21,
|
||||
OP_CLEAR = 22,
|
||||
OP_DRAW = 23,
|
||||
OP_DUMP_FRAMEBUFFER = 24,
|
||||
OP_PUSH_DEBUG_GROUP = 25,
|
||||
OP_POP_DEBUG_GROUP = 26,
|
||||
OP_CHANGE_BLEND = 27,
|
||||
OP_CHANGE_GL_SHADER_ARGS = 28,
|
||||
OP_CHANGE_EXTRA_SOURCE_TEXTURE = 29,
|
||||
OP_CHANGE_CONIC_GRADIENT = 30,
|
||||
OP_LAST
|
||||
} OpKind;
|
||||
|
||||
|
||||
typedef struct { int value; guint send: 1; } IntUniformValue;
|
||||
typedef struct { float value; guint send: 1; } FloatUniformValue;
|
||||
typedef struct { float value[2]; guint send: 1; } Float2UniformValue;
|
||||
typedef struct { GskRoundedRect value; guint send: 1; guint send_corners: 1; } RRUniformValue;
|
||||
typedef struct { const GdkRGBA *value; guint send: 1; } RGBAUniformValue;
|
||||
typedef struct { const graphene_vec4_t *value; guint send: 1; } Vec4UniformValue;
|
||||
typedef struct { const GskColorStop *value; guint send: 1; } ColorStopUniformValue;
|
||||
typedef struct { const graphene_matrix_t *value; guint send: 1; } MatrixUniformValue;
|
||||
|
||||
/* OpNode are allocated within OpBuffer.pos, but we keep
|
||||
* a secondary index into the locations of that buffer
|
||||
* from OpBuffer.index. This allows peeking at the kind
|
||||
* and quickly replacing existing entries when necessary.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
RRUniformValue outline;
|
||||
FloatUniformValue spread;
|
||||
Float2UniformValue offset;
|
||||
RGBAUniformValue color;
|
||||
} OpShadow;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
RRUniformValue outline;
|
||||
} OpOutsetShadow;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint pos;
|
||||
OpKind kind;
|
||||
} OpBufferEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint8 *buf;
|
||||
gsize buflen;
|
||||
gsize bufpos;
|
||||
GArray *index;
|
||||
} OpBuffer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float opacity;
|
||||
} OpOpacity;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
graphene_matrix_t matrix;
|
||||
} OpMatrix;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const Program *program;
|
||||
} OpProgram;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const GdkRGBA *rgba;
|
||||
} OpColor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int render_target_id;
|
||||
} OpRenderTarget;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskRoundedRect clip;
|
||||
guint send_corners: 1;
|
||||
} OpClip;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
graphene_rect_t viewport;
|
||||
} OpViewport;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int texture_id;
|
||||
} OpTexture;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int texture_id;
|
||||
int idx;
|
||||
} OpExtraTexture;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gsize vao_offset;
|
||||
gsize vao_size;
|
||||
} OpDraw;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ColorStopUniformValue color_stops;
|
||||
IntUniformValue n_color_stops;
|
||||
float start_point[2];
|
||||
float end_point[2];
|
||||
gboolean repeat;
|
||||
} OpLinearGradient;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ColorStopUniformValue color_stops;
|
||||
IntUniformValue n_color_stops;
|
||||
float start;
|
||||
float end;
|
||||
float radius[2];
|
||||
float center[2];
|
||||
gboolean repeat;
|
||||
} OpRadialGradient;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ColorStopUniformValue color_stops;
|
||||
IntUniformValue n_color_stops;
|
||||
float center[2];
|
||||
float angle;
|
||||
} OpConicGradient;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MatrixUniformValue matrix;
|
||||
Vec4UniformValue offset;
|
||||
} OpColorMatrix;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float radius;
|
||||
graphene_size_t size;
|
||||
float dir[2];
|
||||
} OpBlur;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float widths[4];
|
||||
const GdkRGBA *color;
|
||||
GskRoundedRect outline;
|
||||
} OpBorder;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float progress;
|
||||
int source2;
|
||||
} OpCrossFade;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *filename;
|
||||
int width;
|
||||
int height;
|
||||
} OpDumpFrameBuffer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char text[64];
|
||||
} OpDebugGroup;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int source2;
|
||||
int mode;
|
||||
} OpBlend;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float child_bounds[4];
|
||||
float texture_rect[4];
|
||||
} OpRepeat;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float size[2];
|
||||
GskGLShader *shader;
|
||||
const guchar *uniform_data;
|
||||
} OpGLShader;
|
||||
|
||||
void op_buffer_init (OpBuffer *buffer);
|
||||
void op_buffer_destroy (OpBuffer *buffer);
|
||||
void op_buffer_clear (OpBuffer *buffer);
|
||||
gpointer op_buffer_add (OpBuffer *buffer,
|
||||
OpKind kind);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GArray *index;
|
||||
OpBuffer *buffer;
|
||||
guint pos;
|
||||
} OpBufferIter;
|
||||
|
||||
static inline void
|
||||
op_buffer_iter_init (OpBufferIter *iter,
|
||||
OpBuffer *buffer)
|
||||
{
|
||||
iter->index = buffer->index;
|
||||
iter->buffer = buffer;
|
||||
iter->pos = 1; /* Skip first OP_NONE */
|
||||
}
|
||||
|
||||
static inline gpointer
|
||||
op_buffer_iter_next (OpBufferIter *iter,
|
||||
OpKind *kind)
|
||||
{
|
||||
const OpBufferEntry *entry;
|
||||
|
||||
if (iter->pos == iter->index->len)
|
||||
return NULL;
|
||||
|
||||
entry = &g_array_index (iter->index, OpBufferEntry, iter->pos);
|
||||
|
||||
iter->pos++;
|
||||
|
||||
*kind = entry->kind;
|
||||
return &iter->buffer->buf[entry->pos];
|
||||
}
|
||||
|
||||
static inline void
|
||||
op_buffer_pop_tail (OpBuffer *buffer)
|
||||
{
|
||||
/* Never truncate the first OP_NONE */
|
||||
if G_LIKELY (buffer->index->len > 0)
|
||||
buffer->index->len--;
|
||||
}
|
||||
|
||||
static inline gpointer
|
||||
op_buffer_peek_tail (OpBuffer *buffer,
|
||||
OpKind *kind)
|
||||
{
|
||||
const OpBufferEntry *entry;
|
||||
|
||||
entry = &g_array_index (buffer->index, OpBufferEntry, buffer->index->len - 1);
|
||||
*kind = entry->kind;
|
||||
return &buffer->buf[entry->pos];
|
||||
}
|
||||
|
||||
static inline gpointer
|
||||
op_buffer_peek_tail_checked (OpBuffer *buffer,
|
||||
OpKind kind)
|
||||
{
|
||||
const OpBufferEntry *entry;
|
||||
|
||||
entry = &g_array_index (buffer->index, OpBufferEntry, buffer->index->len - 1);
|
||||
|
||||
if (entry->kind == kind)
|
||||
return &buffer->buf[entry->pos];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline guint
|
||||
op_buffer_n_ops (OpBuffer *buffer)
|
||||
{
|
||||
return buffer->index->len - 1;
|
||||
}
|
||||
|
||||
#endif /* __OP_BUFFER_H__ */
|
||||
@@ -1,310 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
uniform int u_mode;
|
||||
uniform sampler2D u_source2;
|
||||
|
||||
float
|
||||
combine (float source, float backdrop)
|
||||
{
|
||||
return source + backdrop * (1.0 - source);
|
||||
}
|
||||
|
||||
vec4
|
||||
composite (vec4 Cs, vec4 Cb, vec3 B)
|
||||
{
|
||||
float ao = Cs.a + Cb.a * (1.0 - Cs.a);
|
||||
vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - Cs.a)*Cb.a*Cb.rgb) / ao;
|
||||
return vec4(Co, ao);
|
||||
}
|
||||
|
||||
vec4
|
||||
normal (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, Cs.rgb);
|
||||
}
|
||||
|
||||
vec4
|
||||
multiply (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, Cs.rgb * Cb.rgb);
|
||||
}
|
||||
|
||||
vec4
|
||||
difference (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb));
|
||||
}
|
||||
|
||||
vec4
|
||||
screen (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb);
|
||||
}
|
||||
|
||||
float
|
||||
hard_light (float source, float backdrop)
|
||||
{
|
||||
if (source <= 0.5)
|
||||
return 2.0 * backdrop * source;
|
||||
else
|
||||
return 2.0 * (backdrop + source - backdrop * source) - 1.0;
|
||||
}
|
||||
|
||||
vec4
|
||||
hard_light (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (hard_light (Cs.r, Cb.r),
|
||||
hard_light (Cs.g, Cb.g),
|
||||
hard_light (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
float
|
||||
soft_light (float source, float backdrop)
|
||||
{
|
||||
float db;
|
||||
|
||||
if (backdrop <= 0.25)
|
||||
db = ((16.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop;
|
||||
else
|
||||
db = sqrt (backdrop);
|
||||
|
||||
if (source <= 0.5)
|
||||
return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop);
|
||||
else
|
||||
return backdrop + (2.0 * source - 1.0) * (db - backdrop);
|
||||
}
|
||||
|
||||
vec4
|
||||
soft_light (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (soft_light (Cs.r, Cb.r),
|
||||
soft_light (Cs.g, Cb.g),
|
||||
soft_light (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
overlay (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (hard_light (Cb.r, Cs.r),
|
||||
hard_light (Cb.g, Cs.g),
|
||||
hard_light (Cb.b, Cs.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
darken (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = min (Cs.rgb, Cb.rgb);
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
lighten (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = max (Cs.rgb, Cb.rgb);
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
float
|
||||
color_dodge (float source, float backdrop)
|
||||
{
|
||||
return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0);
|
||||
}
|
||||
|
||||
vec4
|
||||
color_dodge (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (color_dodge (Cs.r, Cb.r),
|
||||
color_dodge (Cs.g, Cb.g),
|
||||
color_dodge (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
color_burn (float source, float backdrop)
|
||||
{
|
||||
return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0);
|
||||
}
|
||||
|
||||
vec4
|
||||
color_burn (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = vec3 (color_burn (Cs.r, Cb.r),
|
||||
color_burn (Cs.g, Cb.g),
|
||||
color_burn (Cs.b, Cb.b));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
exclusion (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb;
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
float
|
||||
lum (vec3 c)
|
||||
{
|
||||
return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
|
||||
}
|
||||
|
||||
vec3
|
||||
clip_color (vec3 c)
|
||||
{
|
||||
float l = lum (c);
|
||||
float n = min (c.r, min (c.g, c.b));
|
||||
float x = max (c.r, max (c.g, c.b));
|
||||
if (n < 0.0) c = l + (((c - l) * l) / (l - n));
|
||||
if (x > 1.0) c = l + (((c - l) * (1.0 - l)) / (x - l));
|
||||
return c;
|
||||
}
|
||||
|
||||
vec3
|
||||
set_lum (vec3 c, float l)
|
||||
{
|
||||
float d = l - lum (c);
|
||||
return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
|
||||
}
|
||||
|
||||
float
|
||||
sat (vec3 c)
|
||||
{
|
||||
return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
|
||||
}
|
||||
|
||||
vec3
|
||||
set_sat (vec3 c, float s)
|
||||
{
|
||||
float cmin = min (c.r, min (c.g, c.b));
|
||||
float cmax = max (c.r, max (c.g, c.b));
|
||||
vec3 res;
|
||||
|
||||
if (cmax == cmin)
|
||||
res = vec3 (0, 0, 0);
|
||||
else
|
||||
{
|
||||
if (c.r == cmax)
|
||||
{
|
||||
if (c.g == cmin)
|
||||
{
|
||||
res.b = ((c.b - cmin) * s) / (cmax - cmin);
|
||||
res.g = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.g = ((c.g - cmin) * s) / (cmax - cmin);
|
||||
res.b = 0.0;
|
||||
}
|
||||
res.r = s;
|
||||
}
|
||||
else if (c.g == cmax)
|
||||
{
|
||||
if (c.r == cmin)
|
||||
{
|
||||
res.b = ((c.b - cmin) * s) / (cmax - cmin);
|
||||
res.r = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.r = ((c.r - cmin) * s) / (cmax - cmin);
|
||||
res.b = 0.0;
|
||||
}
|
||||
res.g = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c.r == cmin)
|
||||
{
|
||||
res.g = ((c.g - cmin) * s) / (cmax - cmin);
|
||||
res.r = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.r = ((c.r - cmin) * s) / (cmax - cmin);
|
||||
res.g = 0.0;
|
||||
}
|
||||
res.b = s;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
vec4
|
||||
color (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
hue (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
saturation (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
vec4
|
||||
luminosity (vec4 Cs, vec4 Cb)
|
||||
{
|
||||
vec3 B = set_lum (Cb.rgb, lum (Cs.rgb));
|
||||
return composite (Cs, Cb, B);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 bottom_color = GskTexture(u_source, vUv);
|
||||
vec4 top_color = GskTexture(u_source2, vUv);
|
||||
|
||||
vec4 result;
|
||||
if (u_mode == 0)
|
||||
result = normal(top_color, bottom_color);
|
||||
else if (u_mode == 1)
|
||||
result = multiply(top_color, bottom_color);
|
||||
else if (u_mode == 2)
|
||||
result = screen(top_color, bottom_color);
|
||||
else if (u_mode == 3)
|
||||
result = overlay(top_color, bottom_color);
|
||||
else if (u_mode == 4)
|
||||
result = darken(top_color, bottom_color);
|
||||
else if (u_mode == 5)
|
||||
result = lighten(top_color, bottom_color);
|
||||
else if (u_mode == 6)
|
||||
result = color_dodge(top_color, bottom_color);
|
||||
else if (u_mode == 7)
|
||||
result = color_burn(top_color, bottom_color);
|
||||
else if (u_mode == 8)
|
||||
result = hard_light(top_color, bottom_color);
|
||||
else if (u_mode == 9)
|
||||
result = soft_light(top_color, bottom_color);
|
||||
else if (u_mode == 10)
|
||||
result = difference(top_color, bottom_color);
|
||||
else if (u_mode == 11)
|
||||
result = exclusion(top_color, bottom_color);
|
||||
else if (u_mode == 12)
|
||||
result = color(top_color, bottom_color);
|
||||
else if (u_mode == 13)
|
||||
result = hue(top_color, bottom_color);
|
||||
else if (u_mode == 14)
|
||||
result = saturation(top_color, bottom_color);
|
||||
else if (u_mode == 15)
|
||||
result = luminosity(top_color, bottom_color);
|
||||
else
|
||||
discard;
|
||||
|
||||
gskSetOutputColor(result * u_alpha);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
void main() {
|
||||
vec4 diffuse = GskTexture(u_source, vUv);
|
||||
|
||||
gskSetOutputColor(diffuse * u_alpha);
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
uniform float u_blur_radius;
|
||||
uniform vec2 u_blur_size;
|
||||
uniform vec2 u_blur_dir;
|
||||
|
||||
_OUT_ vec2 pixel_step;
|
||||
_OUT_ float pixels_per_side;
|
||||
_OUT_ vec3 initial_gaussian;
|
||||
|
||||
const float PI = 3.14159265;
|
||||
const float RADIUS_MULTIPLIER = 2.0;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
|
||||
pixel_step = (vec2(1.0) / u_blur_size) * u_blur_dir;
|
||||
pixels_per_side = floor(u_blur_radius * RADIUS_MULTIPLIER / 2.0);
|
||||
|
||||
float sigma = u_blur_radius / 2.0; // *shrug*
|
||||
initial_gaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma);
|
||||
initial_gaussian.y = exp(-0.5 / (sigma * sigma));
|
||||
initial_gaussian.z = initial_gaussian.y * initial_gaussian.y;
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
_IN_ vec2 pixel_step;
|
||||
_IN_ float pixels_per_side;
|
||||
_IN_ vec3 initial_gaussian;
|
||||
|
||||
// blur_radius 0 is NOT supported and MUST be caught before.
|
||||
|
||||
// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
|
||||
void main() {
|
||||
vec3 incrementalGaussian = initial_gaussian;
|
||||
|
||||
float coefficientSum = 0.0;
|
||||
vec4 sum = GskTexture(u_source, vUv) * incrementalGaussian.x;
|
||||
coefficientSum += incrementalGaussian.x;
|
||||
incrementalGaussian.xy *= incrementalGaussian.yz;
|
||||
|
||||
vec2 p = pixel_step;
|
||||
for (int i = 1; i <= int(pixels_per_side); i++) {
|
||||
sum += GskTexture(u_source, vUv - p) * incrementalGaussian.x;
|
||||
sum += GskTexture(u_source, vUv + p) * incrementalGaussian.x;
|
||||
|
||||
coefficientSum += 2.0 * incrementalGaussian.x;
|
||||
incrementalGaussian.xy *= incrementalGaussian.yz;
|
||||
|
||||
p += pixel_step;
|
||||
}
|
||||
|
||||
gskSetOutputColor(sum / coefficientSum);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
uniform vec4 u_color;
|
||||
uniform vec4 u_widths;
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
|
||||
GskRoundedRect outside = gsk_create_rect(u_outline_rect);
|
||||
GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths);
|
||||
|
||||
gsk_rounded_rect_transform(outside, u_modelview);
|
||||
gsk_rounded_rect_transform(inside, u_modelview);
|
||||
|
||||
gsk_rounded_rect_encode(outside, transformed_outside_outline);
|
||||
gsk_rounded_rect_encode(inside, transformed_inside_outline);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_IN_ vec4 final_color;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
vec2 frag = gsk_get_frag_coord();
|
||||
|
||||
float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
|
||||
gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
|
||||
0.0, 1.0);
|
||||
|
||||
gskSetOutputColor(final_color * alpha);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
uniform vec4 u_color;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
_IN_ vec4 final_color;
|
||||
|
||||
void main() {
|
||||
gskSetOutputColor(final_color);
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
uniform mat4 u_color_matrix;
|
||||
uniform vec4 u_color_offset;
|
||||
|
||||
void main() {
|
||||
vec4 color = GskTexture(u_source, vUv);
|
||||
|
||||
// Un-premultilpy
|
||||
if (color.a != 0.0)
|
||||
color.rgb /= color.a;
|
||||
|
||||
color = u_color_matrix * color + u_color_offset;
|
||||
color = clamp(color, 0.0, 1.0);
|
||||
|
||||
color.rgb *= color.a;
|
||||
|
||||
gskSetOutputColor(color * u_alpha);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
uniform vec4 u_color;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
|
||||
_IN_ vec4 final_color;
|
||||
|
||||
void main() {
|
||||
vec4 diffuse = GskTexture(u_source, vUv);
|
||||
|
||||
gskSetOutputColor(final_color * diffuse.a);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// VERTEX_SHADER
|
||||
uniform vec4 u_geometry;
|
||||
|
||||
_NOPERSPECTIVE_ _OUT_ vec2 coord;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
|
||||
|
||||
vec2 mv0 = u_modelview[0].xy;
|
||||
vec2 mv1 = u_modelview[1].xy;
|
||||
vec2 offset = aPosition - u_geometry.xy;
|
||||
|
||||
coord = vec2(dot(mv0, offset),
|
||||
dot(mv1, offset));
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
#ifdef GSK_LEGACY
|
||||
uniform int u_num_color_stops;
|
||||
#else
|
||||
uniform highp int u_num_color_stops; // Why? Because it works like this.
|
||||
#endif
|
||||
|
||||
uniform vec4 u_geometry;
|
||||
uniform float u_color_stops[6 * 5];
|
||||
|
||||
_NOPERSPECTIVE_ _IN_ vec2 coord;
|
||||
|
||||
float get_offset(int index) {
|
||||
return u_color_stops[5 * index];
|
||||
}
|
||||
|
||||
vec4 get_color(int index) {
|
||||
int base = 5 * index + 1;
|
||||
|
||||
return vec4(u_color_stops[base],
|
||||
u_color_stops[base + 1],
|
||||
u_color_stops[base + 2],
|
||||
u_color_stops[base + 3]);
|
||||
}
|
||||
|
||||
void main() {
|
||||
// direction of point in range [-PI, PI]
|
||||
vec2 pos = floor(coord);
|
||||
float angle = atan(pos.y, pos.x);
|
||||
|
||||
// fract() does the modulo here, so now we have progress
|
||||
// into the current conic
|
||||
float offset = fract(angle * u_geometry.z + u_geometry.w);
|
||||
|
||||
if (offset < get_offset(0)) {
|
||||
gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
|
||||
return;
|
||||
}
|
||||
|
||||
int n = u_num_color_stops - 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
float curr_offset = get_offset(i);
|
||||
float next_offset = get_offset(i + 1);
|
||||
|
||||
if (offset >= curr_offset && offset < next_offset) {
|
||||
float f = (offset - curr_offset) / (next_offset - curr_offset);
|
||||
vec4 curr_color = gsk_premultiply(get_color(i));
|
||||
vec4 next_color = gsk_premultiply(get_color(i + 1));
|
||||
vec4 color = mix(curr_color, next_color, f);
|
||||
|
||||
gskSetOutputColor(color * u_alpha);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
uniform float u_progress;
|
||||
uniform sampler2D u_source2;
|
||||
|
||||
void main() {
|
||||
vec4 source1 = GskTexture(u_source, vUv); // start child
|
||||
vec4 source2 = GskTexture(u_source2, vUv); // end child
|
||||
|
||||
float p_start = (1.0 - u_progress) * u_alpha;
|
||||
float p_end = u_progress * u_alpha;
|
||||
vec4 color = (p_start * source1) + (p_end * source2);
|
||||
gskSetOutputColor(color);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// The shader supplies:
|
||||
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv);
|
||||
|
||||
uniform vec2 u_size;
|
||||
uniform sampler2D u_source2;
|
||||
uniform sampler2D u_source3;
|
||||
uniform sampler2D u_source4;
|
||||
|
||||
void main() {
|
||||
vec4 fragColor;
|
||||
vec2 fragCoord = vec2(vUv.x * u_size.x, (1.0-vUv.y) * u_size.y);
|
||||
mainImage(fragColor, fragCoord, u_size, vUv);
|
||||
gskSetOutputColor(fragColor);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
uniform vec4 u_color;
|
||||
uniform float u_spread;
|
||||
uniform vec2 u_offset;
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
|
||||
GskRoundedRect outside = gsk_create_rect(u_outline_rect);
|
||||
GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread));
|
||||
|
||||
gsk_rounded_rect_offset(inside, u_offset);
|
||||
|
||||
gsk_rounded_rect_transform(outside, u_modelview);
|
||||
gsk_rounded_rect_transform(inside, u_modelview);
|
||||
|
||||
gsk_rounded_rect_encode(outside, transformed_outside_outline);
|
||||
gsk_rounded_rect_encode(inside, transformed_inside_outline);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
_IN_ vec4 final_color;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
vec2 frag = gsk_get_frag_coord();
|
||||
|
||||
float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
|
||||
gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
|
||||
0.0, 1.0);
|
||||
|
||||
gskSetOutputColor(final_color * alpha);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
// VERTEX_SHADER
|
||||
uniform vec4 u_points;
|
||||
|
||||
_NOPERSPECTIVE_ _OUT_ vec4 info;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
|
||||
|
||||
vec2 mv0 = u_modelview[0].xy;
|
||||
vec2 mv1 = u_modelview[1].xy;
|
||||
vec2 offset = aPosition - u_points.xy;
|
||||
vec2 coord = vec2(dot(mv0, offset),
|
||||
dot(mv1, offset));
|
||||
|
||||
// Original equation:
|
||||
// VS | maxDist = length(end - start);
|
||||
// VS | gradient = end - start;
|
||||
// VS | gradientLength = length(gradient);
|
||||
// FS | pos = frag_coord - start
|
||||
// FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient
|
||||
// FS | offset = length(proj) / maxDist
|
||||
|
||||
// Simplified formula derivation:
|
||||
// 1. Notice that maxDist = gradientLength:
|
||||
// offset = length(proj) / gradientLength
|
||||
// 2. Let gnorm = gradient / gradientLength, then:
|
||||
// proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * gradientLength) =
|
||||
// = dot(gnorm, pos) * gnorm
|
||||
// 3. Since gnorm is unit length then:
|
||||
// length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos)
|
||||
// 4. We can avoid the FS division by passing a scaled pos from the VS:
|
||||
// offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength)
|
||||
// 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL
|
||||
vec2 gradient = vec2(dot(mv0, u_points.zw),
|
||||
dot(mv1, u_points.zw));
|
||||
float rcp_gradient_length = inversesqrt(dot(gradient, gradient));
|
||||
|
||||
info = rcp_gradient_length * vec4(coord, gradient);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
#ifdef GSK_LEGACY
|
||||
uniform int u_num_color_stops;
|
||||
#else
|
||||
uniform highp int u_num_color_stops; // Why? Because it works like this.
|
||||
#endif
|
||||
|
||||
uniform float u_color_stops[6 * 5];
|
||||
uniform bool u_repeat;
|
||||
|
||||
_NOPERSPECTIVE_ _IN_ vec4 info;
|
||||
|
||||
float get_offset(int index) {
|
||||
return u_color_stops[5 * index];
|
||||
}
|
||||
|
||||
vec4 get_color(int index) {
|
||||
int base = 5 * index + 1;
|
||||
|
||||
return vec4(u_color_stops[base],
|
||||
u_color_stops[base + 1],
|
||||
u_color_stops[base + 2],
|
||||
u_color_stops[base + 3]);
|
||||
}
|
||||
|
||||
void main() {
|
||||
float offset = dot(info.xy, info.zw);
|
||||
|
||||
if (u_repeat) {
|
||||
offset = fract(offset);
|
||||
}
|
||||
|
||||
if (offset < get_offset(0)) {
|
||||
gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
|
||||
return;
|
||||
}
|
||||
|
||||
int n = u_num_color_stops - 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
float curr_offset = get_offset(i);
|
||||
float next_offset = get_offset(i + 1);
|
||||
|
||||
if (offset >= curr_offset && offset < next_offset) {
|
||||
float f = (offset - curr_offset) / (next_offset - curr_offset);
|
||||
vec4 curr_color = gsk_premultiply(get_color(i));
|
||||
vec4 next_color = gsk_premultiply(get_color(i + 1));
|
||||
vec4 color = mix(curr_color, next_color, f);
|
||||
|
||||
gskSetOutputColor(color * u_alpha);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
uniform vec4 u_color;
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
|
||||
GskRoundedRect outline = gsk_create_rect(u_outline_rect);
|
||||
gsk_rounded_rect_transform(outline, u_modelview);
|
||||
gsk_rounded_rect_encode(outline, transformed_outline);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
_IN_ vec4 final_color;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline;
|
||||
|
||||
void main() {
|
||||
vec2 frag = gsk_get_frag_coord();
|
||||
|
||||
float alpha = GskTexture(u_source, vUv).a;
|
||||
alpha *= (1.0 - clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outline), frag), 0.0, 1.0));
|
||||
|
||||
vec4 color = final_color * alpha;
|
||||
|
||||
gskSetOutputColor(color);
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
uniform sampler2D u_source;
|
||||
uniform mat4 u_projection;
|
||||
uniform mat4 u_modelview;
|
||||
uniform float u_alpha;// = 1.0;
|
||||
uniform vec4 u_viewport;
|
||||
uniform vec4[3] u_clip_rect;
|
||||
|
||||
#if defined(GSK_LEGACY)
|
||||
_OUT_ vec4 outputColor;
|
||||
#elif !defined(GSK_GLES)
|
||||
_OUT_ vec4 outputColor;
|
||||
#endif
|
||||
|
||||
_IN_ vec2 vUv;
|
||||
|
||||
|
||||
|
||||
GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r)
|
||||
{
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
return GskRoundedRect(r[0], r[1], r[2]);
|
||||
#else
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
float
|
||||
gsk_ellipsis_dist (vec2 p, vec2 radius)
|
||||
{
|
||||
if (radius == vec2(0, 0))
|
||||
return 0.0;
|
||||
|
||||
vec2 p0 = p / radius;
|
||||
vec2 p1 = 2.0 * p0 / radius;
|
||||
|
||||
return (dot(p0, p0) - 1.0) / length (p1);
|
||||
}
|
||||
|
||||
float
|
||||
gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
|
||||
{
|
||||
float d = gsk_ellipsis_dist (point - center, radius);
|
||||
return clamp (0.5 - d, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float
|
||||
gsk_rounded_rect_coverage (GskRoundedRect r, vec2 p)
|
||||
{
|
||||
if (p.x < r.bounds.x || p.y < r.bounds.y ||
|
||||
p.x >= r.bounds.z || p.y >= r.bounds.w)
|
||||
return 0.0;
|
||||
|
||||
vec2 ref_tl = r.corner_points1.xy;
|
||||
vec2 ref_tr = r.corner_points1.zw;
|
||||
vec2 ref_br = r.corner_points2.xy;
|
||||
vec2 ref_bl = r.corner_points2.zw;
|
||||
|
||||
if (p.x >= ref_tl.x && p.x >= ref_bl.x &&
|
||||
p.x <= ref_tr.x && p.x <= ref_br.x)
|
||||
return 1.0;
|
||||
|
||||
if (p.y >= ref_tl.y && p.y >= ref_tr.y &&
|
||||
p.y <= ref_bl.y && p.y <= ref_br.y)
|
||||
return 1.0;
|
||||
|
||||
vec2 rad_tl = r.corner_points1.xy - r.bounds.xy;
|
||||
vec2 rad_tr = r.corner_points1.zw - r.bounds.zy;
|
||||
vec2 rad_br = r.corner_points2.xy - r.bounds.zw;
|
||||
vec2 rad_bl = r.corner_points2.zw - r.bounds.xw;
|
||||
|
||||
float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl);
|
||||
float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr);
|
||||
float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br);
|
||||
float d_bl = gsk_ellipsis_coverage(p, ref_bl, rad_bl);
|
||||
|
||||
vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
|
||||
|
||||
bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y,
|
||||
p.x > ref_tr.x && p.y < ref_tr.y,
|
||||
p.x > ref_br.x && p.y > ref_br.y,
|
||||
p.x < ref_bl.x && p.y > ref_bl.y);
|
||||
|
||||
return 1.0 - dot(vec4(is_out), corner_coverages);
|
||||
}
|
||||
|
||||
float
|
||||
gsk_rect_coverage (vec4 r, vec2 p)
|
||||
{
|
||||
if (p.x < r.x || p.y < r.y ||
|
||||
p.x >= r.z || p.y >= r.w)
|
||||
return 0.0;
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
vec4 GskTexture(sampler2D sampler, vec2 texCoords) {
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
return texture2D(sampler, texCoords);
|
||||
#else
|
||||
return texture(sampler, texCoords);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef GSK_GL3
|
||||
layout(origin_upper_left) in vec4 gl_FragCoord;
|
||||
#endif
|
||||
|
||||
vec2 gsk_get_frag_coord() {
|
||||
vec2 fc = gl_FragCoord.xy;
|
||||
|
||||
#ifdef GSK_GL3
|
||||
fc += u_viewport.xy;
|
||||
#else
|
||||
fc.x += u_viewport.x;
|
||||
fc.y = (u_viewport.y + u_viewport.w) - fc.y;
|
||||
#endif
|
||||
|
||||
return fc;
|
||||
}
|
||||
|
||||
void gskSetOutputColor(vec4 color) {
|
||||
vec4 result;
|
||||
|
||||
#if defined(NO_CLIP)
|
||||
result = color;
|
||||
#elif defined(RECT_CLIP)
|
||||
result = color * gsk_rect_coverage(gsk_get_bounds(u_clip_rect),
|
||||
gsk_get_frag_coord());
|
||||
#else
|
||||
result = color * gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect),
|
||||
gsk_get_frag_coord());
|
||||
#endif
|
||||
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
gl_FragColor = result;
|
||||
#else
|
||||
outputColor = result;
|
||||
#endif
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
#ifndef GSK_LEGACY
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
#define _OUT_ varying
|
||||
#define _IN_ varying
|
||||
#define _NOPERSPECTIVE_
|
||||
#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3]
|
||||
#else
|
||||
#define _OUT_ out
|
||||
#define _IN_ in
|
||||
#define _NOPERSPECTIVE_ noperspective
|
||||
#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect
|
||||
#endif
|
||||
|
||||
|
||||
struct GskRoundedRect
|
||||
{
|
||||
vec4 bounds; // Top left and bottom right
|
||||
// Look, arrays can't be in structs if you want to return the struct
|
||||
// from a function in gles or whatever. Just kill me.
|
||||
vec4 corner_points1; // xy = top left, zw = top right
|
||||
vec4 corner_points2; // xy = bottom right, zw = bottom left
|
||||
};
|
||||
|
||||
// Transform from a C GskRoundedRect to what we need.
|
||||
GskRoundedRect
|
||||
gsk_create_rect(vec4[3] data)
|
||||
{
|
||||
vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw);
|
||||
|
||||
vec4 corner_points1 = vec4(bounds.xy + data[1].xy,
|
||||
bounds.zy + vec2(data[1].zw * vec2(-1, 1)));
|
||||
vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)),
|
||||
bounds.xw + vec2(data[2].zw * vec2(1, -1)));
|
||||
|
||||
return GskRoundedRect(bounds, corner_points1, corner_points2);
|
||||
}
|
||||
|
||||
vec4
|
||||
gsk_get_bounds(vec4[3] data)
|
||||
{
|
||||
return vec4(data[0].xy, data[0].xy + data[0].zw);
|
||||
}
|
||||
|
||||
vec4 gsk_premultiply(vec4 c) {
|
||||
return vec4(c.rgb * c.a, c.a);
|
||||
}
|
||||
|
||||
vec4 gsk_scaled_premultiply(vec4 c, float s) {
|
||||
// Fast version of gsk_premultiply(c) * s
|
||||
// 4 muls instead of 7
|
||||
float a = s * c.a;
|
||||
|
||||
return vec4(c.rgb * a, a);
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
uniform mat4 u_projection;
|
||||
uniform mat4 u_modelview;
|
||||
uniform float u_alpha;
|
||||
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
attribute vec2 aPosition;
|
||||
attribute vec2 aUv;
|
||||
_OUT_ vec2 vUv;
|
||||
#else
|
||||
_IN_ vec2 aPosition;
|
||||
_IN_ vec2 aUv;
|
||||
_OUT_ vec2 vUv;
|
||||
#endif
|
||||
|
||||
// amount is: top, right, bottom, left
|
||||
GskRoundedRect
|
||||
gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount)
|
||||
{
|
||||
vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz;
|
||||
vec4 new_corner_points1 = r.corner_points1;
|
||||
vec4 new_corner_points2 = r.corner_points2;
|
||||
|
||||
if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy;
|
||||
if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy;
|
||||
if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw;
|
||||
if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw;
|
||||
|
||||
return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset)
|
||||
{
|
||||
r.bounds.xy += offset;
|
||||
r.bounds.zw += offset;
|
||||
r.corner_points1.xy += offset;
|
||||
r.corner_points1.zw += offset;
|
||||
r.corner_points2.xy += offset;
|
||||
r.corner_points2.zw += offset;
|
||||
}
|
||||
|
||||
void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat)
|
||||
{
|
||||
r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy;
|
||||
r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy;
|
||||
|
||||
r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy;
|
||||
r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy;
|
||||
|
||||
r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy;
|
||||
r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy;
|
||||
}
|
||||
|
||||
#if defined(GSK_LEGACY)
|
||||
// Can't have out or inout array parameters...
|
||||
#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2;
|
||||
#else
|
||||
void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r)
|
||||
{
|
||||
#if defined(GSK_GLES)
|
||||
out_r[0] = r.bounds;
|
||||
out_r[1] = r.corner_points1;
|
||||
out_r[2] = r.corner_points2;
|
||||
#else
|
||||
out_r = r;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,74 +0,0 @@
|
||||
// VERTEX_SHADER
|
||||
uniform vec4 u_geometry;
|
||||
|
||||
_NOPERSPECTIVE_ _OUT_ vec2 coord;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
|
||||
|
||||
vec2 mv0 = u_modelview[0].xy;
|
||||
vec2 mv1 = u_modelview[1].xy;
|
||||
vec2 offset = aPosition - u_geometry.xy;
|
||||
vec2 dir = vec2(dot(mv0, offset),
|
||||
dot(mv1, offset));
|
||||
|
||||
coord = dir * u_geometry.zw;
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
#ifdef GSK_LEGACY
|
||||
uniform int u_num_color_stops;
|
||||
#else
|
||||
uniform highp int u_num_color_stops;
|
||||
#endif
|
||||
|
||||
uniform bool u_repeat;
|
||||
uniform vec2 u_range;
|
||||
uniform float u_color_stops[6 * 5];
|
||||
|
||||
_NOPERSPECTIVE_ _IN_ vec2 coord;
|
||||
|
||||
float get_offset(int index) {
|
||||
return u_color_stops[5 * index];
|
||||
}
|
||||
|
||||
vec4 get_color(int index) {
|
||||
int base = 5 * index + 1;
|
||||
|
||||
return vec4(u_color_stops[base],
|
||||
u_color_stops[base + 1],
|
||||
u_color_stops[base + 2],
|
||||
u_color_stops[base + 3]);
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Reverse scale
|
||||
float offset = length(coord) * u_range.x + u_range.y;
|
||||
|
||||
if (u_repeat) {
|
||||
offset = fract(offset);
|
||||
}
|
||||
|
||||
if (offset < get_offset(0)) {
|
||||
gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
|
||||
return;
|
||||
}
|
||||
|
||||
int n = u_num_color_stops - 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
float curr_offset = get_offset(i);
|
||||
float next_offset = get_offset(i + 1);
|
||||
|
||||
if (offset >= curr_offset && offset < next_offset) {
|
||||
float f = (offset - curr_offset) / (next_offset - curr_offset);
|
||||
vec4 curr_color = gsk_premultiply(get_color(i));
|
||||
vec4 next_color = gsk_premultiply(get_color(i + 1));
|
||||
vec4 color = mix(curr_color, next_color, f);
|
||||
|
||||
gskSetOutputColor(color * u_alpha);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
uniform vec4 u_child_bounds;
|
||||
uniform vec4 u_texture_rect;
|
||||
|
||||
|
||||
float wrap(float f, float wrap_for) {
|
||||
return mod(f, wrap_for);
|
||||
}
|
||||
|
||||
/* We get the texture coordinates via vUv,
|
||||
* but that might be on a texture atlas, so we need to do the
|
||||
* wrapping ourselves.
|
||||
*/
|
||||
void main() {
|
||||
|
||||
/* We map the texture coordinate to [1;0], then wrap it and scale the result again */
|
||||
|
||||
float tw = u_texture_rect.z - u_texture_rect.x;
|
||||
float th = u_texture_rect.w - u_texture_rect.y;
|
||||
|
||||
float mapped_x = (vUv.x - u_texture_rect.x) / tw;
|
||||
float mapped_y = (vUv.y - u_texture_rect.y) / th;
|
||||
|
||||
float wrapped_x = wrap(u_child_bounds.x + mapped_x * u_child_bounds.z, 1.0);
|
||||
float wrapped_y = wrap(u_child_bounds.y + mapped_y * u_child_bounds.w, 1.0);
|
||||
|
||||
vec2 tp;
|
||||
tp.x = u_texture_rect.x + (wrapped_x * tw);
|
||||
tp.y = u_texture_rect.y + (wrapped_y * th);
|
||||
|
||||
vec4 diffuse = GskTexture(u_source, tp);
|
||||
|
||||
gskSetOutputColor(diffuse * u_alpha);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// VERTEX_SHADER:
|
||||
uniform vec4 u_color;
|
||||
uniform float u_spread;
|
||||
uniform vec2 u_offset;
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_OUT_ vec4 final_color;
|
||||
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
final_color = gsk_premultiply(u_color) * u_alpha;
|
||||
|
||||
GskRoundedRect inside = gsk_create_rect(u_outline_rect);
|
||||
GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread));
|
||||
|
||||
gsk_rounded_rect_offset(outside, u_offset);
|
||||
|
||||
gsk_rounded_rect_transform(outside, u_modelview);
|
||||
gsk_rounded_rect_transform(inside, u_modelview);
|
||||
|
||||
gsk_rounded_rect_encode(outside, transformed_outside_outline);
|
||||
gsk_rounded_rect_encode(inside, transformed_inside_outline);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
_IN_ vec4 final_color;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
vec2 frag = gsk_get_frag_coord();
|
||||
|
||||
float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) -
|
||||
gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag),
|
||||
0.0, 1.0);
|
||||
|
||||
gskSetOutputColor(final_color * alpha);
|
||||
}
|
||||
|
||||
@@ -139,7 +139,6 @@
|
||||
#include "gskglshaderprivate.h"
|
||||
#include "gskdebugprivate.h"
|
||||
|
||||
#include "gl/gskglrendererprivate.h"
|
||||
#include "ngl/gsknglrendererprivate.h"
|
||||
|
||||
static GskGLUniformType
|
||||
@@ -544,9 +543,7 @@ gsk_gl_shader_compile (GskGLShader *shader,
|
||||
{
|
||||
g_return_val_if_fail (GSK_IS_GL_SHADER (shader), FALSE);
|
||||
|
||||
if (GSK_IS_GL_RENDERER (renderer))
|
||||
return gsk_gl_renderer_try_compile_gl_shader (GSK_GL_RENDERER (renderer), shader, error);
|
||||
else if (GSK_IS_NGL_RENDERER (renderer))
|
||||
if (GSK_IS_NGL_RENDERER (renderer))
|
||||
return gsk_ngl_renderer_try_compile_gl_shader (GSK_NGL_RENDERER (renderer), shader, error);
|
||||
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
#include "gskcairorenderer.h"
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gl/gskglrenderer.h"
|
||||
#include "ngl/gsknglrenderer.h"
|
||||
#include "gskprofilerprivate.h"
|
||||
#include "gskrendernodeprivate.h"
|
||||
@@ -508,8 +507,6 @@ get_renderer_for_name (const char *renderer_name)
|
||||
else if (g_ascii_strcasecmp (renderer_name, "opengl") == 0 ||
|
||||
g_ascii_strcasecmp (renderer_name, "ngl") == 0)
|
||||
return GSK_TYPE_NGL_RENDERER;
|
||||
else if (g_ascii_strcasecmp (renderer_name, "gl") == 0)
|
||||
return GSK_TYPE_GL_RENDERER;
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
else if (g_ascii_strcasecmp (renderer_name, "vulkan") == 0)
|
||||
return GSK_TYPE_VULKAN_RENDERER;
|
||||
@@ -520,12 +517,11 @@ get_renderer_for_name (const char *renderer_name)
|
||||
#ifdef GDK_WINDOWING_BROADWAY
|
||||
g_print ("broadway - Use the Broadway specific renderer\n");
|
||||
#else
|
||||
g_print ("broadway - disabled during GTK build\n");
|
||||
g_print ("broadway - Disabled during GTK build\n");
|
||||
#endif
|
||||
g_print (" cairo - Use the Cairo fallback renderer\n");
|
||||
g_print (" opengl - Use the default OpenGL renderer\n");
|
||||
g_print (" gl - An OpenGL renderer\n");
|
||||
g_print (" ngl - Another OpenGL renderer\n");
|
||||
g_print (" ngl - An OpenGL renderer\n");
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
g_print (" vulkan - Use the Vulkan renderer\n");
|
||||
#else
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* GskRenderNode: (ref-func gsk_render_node_ref) (unref-func gsk_render_node_unref)
|
||||
* GskRenderNode: (ref-func gsk_render_node_ref) (unref-func gsk_render_node_unref) (set-value-func gsk_value_set_render_node) (get-value-func gsk_value_get_render_node)
|
||||
*
|
||||
* `GskRenderNode` is the basic block in a scene graph to be
|
||||
* rendered using `GskRenderer`.
|
||||
@@ -620,3 +620,108 @@ gsk_render_node_deserialize (GBytes *bytes,
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_value_set_render_node:
|
||||
* @value: a `GValue` initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
* @node: a `GskRenderNode`
|
||||
*
|
||||
* Stores the given `GskRenderNode` inside `value`.
|
||||
*
|
||||
* The `GValue` will acquire a reference to the `node`.
|
||||
*/
|
||||
void
|
||||
gsk_value_set_render_node (GValue *value,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
GskRenderNode *old_node;
|
||||
|
||||
g_return_if_fail (G_VALUE_HOLDS (value, GSK_TYPE_RENDER_NODE));
|
||||
|
||||
old_node = value->data[0].v_pointer;
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_RENDER_NODE (node));
|
||||
|
||||
value->data[0].v_pointer = gsk_render_node_ref (node);
|
||||
}
|
||||
else
|
||||
{
|
||||
value->data[0].v_pointer = NULL;
|
||||
}
|
||||
|
||||
if (old_node != NULL)
|
||||
gsk_render_node_unref (old_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_value_take_render_node:
|
||||
* @value: a `GValue` initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
* @node: (transfer full) (nullable): a `GskRenderNode`
|
||||
*
|
||||
* Stores the given `GskRenderNode` inside `value`.
|
||||
*
|
||||
* This function transfers the ownership of the `node` to the `GValue`.
|
||||
*/
|
||||
void
|
||||
gsk_value_take_render_node (GValue *value,
|
||||
GskRenderNode *node)
|
||||
{
|
||||
GskRenderNode *old_node;
|
||||
|
||||
g_return_if_fail (G_VALUE_HOLDS (value, GSK_TYPE_RENDER_NODE));
|
||||
|
||||
old_node = value->data[0].v_pointer;
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_RENDER_NODE (node));
|
||||
|
||||
value->data[0].v_pointer = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
value->data[0].v_pointer = NULL;
|
||||
}
|
||||
|
||||
if (old_node != NULL)
|
||||
gsk_render_node_unref (old_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_value_get_render_node:
|
||||
* @value: a `GValue` initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
*
|
||||
* Retrieves the `GskRenderNode` stored inside the given `value`.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a `GskRenderNode`
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_value_get_render_node (const GValue *value)
|
||||
{
|
||||
g_return_val_if_fail (G_VALUE_HOLDS (value, GSK_TYPE_RENDER_NODE), NULL);
|
||||
|
||||
return value->data[0].v_pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_value_dup_render_node:
|
||||
* @value: a `GValue` initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
*
|
||||
* Retrieves the `GskRenderNode` stored inside the given `value`, and acquires
|
||||
* a reference to it.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a `GskRenderNode`
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_value_dup_render_node (const GValue *value)
|
||||
{
|
||||
g_return_val_if_fail (G_VALUE_HOLDS (value, GSK_TYPE_RENDER_NODE), NULL);
|
||||
|
||||
if (value->data[0].v_pointer == NULL)
|
||||
return NULL;
|
||||
|
||||
return gsk_render_node_ref (value->data[0].v_pointer);
|
||||
}
|
||||
|
||||
|
||||
@@ -534,6 +534,26 @@ GBytes * gsk_gl_shader_node_get_args (const GskRender
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLShader * gsk_gl_shader_node_get_shader (const GskRenderNode *node) G_GNUC_PURE;
|
||||
|
||||
/**
|
||||
* GSK_VALUE_HOLDS_RENDER_NODE:
|
||||
* @value: a `GValue`
|
||||
*
|
||||
* Evaluates to %TRUE if @value was initialized with %GSK_TYPE_RENDER_NODE.
|
||||
*/
|
||||
#define GSK_VALUE_HOLDS_RENDER_NODE(value) (G_VALUE_HOLDS ((value), GSK_TYPE_RENDER_NODE))
|
||||
|
||||
GDK_AVAILABLE_IN_4_4
|
||||
void gsk_value_set_render_node (GValue *value,
|
||||
GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_4_4
|
||||
void gsk_value_take_render_node (GValue *value,
|
||||
GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_4_4
|
||||
GskRenderNode * gsk_value_get_render_node (const GValue *value);
|
||||
GDK_AVAILABLE_IN_4_4
|
||||
GskRenderNode * gsk_value_dup_render_node (const GValue *value);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_RENDER_NODE_H__ */
|
||||
|
||||
@@ -4377,15 +4377,6 @@ gsk_text_node_draw (GskRenderNode *node,
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
/* We steal one of the bits in PangoGlyphVisAttr */
|
||||
|
||||
G_STATIC_ASSERT (sizeof (PangoGlyphVisAttr) == 4);
|
||||
|
||||
#define COLOR_GLYPH_BIT 2
|
||||
#define GLYPH_IS_COLOR(g) (((*(guint32*)&(g)->attr) & COLOR_GLYPH_BIT) != 0)
|
||||
#define GLYPH_SET_COLOR(g) (*(guint32*)(&(g)->attr) |= COLOR_GLYPH_BIT)
|
||||
#define GLYPH_CLEAR_COLOR(g) (*(guint32*)(&(g)->attr) &= ~COLOR_GLYPH_BIT)
|
||||
|
||||
static void
|
||||
gsk_text_node_diff (GskRenderNode *node1,
|
||||
GskRenderNode *node2,
|
||||
@@ -4411,7 +4402,7 @@ gsk_text_node_diff (GskRenderNode *node1,
|
||||
info1->geometry.x_offset == info2->geometry.x_offset &&
|
||||
info1->geometry.y_offset == info2->geometry.y_offset &&
|
||||
info1->attr.is_cluster_start == info2->attr.is_cluster_start &&
|
||||
GLYPH_IS_COLOR (info1) == GLYPH_IS_COLOR (info2))
|
||||
info1->attr.is_color == info2->attr.is_color)
|
||||
continue;
|
||||
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
@@ -4424,46 +4415,6 @@ gsk_text_node_diff (GskRenderNode *node1,
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
font_has_color_glyphs (PangoFont *font)
|
||||
{
|
||||
hb_face_t *face = hb_font_get_face (pango_font_get_hb_font (font));
|
||||
|
||||
return hb_ot_color_has_layers (face) ||
|
||||
hb_ot_color_has_png (face) ||
|
||||
hb_ot_color_has_svg (face);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
glyph_has_color (PangoFont *font,
|
||||
guint glyph)
|
||||
{
|
||||
hb_font_t *hb_font = pango_font_get_hb_font (font);
|
||||
hb_face_t *face = hb_font_get_face (hb_font);
|
||||
hb_blob_t *blob;
|
||||
|
||||
if (hb_ot_color_glyph_get_layers (face, glyph, 0, NULL, NULL) > 0)
|
||||
return TRUE;
|
||||
|
||||
blob = hb_ot_color_glyph_reference_png (hb_font, glyph);
|
||||
if (blob)
|
||||
{
|
||||
guint length = hb_blob_get_length (blob);
|
||||
hb_blob_destroy (blob);
|
||||
return length > 0;
|
||||
}
|
||||
|
||||
blob = hb_ot_color_glyph_reference_svg (face, glyph);
|
||||
if (blob)
|
||||
{
|
||||
guint length = hb_blob_get_length (blob);
|
||||
hb_blob_destroy (blob);
|
||||
return length > 0;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_text_node_new:
|
||||
* @font: the `PangoFont` containing the glyphs
|
||||
@@ -4488,7 +4439,6 @@ gsk_text_node_new (PangoFont *font,
|
||||
GskRenderNode *node;
|
||||
PangoRectangle ink_rect;
|
||||
PangoGlyphInfo *glyph_infos;
|
||||
gboolean has_color_glyphs;
|
||||
int n;
|
||||
|
||||
pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
|
||||
@@ -4507,7 +4457,6 @@ gsk_text_node_new (PangoFont *font,
|
||||
self->has_color_glyphs = FALSE;
|
||||
|
||||
glyph_infos = g_malloc_n (glyphs->num_glyphs, sizeof (PangoGlyphInfo));
|
||||
has_color_glyphs = font_has_color_glyphs (font);
|
||||
|
||||
n = 0;
|
||||
for (int i = 0; i < glyphs->num_glyphs; i++)
|
||||
@@ -4517,14 +4466,9 @@ gsk_text_node_new (PangoFont *font,
|
||||
continue;
|
||||
|
||||
glyph_infos[n] = glyphs->glyphs[i];
|
||||
GLYPH_CLEAR_COLOR (&glyph_infos[n]);
|
||||
|
||||
if (has_color_glyphs &&
|
||||
glyph_has_color (font, glyph_infos[n].glyph))
|
||||
{
|
||||
self->has_color_glyphs = TRUE;
|
||||
GLYPH_SET_COLOR (&glyph_infos[n]);
|
||||
}
|
||||
if (glyphs->glyphs[i].attr.is_color)
|
||||
self->has_color_glyphs = TRUE;
|
||||
|
||||
n++;
|
||||
}
|
||||
@@ -5721,6 +5665,116 @@ gsk_render_node_init_types_once (void)
|
||||
gsk_render_node_types[GSK_DEBUG_NODE] = node_type;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_render_node_content_serializer_finish (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer serializer)
|
||||
{
|
||||
GOutputStream *stream = G_OUTPUT_STREAM (source);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_output_stream_write_bytes_finish (stream, result, &error))
|
||||
gdk_content_serializer_return_error (serializer, error);
|
||||
else
|
||||
gdk_content_serializer_return_success (serializer);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_render_node_content_serializer (GdkContentSerializer *serializer)
|
||||
{
|
||||
const GValue *value;
|
||||
GskRenderNode *node;
|
||||
GBytes *bytes;
|
||||
|
||||
value = gdk_content_serializer_get_value (serializer);
|
||||
node = gsk_value_get_render_node (value);
|
||||
bytes = gsk_render_node_serialize (node);
|
||||
|
||||
g_output_stream_write_bytes_async (gdk_content_serializer_get_output_stream (serializer),
|
||||
bytes,
|
||||
gdk_content_serializer_get_priority (serializer),
|
||||
gdk_content_serializer_get_cancellable (serializer),
|
||||
gsk_render_node_content_serializer_finish,
|
||||
serializer);
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_render_node_content_deserializer_finish (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer deserializer)
|
||||
{
|
||||
GOutputStream *stream = G_OUTPUT_STREAM (source);
|
||||
GError *error = NULL;
|
||||
gssize written;
|
||||
GValue *value;
|
||||
GskRenderNode *node;
|
||||
GBytes *bytes;
|
||||
|
||||
written = g_output_stream_splice_finish (stream, result, &error);
|
||||
if (written < 0)
|
||||
{
|
||||
gdk_content_deserializer_return_error (deserializer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream));
|
||||
|
||||
/* For now, we ignore any parsing errors. We might want to revisit that if it turns
|
||||
* out copy/paste leads to too many errors */
|
||||
node = gsk_render_node_deserialize (bytes, NULL, NULL);
|
||||
|
||||
value = gdk_content_deserializer_get_value (deserializer);
|
||||
gsk_value_take_render_node (value, node);
|
||||
|
||||
gdk_content_deserializer_return_success (deserializer);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_render_node_content_deserializer (GdkContentDeserializer *deserializer)
|
||||
{
|
||||
GOutputStream *output;
|
||||
|
||||
output = g_memory_output_stream_new_resizable ();
|
||||
|
||||
g_output_stream_splice_async (output,
|
||||
gdk_content_deserializer_get_input_stream (deserializer),
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||
gdk_content_deserializer_get_priority (deserializer),
|
||||
gdk_content_deserializer_get_cancellable (deserializer),
|
||||
gsk_render_node_content_deserializer_finish,
|
||||
deserializer);
|
||||
g_object_unref (output);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_render_node_init_content_serializers (void)
|
||||
{
|
||||
gdk_content_register_serializer (GSK_TYPE_RENDER_NODE,
|
||||
"application/x-gtk-render-node",
|
||||
gsk_render_node_content_serializer,
|
||||
NULL,
|
||||
NULL);
|
||||
gdk_content_register_serializer (GSK_TYPE_RENDER_NODE,
|
||||
"text/plain;charset=utf-8",
|
||||
gsk_render_node_content_serializer,
|
||||
NULL,
|
||||
NULL);
|
||||
/* The serialization format only outputs ASCII, so we can do this */
|
||||
gdk_content_register_serializer (GSK_TYPE_RENDER_NODE,
|
||||
"text/plain",
|
||||
gsk_render_node_content_serializer,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
gdk_content_register_deserializer ("application/x-gtk-render-node",
|
||||
GSK_TYPE_RENDER_NODE,
|
||||
gsk_render_node_content_deserializer,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gsk_render_node_init_types:
|
||||
*
|
||||
@@ -5735,6 +5789,7 @@ gsk_render_node_init_types (void)
|
||||
{
|
||||
gboolean initialized = TRUE;
|
||||
gsk_render_node_init_types_once ();
|
||||
gsk_render_node_init_content_serializers ();
|
||||
g_once_init_leave (®ister_types__volatile, initialized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,3 @@
|
||||
gsk_private_gl_shaders = [
|
||||
'gl/resources/preamble.glsl',
|
||||
'gl/resources/preamble.fs.glsl',
|
||||
'gl/resources/preamble.vs.glsl',
|
||||
'gl/resources/border.glsl',
|
||||
'gl/resources/blit.glsl',
|
||||
'gl/resources/coloring.glsl',
|
||||
'gl/resources/color.glsl',
|
||||
'gl/resources/linear_gradient.glsl',
|
||||
'gl/resources/radial_gradient.glsl',
|
||||
'gl/resources/conic_gradient.glsl',
|
||||
'gl/resources/color_matrix.glsl',
|
||||
'gl/resources/blur.glsl',
|
||||
'gl/resources/inset_shadow.glsl',
|
||||
'gl/resources/outset_shadow.glsl',
|
||||
'gl/resources/unblurred_outset_shadow.glsl',
|
||||
'gl/resources/cross_fade.glsl',
|
||||
'gl/resources/blend.glsl',
|
||||
'gl/resources/repeat.glsl',
|
||||
'gl/resources/custom.glsl',
|
||||
]
|
||||
|
||||
gsk_private_ngl_shaders = [
|
||||
'ngl/resources/preamble.glsl',
|
||||
'ngl/resources/preamble.fs.glsl',
|
||||
@@ -53,7 +31,6 @@ gsk_public_sources = files([
|
||||
'gskrendernodeparser.c',
|
||||
'gskroundedrect.c',
|
||||
'gsktransform.c',
|
||||
'gl/gskglrenderer.c',
|
||||
'ngl/gsknglrenderer.c',
|
||||
])
|
||||
|
||||
@@ -62,16 +39,6 @@ gsk_private_sources = files([
|
||||
'gskdebug.c',
|
||||
'gskprivate.c',
|
||||
'gskprofiler.c',
|
||||
'gl/gskglshaderbuilder.c',
|
||||
'gl/gskglprofiler.c',
|
||||
'gl/gskglglyphcache.c',
|
||||
'gl/gskgldriver.c',
|
||||
'gl/gskglrenderops.c',
|
||||
'gl/gskglshadowcache.c',
|
||||
'gl/gskgltextureatlas.c',
|
||||
'gl/gskgliconcache.c',
|
||||
'gl/opbuffer.c',
|
||||
'gl/stb_rect_pack.c',
|
||||
'ngl/gsknglattachmentstate.c',
|
||||
'ngl/gsknglbuffer.c',
|
||||
'ngl/gsknglcommandqueue.c',
|
||||
@@ -85,6 +52,8 @@ gsk_private_sources = files([
|
||||
'ngl/gskngltexturelibrary.c',
|
||||
'ngl/gskngluniformstate.c',
|
||||
'ngl/gskngltexturepool.c',
|
||||
'ngl/gskglprofiler.c',
|
||||
'ngl/stb_rect_pack.c',
|
||||
'ngl/fp16.c',
|
||||
])
|
||||
|
||||
@@ -106,7 +75,6 @@ gsk_public_headers = files([
|
||||
install_headers(gsk_public_headers, 'gsk.h', subdir: 'gtk-4.0/gsk')
|
||||
|
||||
gsk_public_gl_headers = files([
|
||||
'gl/gskglrenderer.h',
|
||||
'ngl/gsknglrenderer.h',
|
||||
])
|
||||
install_headers(gsk_public_gl_headers, subdir: 'gtk-4.0/gsk/gl')
|
||||
@@ -177,7 +145,6 @@ gsk_resources_xml = configure_file(output: 'gsk.resources.xml',
|
||||
command: [
|
||||
find_program('gen-gsk-gresources-xml.py'),
|
||||
'@OUTPUT@',
|
||||
gsk_private_gl_shaders,
|
||||
gsk_private_ngl_shaders,
|
||||
gsk_private_vulkan_compiled_shaders,
|
||||
gsk_private_vulkan_shaders
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#include "inlinearray.h"
|
||||
|
||||
#include "../gl/gskglprofilerprivate.h"
|
||||
#include "gskglprofilerprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
@@ -2838,9 +2838,6 @@ compute_phase_and_pos (float value, float *pos)
|
||||
}
|
||||
}
|
||||
|
||||
#define COLOR_GLYPH_BIT 2
|
||||
#define GLYPH_IS_COLOR(g) (((*(guint32*)&(g)->attr) & COLOR_GLYPH_BIT) != 0)
|
||||
|
||||
static inline void
|
||||
gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
|
||||
const GskRenderNode *node,
|
||||
@@ -2903,7 +2900,7 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
|
||||
/* If the glyph has color, we don't need to recolor anything.
|
||||
* We tell the shader by setting the color to vec4(-1).
|
||||
*/
|
||||
if (!force_color && GLYPH_IS_COLOR (gi))
|
||||
if (!force_color && gi->attr.is_color)
|
||||
c = nc;
|
||||
else
|
||||
c = cc;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "gskngltypesprivate.h"
|
||||
#include "gskngltexturepoolprivate.h"
|
||||
|
||||
#include "../gl/stb_rect_pack.h"
|
||||
#include "stb_rect_pack.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user