Compare commits

..

436 Commits

Author SHA1 Message Date
Matthias Clasen dfefa884ad Add a GskPoint type and use it for offsets
This has a tremendous ripple effect and is kind of disastrous.
2024-01-21 21:25:24 -05:00
Matthias Clasen 72b8c6cf74 Use graphene's simd4f type for GskScale 2024-01-21 18:42:33 -05:00
Matthias Clasen 501095452a gsk: Introduce GskScale
Use a separate type for a 2d scale that the compiler won't confuse
with graphene_point_t. We can also move some of the generic scale/
transform code form gskgpunodeprocessor.c here.
2024-01-21 15:56:59 -05:00
Matthias Clasen 2ede31b682 Don't use a vec2 for blur direction either
A point_t does just as well.
2024-01-21 08:04:36 -05:00
Matthias Clasen 1355367360 gpu: Don't use a vec2 for scales
This is wasteful (since it gets stored as 4 highly-aligned floats),
and all we ever do is unpack and repack that simf4.
2024-01-21 08:04:36 -05:00
Matthias Clasen 761995ce3c Merge branch 'bilelmoussaoui/file-fixes' into 'main'
gtk: Allow a nullable file in FileChooser.set_current_folder

See merge request GNOME/gtk!6794
2024-01-21 12:01:33 +00:00
Bilal Elmoussaoui d164dd3146 gtk: Allow a nullable file in FileChooser.set_current_folder
To match the annotation
2024-01-21 09:36:30 +01:00
Matthias Clasen 4b9b55ab17 Merge branch 'gl-fix-big-glyphs' into 'main'
gl: Avoid a use-after-free

Closes #6347

See merge request GNOME/gtk!6791
2024-01-20 19:16:56 +00:00
Artur S0 6e9767c7c1 Update Russian translation 2024-01-20 18:59:41 +00:00
Matthias Clasen b2f783b70b gl: Avoid a use-after-free
This only happens with big, non-atlased glyphs, so it is rare, but
it gets triggered by the Masking demo in gtk4-demo.

Fixes: #6347
2024-01-20 13:33:54 -05:00
Matthias Clasen 5a68426c9a Merge branch 'bilelmoussaoui/gi-stuff' into 'main'
gi/docs: Document GtkGraphicsOffloadEnabled

See merge request GNOME/gtk!6790
2024-01-20 17:48:21 +00:00
Bilal Elmoussaoui 32d77fa874 gi/docs: Document GtkGraphicsOffloadEnabled
Mostly to add since annotation
2024-01-20 17:18:26 +00:00
Matthias Clasen 8d00af6351 Merge branch 'matthiasc/for-main' into 'main'
gsk: Inline some more rect functions

See merge request GNOME/gtk!6789
2024-01-20 17:11:48 +00:00
Matthias Clasen a91a0720f5 gl: Consistently use float apis 2024-01-20 11:52:42 -05:00
Matthias Clasen f01208ad94 gpu: Consistently use ceilf
There was a mix of ceil() and ceilf() calls here, but the arguments
are always floats, so use ceilf() throughout.
2024-01-20 11:33:59 -05:00
Matthias Clasen 56b955f819 roundedrect: Use fabsf
The arguments are floats.
2024-01-20 11:33:59 -05:00
Matthias Clasen 0d7761269c gpu: Use gsk_rect_scale 2024-01-20 11:33:59 -05:00
Matthias Clasen 9ebaafa2af gsk: Inline some more rect functions
When we use graphene_rect_scale, the rect is always normalized,
so we can avoid some overhead here.
2024-01-20 11:33:59 -05:00
Matthias Clasen 25ea6beb39 inspector: Fix a typo 2024-01-20 09:38:53 -05:00
Matthias Clasen 905bb2c6fd Merge branch 'matthiasc/for-main' into 'main'
gpu: Cosmetics

See merge request GNOME/gtk!6788
2024-01-20 13:51:43 +00:00
Matthias Clasen b4b7e9b040 gpu: Fix up gc
Make the gc loop free the the right item.
2024-01-20 08:04:43 -05:00
Matthias Clasen c3fcf0f7b0 gpu: Plug a memory leak
This looks like just a leftover line.
2024-01-20 08:02:20 -05:00
Matthias Clasen 60fc48e71f gpu: Cosmetics
s/timestsamp/timestamp/
2024-01-20 08:01:59 -05:00
Danial Behzadi 01d9886eea Update Persian translation 2024-01-20 11:22:43 +00:00
Danial Behzadi a97231c8bf Update Persian translation
(cherry picked from commit 58425405d2)
2024-01-20 11:13:44 +00:00
Matthias Clasen 8ac8a027b2 Merge branch 'wip/no-seat' into 'main'
Fix possible crashers if no seats are available

See merge request GNOME/gtk!6787
2024-01-20 03:30:12 +00:00
Carlos Garnacho 070f3a61ac gdk/wayland: Bail out on titlebar gestures with no seat
This API might be called programmatically at a time that there's no
seats, handle this situation by returning FALSE in the GDK API.

Related: https://gitlab.gnome.org/GNOME/gtk/-/issues/6335
2024-01-20 01:27:27 +01:00
Carlos Garnacho 022347fa85 gdk/wayland: Avoid activation paths with no seats
When a toplevel is focused programmatically and there is no
underlying seat, we cannot attempt to focus it with no
focus to be obtained, nor serials serials to use.

Related: https://gitlab.gnome.org/GNOME/gtk/-/issues/6335
2024-01-20 01:27:27 +01:00
Matthias Clasen ebb6076aca Merge branch 'matthiasc/for-main' into 'main'
inspector: Update logging tab

See merge request GNOME/gtk!6783
2024-01-19 16:46:06 +00:00
Matthias Clasen 7b66bc45aa Cosmetics
Add some vim modelines.
2024-01-19 09:26:32 -05:00
Matthias Clasen 698aa7c0f3 inspector: Update logging tab
The verbose flag was missing in the gsk section.
2024-01-19 09:26:32 -05:00
Matthias Clasen 70699efc71 Merge branch 'matthiasc/for-main' into 'main'
Automate profile setting

See merge request GNOME/gtk!6781
2024-01-19 03:49:58 +00:00
Matthias Clasen cebc95f253 Automate profile setting
We can derive whether we are build a developement snapshot or
a stable version from the minor version number. So do that.
This way, we'll get the devel profile selected in the nightly
SDK, which will make the commit sha appear in the inspector,
which is useful to determine what nightly users are testing.
2024-01-18 21:26:39 -05:00
Matthias Clasen f9c6bd125b Merge branch 'inspector-git-sha' into 'main'
build: Move demo header generation

See merge request GNOME/gtk!6780
2024-01-19 01:41:40 +00:00
Matthias Clasen 4733ca193b inspector: Show git sha for the build 2024-01-18 20:22:00 -05:00
Matthias Clasen c7b345f73e build: Move and rename demo_conf.h header
We want to use the same header in the inspector, so move it to
the toplevel. And since it is no longer for demos only, rename
it to profile_conf.h, and also rename the build option back
to profile.
2024-01-18 20:20:58 -05:00
Matthias Clasen 1fbc61f2cb Merge branch 'static_text_widgets_are_not_special' into 'main'
a11y: Remove special handling of accessible names for static text widgets

See merge request GNOME/gtk!6776
2024-01-18 16:01:29 +00:00
Matthias Clasen 565694ede5 Merge branch 'wip/chergert/fix-expression-weak-ref-uaf' into 'main'
expression: use indirection to safely finalize object expression

See merge request GNOME/gtk!6778
2024-01-18 16:00:55 +00:00
Christian Hergert 0df03b054d expression: guard against UAF with indirection
When using g_object_weak_ref(), it is important that you can discover
weather or not it is safe to call g_object_weak_unref(). That is
problematic if you use a naked pointer to structure. Additionally,
if a GWeakRef is used, and things are not cleaned up carefully,
GObject itself will try to write to it. So ensuring that the GWeakRef
is cleared safely before the owning struct is finalized is paramount.
That is difficult if you are unsure wheather or not your weak_ref
callback has been called.

This introduces WeakRefGuard which is an indirection pointer that is
cleared on the first unref. There are only ever two references. When
the owning struct is finalized or the weak ref callback is called, an
unref will occur and the guard will clear the data pointer.
2024-01-17 19:25:31 -08:00
Christian Hergert 73d01d3130 expression: release target if evaulation fails
Related #6341
2024-01-17 19:25:00 -08:00
Matthias Clasen 80f3357117 Merge branch 'dboles/Notebook-DropTarget-GTK4' into 'main'
Notebook: Update doc on how to accept dropped tabs

See merge request GNOME/gtk!6450
2024-01-18 02:28:18 +00:00
Lukáš Tyrychtr d5b34aecdd a11y: Remove special handling of accessible names for static text widgets
By doing this, we gain the capability to send notifications when their
accessible names change. Also, it simplifies the accessible name
generation logic.
2024-01-17 12:49:38 +01:00
Matthias Clasen d16d2135e6 Merge branch 'demos-fix-commit-sha' into 'main'
Flatpak demos fix missing commit sha

See merge request GNOME/gtk!6774
2024-01-17 02:51:35 +00:00
Matthias Clasen 53b52abd30 Merge branch 'matthiasc/for-main' into 'main'
Shrink the repeat-repeats tests

See merge request GNOME/gtk!6775
2024-01-17 02:40:22 +00:00
Matthias Clasen e55e9e3b36 Shrink the repeat-repeats tests
This was triggering timeouts in ci.
2024-01-16 20:58:02 -05:00
Matthias Clasen 9f9cea219f Merge branch 'dnd-cursor-names' into 'main'
dnd: Use standard cursor names

Closes #6337

See merge request GNOME/gtk!6770
2024-01-17 01:33:41 +00:00
Matthias Clasen dbee1a8160 dnd: Use standard cursor names
The css spec doesn't cover the fringe 'ask' feature of DND, but
apart from that, we should use the names in the spec.

Fixes: #6337
2024-01-16 19:45:53 -05:00
Matthias Clasen 133cd87bdf Merge branch 'ebassi/doc-fixes' into 'main'
docs: Clean up the note on nVidia on Windows

See merge request GNOME/gtk!6773
2024-01-17 00:20:35 +00:00
Benjamin Otte 9f8e84cb60 Merge branch 'wip/otte/for-main' into 'main'
gl: BGRA formats need a different internal format

Closes #6333

See merge request GNOME/gtk!6772
2024-01-16 21:21:17 +00:00
Emmanuele Bassi b8057b088e docs: Clean up the note on nVidia on Windows
Turn the URL to the nVidia forums into an actual link, and put the whole
paragraph into an aside.
2024-01-16 20:14:21 +00:00
Jan Willem Eriks cf8cca8724 Flatpak builds pass the commit sha as environment variable
This variable is refrenced at build-aux/meson/gen-demo-header.py but never passed to the flatpak builder.
This fixes that the flatpak build don't have their commit in the about window.
2024-01-16 20:45:01 +01:00
Benjamin Otte d97767014c gl: BGRA formats need a different internal format
In GLES, BGRA is still done by GL_EXT_texture_format_BGRA8888 which is
an extension that is older than GLES 2.0.

And back then, internal formats had to be specified unsized. And when
that was changed with GLES3, nobody updated the extension.
However, on OpenGL, this extension doesn't exist, and internal formats
need to be sized.

So let's use different internal formats depending on GL version.

Fixes #6333
2024-01-16 20:35:20 +01:00
Benjamin Otte 2f974a1f5a gl: Split internal format for GdkMemoryFormat into GL/GLES
This commit just duplicates the struct.

It's separate because it's just a bunch of boilerplate.
2024-01-16 20:35:20 +01:00
Benjamin Otte 4e2c7d5eb0 gl: Require GL/GLES flag when looking up memory formats
This code just adds the argument to the function and fixes all callers.

It's separate because it's just a bunch of boilerplate.
2024-01-16 20:35:20 +01:00
Emmanuele Bassi a5d1cb93ef Merge branch 'ebassi/flatpak-no-vulkan' into 'main'
ci: Really disable Vulkan for Flatpak bundles

See merge request GNOME/gtk!6769
2024-01-16 16:31:38 +00:00
Emmanuele Bassi 401b902cbf ci: Really disable Vulkan for Flatpak bundles
We don't use the config options from the manifest to build GTK.
2024-01-16 15:56:58 +00:00
Matthias Clasen 9f2778b97c Merge branch 'fallback-6298' into 'main'
popovermenu: Add default sliding flag

See merge request GNOME/gtk!6746
2024-01-16 13:41:58 +00:00
Matthias Clasen ed4eeb8adb Merge branch 'wip/chergert/fix-object-expression-notify' into 'main'
expression: combine GWeakNotify and GWeakRef for object expression

Closes #5542 and #6220

See merge request GNOME/gtk!6763
2024-01-16 13:34:08 +00:00
Matthias Clasen fb36d30685 Merge branch 'custom-font-url' into 'main'
gsk: Keep a fontmap reference in text nodes

See merge request GNOME/gtk!6759
2024-01-16 13:04:13 +00:00
Matthias Clasen 385b9a7241 gsk: Serialize custom fonts with url
If we see custom fonts when serializeing text nodes, write data
url that contains the font file, the first time we see it.

This does not add blobs standard fonts, like Cantarell or Monospace.

Update all affected nodeparser tests.
2024-01-16 07:04:45 -05:00
Matthias Clasen c2abf30c46 Revert "node-editor: Make test fonts available"
This reverts commit 4882514234.

We can now put custom fonts into node files, so there is
no more need for this.
2024-01-16 07:04:45 -05:00
Matthias Clasen 50a47f55d9 Revert "rendernode-tool: Make test fonts available"
This reverts commit cdbfb35067.

We can now put custom fonts into node files, so there is
no more need for this.
2024-01-16 07:04:45 -05:00
Matthias Clasen cd7fe772a7 tests: Drop fontconfig setup for custom fonts
We are putting custom fonts into node files now, so there is
no more need for this.
2024-01-16 07:04:45 -05:00
Matthias Clasen 317bba756e Port existing gsk tests to embedded custom fonts
Make all the tests using custom fonts use the new url syntax.
2024-01-16 07:04:45 -05:00
Matthias Clasen 2212049e8f Merge branch 'wip/otte/for-main' into 'main'
Fix infinite loop in zenity

See merge request GNOME/gtk!6767
2024-01-16 11:36:34 +00:00
Matthias Clasen 0f26a006ee Merge branch 'revert-364eec24' into 'main'
Revert "Merge branch 'demos-enable-vulkan' into 'main'"

See merge request GNOME/gtk!6766
2024-01-16 10:15:52 +00:00
Benjamin Otte 3c451b3ec7 columnview: Make sure cells disconnect from their column
When a cell is removed from the columnview, we need to make sure it s
not just removed from the cell (via unset_parent()) but also from the
column.

Previously, we were doing this from dispose(), but this is broken
because dispose() only runs when the refcount goes to zero. But if some
code still has a reference for whatever reason, this won't happen.

So now we do it explicitly together with unset_parent().
2024-01-16 07:20:23 +01:00
Benjamin Otte 323adf9aa8 Revert "gtkcolumnviewcellwidget: move cleanup from dispose to unroot"
This reverts commit ff262c081e.

This is a wrong fix because it triggers when the columnview gets
unrooted but the cell keeps existing. Later, when the columnview gets
re-rooted, the cell is still there but thinks it has no column.

And that's bad.
2024-01-16 06:59:15 +01:00
Benjamin Otte 70f0cde730 tests: Fix gio API usage
Related: glib!3261
2024-01-16 06:22:43 +01:00
Christian Hergert 14e78663ee expression: combine GWeakNotify and GWeakRef for bind expression
This does the same thing to GtkExpressionBind that was done to
GtkExpressionObject. Use a GWeakRef to ensure we're working with a valid
object instead of relying on when our weak pointer and/or notify callback.
2024-01-15 20:59:27 -08:00
Christian Hergert d8279209a2 expression: retrieve next pointer before notifying closure
Any time we call back into user code we risk re-entrancy issues. Get the
next pointer for the list before calling back into notifiers.
2024-01-15 20:41:45 -08:00
Christian Hergert a0527ff0bd expression: combine GWeakNotify and GWeakRef for object expression
When using a GtkObjectExpression multiple times in the same GtkBuilder
template, we can run into a situation where we are in disposal but have
not yet had our callback notified.

This attempts to improve on that situation by using something I've done in
other projects for years. Combine both GWeakNotify and GWeakRef. Only use
the GWeakRef to get an object instance rather than relying on the
GWeakNotify alone.

By doing this, we can avoid trying to remove an object weak reference for
an object that is in disposal and causing runtime warnings.

Fixes #5542
Fixes #6220
2024-01-15 19:29:29 -08:00
Matthias Clasen 771ea81715 Merge branch 'fix-doc-link' into 'main'
docs: Update link to GitLab documentation

See merge request GNOME/gtk!6764
2024-01-16 01:49:34 +00:00
Emmanuele Bassi f22a3f9ec6 Revert "Merge branch 'demos-enable-vulkan' into 'main'"
This reverts merge request !6724
2024-01-16 00:45:00 +00:00
Matthias Clasen 246876a404 Add a test for font-related node parser errors
This tests the behaviors implemented in the previous commit.
2024-01-15 18:58:17 -05:00
Matthias Clasen 27a086b5f0 Add a test for new text node syntax
Add a test that checks that font: properties can be parsed without
error, both with and without the optional url.
2024-01-15 18:58:17 -05:00
Matthias Clasen 8158945de9 gsk: Allow custom fonts in node files
This will let us store complete test fonts inside node files,
as data: urls. You can also use a file: url to refer to a local
file.

The syntax is as follows:

text {
  font: "FONT DESCRIPTION" url("data:font/ttf;base64,FONT DATA");
}

with the url being optional.
2024-01-15 18:58:17 -05:00
Matthias Clasen 1c85141612 gsk: Keep a fontmap reference in text nodes
A PangoFont keeps a weak reference to its fontmap. In addition,
keep a strong reference in GskTextNode, so we can be sure that
custom font maps won't go away before the node is finalized.
2024-01-15 18:25:15 -05:00
Matthias Clasen 690381672b tests: Fix up test font naming
The entry for the family name in the name table has nameID=1, not
nameID=0, so we were relying on the filename to be just right.
Oops.
2024-01-15 18:25:15 -05:00
Matthias Clasen 3d7ff44dc5 Cosmetics 2024-01-15 18:25:15 -05:00
Florian Müllner a518c59098 docs: Update link to GitLab documentation
The original link no longer works, so update the reference to
point to the currently correct location.
2024-01-15 21:41:15 +01:00
Benjamin Otte 1dd5e92499 Merge branch 'unroot' into 'main'
gtkcolumnviewcellwidget: move cleanup from dispose to unroot

Closes #6200

See merge request GNOME/gtk!6758
2024-01-15 14:13:09 +00:00
Matthias Clasen fbd3c5ebd0 Merge branch 'matthiasc/for-main' into 'main'
Update the node format docs

See merge request GNOME/gtk!6761
2024-01-15 13:00:51 +00:00
Matthias Clasen 48dc7df5b7 Update the node format docs
Mention the new syntax for naming and reusing textures.
2024-01-15 07:46:18 -05:00
Emmanuele Bassi 0c4c90d606 Merge branch 'stackpage-auto-cleanup' into 'main'
stack: Add automatic cleanup for GtkStackPage

See merge request GNOME/gtk!6760
2024-01-15 11:33:07 +00:00
Guido Günther da954d20f9 stack: Add automatic cleanup for GtkStackPage
Useful when iterating over the pages via g_list_model_get_item ().
2024-01-15 11:48:21 +01:00
tszymanski ff262c081e gtkcolumnviewcellwidget: move cleanup from dispose to unroot
No longer gets stuck in an infinite loop.

Fixes #6200
2024-01-14 15:38:21 -08:00
Matthias Clasen c6967234de Merge branch 'matthiasc/for-main' into 'main'
gsk: Inline some more rect functions

See merge request GNOME/gtk!6755
2024-01-14 22:37:02 +00:00
Matthias Clasen cdbfb35067 rendernode-tool: Make test fonts available
We are likely to use the tool with node files from out testsuite,
which may now refer to custom test fonts, so make them available
in the same way as in the node editor.

If in doubt, you can set GTK_SOURCE_DIR to make the tool find the
fonts.
2024-01-14 16:58:05 -05:00
Matthias Clasen 53e17ab14e Merge branch 'node-editor-autosave' into 'main'
node-editor: Add an auto-reload property

See merge request GNOME/gtk!6757
2024-01-14 21:51:19 +00:00
Matthias Clasen 550e98090a node-editor: Redo crash recovery UX
Switch from a dialog to an in-app notification, and make use
of the new auto-reload property for it.
2024-01-14 14:40:51 -05:00
Matthias Clasen 2771befdd9 node-editor: Add a menu items for auto reloading
Expose the auto-reload property as a toggle action, and add
a menu item for it.
2024-01-14 14:40:51 -05:00
Matthias Clasen 911730493d node-editor: Add an auto-reload property
This is not exposed anywhere yet.
2024-01-14 14:40:51 -05:00
Maximiliano Sandoval d05f47a695 popovermenu: Add default sliding flag
Also add missing annotation.

Continuation of https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6298
2024-01-14 16:32:20 +01:00
Quentin PAGÈS 11dc15207e Update Occitan translation 2024-01-14 11:32:22 +00:00
Matthias Clasen 4ea748a676 Merge branch 'matthiasc/for-main' into 'main'
Add another font rendering test

See merge request GNOME/gtk!6752
2024-01-14 01:16:57 +00:00
Matthias Clasen b78d2a7f75 Add another font rendering test
This one tests that we handle glyphs with lsb correctly wrt. to
positioning.
2024-01-13 17:47:27 -05:00
Benjamin Otte 1fd9e1e916 Merge branch 'wip/otte/benchmark' into 'main'
Add gtk-rendernode-tool benchmark

See merge request GNOME/gtk!6751
2024-01-13 17:20:45 +00:00
Benjamin Otte 24ceb47cbc tools: Add the new benchmark command to the docs 2024-01-13 17:22:57 +01:00
Benjamin Otte 8872e1cbb0 tools: Add gtk-rendernode-tool benchmark
A simple tool that runs gsk_renderer_render_texture() a few times with
every renderer and prints the results.
2024-01-13 17:22:57 +01:00
Benjamin Otte c1e2ffac83 tools: Split out a function
There's a function now that creates a renderer by name - and allows NULL
for the default renderer
2024-01-13 17:22:57 +01:00
Piotr Drąg 17df646663 Update POTFILES.in 2024-01-13 13:29:25 +01:00
Ngọc Quân Trần 6f8fae590f Update Vietnamese translation
(cherry picked from commit cbc44e202a)
2024-01-13 07:19:30 +00:00
Matthias Clasen 4146db0003 Merge branch 'matthiasc/for-main' into 'main'
glarea: Add some details to the docs

Closes #6317

See merge request GNOME/gtk!6749
2024-01-13 03:17:05 +00:00
Matthias Clasen 9c228cc634 glarea: Add some details to the docs
Mention that the rendering is integrated into the GTK scene graph
as a texture and that the initial framebuffer contents are
transparent.

Fixes: #6317
2024-01-12 21:58:44 -05:00
Matthias Clasen df2cdb6913 Merge branch 'node-editor-autosave' into 'main'
node-editor: Add autosave

See merge request GNOME/gtk!6748
2024-01-13 02:30:06 +00:00
Matthias Clasen 22a5447039 docs: Document new node-editor options 2024-01-12 21:13:51 -05:00
Matthias Clasen a2475051fa Merge branch 'use-modifier-none' into 'main'
Use GDK_NO_MODIFIER_MASK in default prop values

See merge request GNOME/gtk!6747
2024-01-13 01:55:12 +00:00
Matthias Clasen d41fb7c5a6 node-editor: Add commandline options
Add --reset to remove the autosave file. While we're at it, also
add --version.
2024-01-12 20:50:34 -05:00
Matthias Clasen 3b28c46595 node-editor: Add autosave
Save the buffer contents to a file in ~/.cache/gtk4-node-editor
and restore it on startup.
2024-01-12 20:50:34 -05:00
Maximiliano Sandoval f57300b924 Use GDK_NO_MODIFIER_MASK in default prop values 2024-01-13 01:30:02 +01:00
Matthias Clasen c146f225ff Merge branch 'big-glyph-test' into 'main'
gsk: Fix big glyphs getting clipped

See merge request GNOME/gtk!6744
2024-01-12 21:31:35 +00:00
Matthias Clasen 9f4f65be4a gsk: Add test for clipped big glyphs
Tests the fix in the previous commit 93715b963e.

Sadly, the flipped variant of this test fails with the cairo
renderer, so it is marked as -nocairo. All the other renderers
pass it.
2024-01-12 16:02:05 -05:00
Matthias Clasen 93715b963e gsk: Fix big glyphs getting clipped
We were inadvertedly shifting the rendering by one pixel.
2024-01-12 15:55:27 -05:00
Benjamin Otte c1407f2ca6 Merge branch 'wip/otte/for-main' into 'main'
gpu: Remove unnecessary optimization

Closes #6322

See merge request GNOME/gtk!6743
2024-01-12 19:23:46 +00:00
Benjamin Otte 3b299f574d testsuite: Add a test for contained clips
Related: #6322
2024-01-12 20:06:04 +01:00
Benjamin Otte a51c6aed47 gpu: Introduce "contained" clip
This clip is different from "none" in that the bounds rect cannot be
ignored and that potential drawing outside the clip must be avoided.

In particular it means that clip nodes cannot be discarded if they
encompass the full clip region.

Fixes #6322
2024-01-12 20:06:04 +01:00
Benjamin Otte b552cf74dd gpu: Remove unnecessary optimization
Every branch in the switch is so optimized that it does this check
early anyway, so there's no need to have it as an extra step.
2024-01-12 20:06:04 +01:00
Matthias Clasen 0be0265751 Merge branch 'ebassi/doc-since-fix' into 'main'
docs: Add missing Since to gtk-show-status-shapes setting

See merge request GNOME/gtk!6741
2024-01-12 15:04:05 +00:00
Matthias Clasen 207dd6fe0d Merge branch 'matthiasc/for-main' into 'main'
gsk: Fix up test names to include 'compare'

See merge request GNOME/gtk!6739
2024-01-12 14:38:46 +00:00
Emmanuele Bassi a87ff8d556 docs: Add missing Since to gtk-show-status-shapes setting 2024-01-12 12:54:54 +00:00
Matthias Clasen 153cb8316e gsk: Fix up test names to include 'compare' 2024-01-11 23:19:29 -05:00
Matthias Clasen 7ad7c0d8c1 Merge branch 'switch-shapes' into 'main'
switch: Follow "switch-shapes" setting

Closes #5354

See merge request GNOME/gtk!6731
2024-01-11 19:19:58 +00:00
Benjamin Otte 61595af586 Merge branch 'ngl-backbuffer-leak' into 'main'
ngl: Don't leak the backbuffer

See merge request GNOME/gtk!6736
2024-01-11 11:16:31 +00:00
Matthias Clasen d240c35850 ngl: Don't leak the backbuffer
Clear it in unrealize, just like the vulkan renderer does with
its targets.
2024-01-10 23:08:01 -05:00
Matthias Clasen d276eb9e9a Merge branch 'test-font-tweaks' into 'main'
tests: Change the way custom fonts are handled

See merge request GNOME/gtk!6734
2024-01-11 03:33:15 +00:00
Matthias Clasen afe4cbf26d tests: Change the way custom fonts are handled
Instead of setting FONTCONFIG_FILE to a custom font configuration,
pass the directory containing the fonts as TEST_FONTS and use
FcConfigAppFontAddDir to add them to the default font configuration.
2024-01-10 22:18:37 -05:00
Matthias Clasen 76e5ef6937 Merge branch 'node-editor-tweaks' into 'main'
node-editor: Make test fonts available

See merge request GNOME/gtk!6733
2024-01-11 02:55:50 +00:00
Matthias Clasen 0ed43f66a9 docs: Beef up the node-editor man page
Mention the GTK_SOURCE_DIR environment variable in the man page.
2024-01-10 21:10:36 -05:00
Matthias Clasen 4882514234 node-editor: Make test fonts available
Add the directory containing test fonts for gsk tests to the
font configuration, so that node files from the testsuite using
these fonts just work.
2024-01-10 21:10:36 -05:00
Matthias Clasen a15e87d2a6 Merge branch 'mixed-color-test' into 'main'
gsk: Add another font text

See merge request GNOME/gtk!6732
2024-01-11 01:50:09 +00:00
Matthias Clasen cc92b9b19f gsk: Add another font text
This is similar to text-mixed-color, but it uses the COLRv1 table,
to test our support for this font technology.
2024-01-10 19:44:55 -05:00
Florian Müllner bf0120f73d switch: Follow "show-status-shapes" setting
Whether or not switches include shapes to indicate their ON/OFF
state is currently controlled by the stylesheet (in particular
the HighContrast style).

However there are use cases for both using the HighContrast style
without shapes, and for using shapes with the regular stylesheet,
so follow the newly added "show-status-shapes" setting instead.

https://gitlab.gnome.org/GNOME/gtk/-/issues/5354
2024-01-11 01:33:16 +01:00
Matthias Clasen 7f06eed8da Merge branch 'hc-cleanup' into 'main'
wayland/display: Don't notify "icon-theme" on high-contrast changes

See merge request GNOME/gtk!6730
2024-01-10 21:38:55 +00:00
Matthias Clasen dc30044829 Merge branch 'gpu-fix-mixed-color-text' into 'main'
gpu: Fix handling of mixed-color text runs

See merge request GNOME/gtk!6725
2024-01-10 18:11:23 +00:00
Matthias Clasen 781fe2d7fa gsk: Add a compare test for mixed color runs
This tests the fixes in aa82190da659b5 and dcaa2c4ccb182c74cb40.

The test uses a custom font named 'text-mixed-color' which contains
six glyphs that are just boxes. Glyphs 1, 2, 3 are just plain glyphs,
and glyphs 4, 5, 6 are color glyphs in red, green and blue.

The glyphs are mapped to the characters A, B, C, D, E, F.

The test is currently disabled for cairo, since it has some issues
with transformed color glyphs.
2024-01-10 12:49:08 -05:00
Florian Müllner b8a61f7899 wayland/display: Don't notify "icon-theme" on high-contrast changes
Since commit c3706ea9ec, the "high-contrast" setting no longer
forces the "HighContrast" icon theme.
2024-01-10 15:46:46 +01:00
Matthias Clasen a44ca6756a gpu: Use the right format for atlases
The glyph atlas format needs to match the cairo memory format.
NGL was getting this wrong, causing color glyphs to have their
red and blue swapped.
2024-01-10 08:00:15 -05:00
Matthias Clasen 490a9f193d gpu: Fix handling of mixed color text runs
We need to decide per-glyph whether to use coloring or texture ops.
2024-01-10 08:00:15 -05:00
Matthias Clasen 754d364efd gsk: Allow custom fonts in tests
The commit adds a custom fontconfig configuration in
testsuite/gsk/fonts/fonts.conf and sets the FONTCONFIG_FILE
environment variable for the gsk compare tests to point at it.

To use a custom font in tests, just drop it into the
testsuite/gsk/fonts/ directory.

The font configuration includes the system configuration,
so existing tests should not be affected.
2024-01-10 07:58:19 -05:00
Benjamin Otte 4939f0bb75 Merge branch 'wip/otte/for-main' into 'main'
contour: Fix stroke bounds for rect contour

See merge request GNOME/gtk!6728
2024-01-10 01:05:22 +00:00
Carlos Garnacho 7537d80047 Merge branch 'wip/show-tablet-cursor' into 'main'
gdk/wayland: reset cursor_is_default on proximity out

Closes #6312

See merge request GNOME/gtk!6720
2024-01-10 00:55:32 +00:00
Benjamin Otte c5bdf0a995 testsuite: Add tests for pixel grid accuracy
See previous commit for details.
2024-01-10 01:33:49 +01:00
Peter Hutterer 04870fc1a1 gdk/wayland: Reset cursor_is_default on proximity out
For tablet tools if we have NULL cursor, we use the default cursor
instead. This provides us with a tablet cursor when an application never
sets the cursor.

However, on proximity out when we clear said cursor we also
need to toggle off cursor_is_default, otherwise on the next proximity in
we assume we already have a cursor and never update it again.

This leads to an invisible cursor over GTK application when the tablet
tool is brought into proximity over the widget (but not when moving into
the widget from the outside).

Closes: #6312
2024-01-10 00:25:01 +00:00
Matthias Clasen 43e5bc795a Merge branch 'log_whitespace' into 'main'
Add missing space to warning

See merge request GNOME/gtk!6729
2024-01-10 00:06:05 +00:00
Spencer Burris f3ec58d290 Add missing space to warning 2024-01-09 16:57:26 -07:00
Benjamin Otte 5b3d14e15b gpu: respect pixel grid for Cairo rendering
Make sure fallbacks and fill/stroke masks use image surfaces with the
same pixel grid as the target if possible.

Fixes blurriness with some path renderings.
2024-01-10 00:13:52 +01:00
Benjamin Otte 131ab11f5c testsuite: Check that pixel grid math respects offsets 2024-01-10 00:13:52 +01:00
Benjamin Otte a2eb467663 gpu: Change rect_round_pixels() to take an offset
We need to respect the offset when converting to the pixel grid, so pass
the current offset into the function.

Also move the rounded out of gsk_gpu_get_node_as_image() and into the 2
callers, because the offset is not passed into the function and I see no
reason to change that.
2024-01-10 00:13:52 +01:00
Benjamin Otte 06f85ee566 contour: Fix stroke bounds for rect contour
There's no tests for stroke bounds, oh no!
2024-01-09 23:27:55 +01:00
Benjamin Otte aab40ad6a2 gpu: Fix text coordinates in the ubershader 2024-01-09 23:27:55 +01:00
Matthias Clasen 364eec24b1 Merge branch 'demos-enable-vulkan' into 'main'
Enable vulkan on the flatpak demos.

See merge request GNOME/gtk!6724
2024-01-08 20:53:25 +00:00
Jan Willem Eriks f1fe21e009 Enable vulkan on the flatpak demos.
Since ed12c0cd5a enabled vulkan by default also build the demos with Vulkan enabled.
2024-01-08 19:01:02 +01:00
Artur S0 126cbccddf Update Russian translation 2024-01-08 13:43:52 +00:00
Benjamin Otte 26cf74de5c Merge branch 'wip/otte/for-main' into 'main'
Wip/otte/for main

See merge request GNOME/gtk!6721
2024-01-08 11:48:43 +00:00
Benjamin Otte 2ecb8c08dc testsuite: Add a test for borders inside opacity
Tests the latest fix.
2024-01-08 11:17:09 +01:00
Matthias Clasen ce7cc942e4 gpu: Use opacity for border colors
We were computing the right colors, but forgot to use them.
2024-01-08 11:17:09 +01:00
Benjamin Otte a0e9d93b4c testsuite: Add a test for previous fix
Fill a rectangle with fractional coordinates << 1.0 but scale it up so
that it ends up being nice integers.

Makes sure that nobody does any bad rounding here.
2024-01-08 11:17:09 +01:00
Benjamin Otte 017aea1952 gl: Fix rendering of nodes with fractional offsets
We can't just be floored by fractions, especially not when we have a
massive scale factor.

Fixes rendering of paintable gtk-demo.
2024-01-08 09:28:26 +01:00
Benjamin Otte 63d7b22924 demo: Port the paintable demo to paths 2024-01-08 09:28:26 +01:00
Benjamin Otte 3f3629154c gpu: clip to redraw region rects instead of extents
Instead of using the bounds of the clip region, emit individual
renderpasses for each rectangle of the clip region.

The benefit of this depends on how many pixels the clip region covers,
but for widget factory it reduces the required rendering by a huge
amount.

This is now the best clipping renderer - Cairo doesn't clip at all and
GL clips based on the extents.
2024-01-08 09:28:26 +01:00
Benjamin Otte c3cfabfa96 gpu: Respect the initial scissor clip in the clip region
Previously, we would set a scissor rect when doing a partial redraw, but
we would not clip the nodes based on that rectangle.

Do that now.

This massively reduces the amount of ops we emit for small redraws.
2024-01-08 09:28:26 +01:00
Ekaterine Papava cd9525afc9 Update Georgian translation 2024-01-08 04:13:07 +00:00
Matthias Clasen 4d76beb59c Merge branch 'matthiasc/for-main' into 'main'
Matthiasc/for main

See merge request GNOME/gtk!6717
2024-01-08 02:46:11 +00:00
Matthias Clasen 59578c6d18 Fix typos throughout
These were pointed out by codespell.
2024-01-07 20:44:05 -05:00
Matthias Clasen 7bf8669d97 gdk: Cosmetics 2024-01-07 19:31:01 -05:00
Matthias Clasen e1156ea636 gtk: Cosmetics 2024-01-07 18:32:05 -05:00
Matthias Clasen 82f601253e gtk: Cosmetics 2024-01-07 18:31:09 -05:00
Matthias Clasen 96e710a76f Post-release version bump 2024-01-07 11:18:47 -05:00
Matthias Clasen a45b66e1ca Merge branch 'matthiasc/for-main' into 'main'
ci: Fix test names

See merge request GNOME/gtk!6716
2024-01-07 14:55:46 +00:00
Matthias Clasen 325b0010e4 NEWS: Updates 2024-01-07 09:40:43 -05:00
Matthias Clasen bf14a5f70b ci: Fix test names
Don't call the offload test 'parser ...'.
2024-01-07 09:40:43 -05:00
Matthias Clasen 532e887c88 Merge branch 'wip/otte/vulkan-api' into 'main'
Vulkan and new renderer related API changes

See merge request GNOME/gtk!6715
2024-01-07 14:40:05 +00:00
Benjamin Otte 7830535c04 vulkan: Guard dmabuf code with HAVE_DMABUF 2024-01-07 15:07:15 +01:00
Benjamin Otte 440c207146 build: Enable Vulkan on msys CI 2024-01-07 14:47:22 +01:00
Benjamin Otte ed12c0cd5a build: Enable Vulkan by default
It's still possible to disable via -Dvulkan=disabled

We force-disable it on Mac OS.

I don't know how to best handle it on Windows. Technically we don't need
it, because the Vulkan stuff we want is about dmabufs, but I have no
idea how to convince the build system to toggle the default to
"disabled" on Windows, so it has to stay enabled for now.
2024-01-07 14:47:22 +01:00
Benjamin Otte 543c7ae52a vulkan: Disable gdk_surface_create_vulkan_context()
... and deprecate it.

It will now always return NULL and error out.

We do not want to expose any Vulkan internals in the public API.
2024-01-07 14:47:22 +01:00
Benjamin Otte 3ac50b81f2 vulkan: Make gdk_display_create_vulkan_context() take a surface
This is so we can deprecate gdk_surface_create_vulkan_context() which is
public API in the next commit.
2024-01-07 14:47:22 +01:00
Benjamin Otte 6bac377fa5 gdk: Don't include vulkan.h in public API anymore 2024-01-07 14:47:22 +01:00
Benjamin Otte 3bb1c2298f gsk: Emit deprecation warning for #include <gsk/gl/gskglrenderer.h>
This is a bit hacky, but it seems to work.

Note: It doesn't work inside GTK because GTK_COMPILATION during the
whole build.
2024-01-07 14:47:22 +01:00
Benjamin Otte 637f6cc81b gtk: Don't #include <gsk/gl/gskglrenderer.h> 2024-01-07 14:47:22 +01:00
Benjamin Otte 0ba8903fa5 testsuite: Don't #include <gsk/gl/gskglrenderer.h> 2024-01-07 14:47:22 +01:00
Benjamin Otte ee14b96c28 node-editor: Don't #include <gsk/gl/gskglrenderer.h> 2024-01-07 14:47:22 +01:00
Benjamin Otte cf86a01b65 gsk: Include GL renderer in gsk.h
Same as the Vulkan renderer
2024-01-07 14:47:22 +01:00
Benjamin Otte f57e211ba9 node-editor: Use gsk_renderer_realize_for_display()
... in all the places where we used realize (NULL) before.
2024-01-07 14:47:22 +01:00
Benjamin Otte e2c8b7fa6c testsuite: Use gsk_renderer_realize_for_display()
... in all the places where we used realize (NULL) before.
2024-01-07 14:47:22 +01:00
Benjamin Otte b486588883 dmabuf: Use gsk_renderer_realize_for_display()
We want to use the correct display when realizing our dmabuf
downloaders.

It's a good thing that the inspector doesn't use dmabufs, isn't it?
2024-01-07 14:47:22 +01:00
Benjamin Otte d0bf33339e API: Add gsk_renderer_realize_for_display()
This makes realizing a renderer without a surface explicit.

And more importantly, it allows passing a different display than the
default one.
2024-01-07 14:47:22 +01:00
Benjamin Otte df09975753 renderer: Pass the display as part of the vfunc
We allow realizing renderers without surfaces. But they still need a
display, so pass it explicitly.
2024-01-07 14:47:22 +01:00
Benjamin Otte d21467e2e8 gdk: Remove all VulkanContext API
All API for GdkVulkanContext gets removed here. It was experimental and
it's not a good API. So get rid of it.
2024-01-07 14:47:22 +01:00
Benjamin Otte c8529df309 inspector: Use Vulkan without a context
This means we don't need to include gdkvulkancontext.h and it means we
don't initialize Vulkan if it isn't initialized yet.

Should we?
Should we add a button maybe?

No idea.
2024-01-07 14:47:22 +01:00
Benjamin Otte 5f03053569 gsk: include Vulkan renderer in public header
The Vulkan renderer can just be public API, because it doesn't expose
any Vulkan-specific APIs.
And it can just exist when compiled without Vulkan, because it can fail
to realize.

Also move get rid of the gsk/vulkan/gskvulkanrenderer.h header. It was
experimental and isn't necessary now that the renderer is included via
gsk.h.
2024-01-07 14:47:22 +01:00
Benjamin Otte 1dbd74e181 Merge branch 'wip/otte/gpu' into 'main'
Add new unified renderer

See merge request GNOME/gtk!6588
2024-01-07 07:44:16 +00:00
Matthias Clasen c8ae2d9002 testsuite: Add NGL and Vulkan renderer to compare tests
Add a testsuite called gsk-compare-vulkan to run
the gsk renderer tests with the Vulkan renderer and
gsk-compare-ngl to run them with the NGL renderer.

To run the tests locally, you can do:

meson test -C_build --suite gsk-compare-vulkan
2024-01-07 08:18:36 +01:00
Benjamin Otte 03cd652063 gpu: Disable the ubershader when shaders aren't nonuniform
If shaders don't support nonuniform indexing, we emulate it via if/else
ladders (or switch ladders) which get inlined by the GLSL compiles and
massively blow up the code.

And that makes compilation of the shaders take minutes and results in
shader code that isn't necessarily faster.

So we disable it on GL entirely and on Vulkan if the required features
aren't available.

As it's only an optimization and does not fall back to Cairo anymore,
this should be fine.
2024-01-07 08:18:36 +01:00
Matthias Clasen c0d49f296e Update docs
Update the docs for environment variables that we parse to include
GDK_VULKAN_SKIP and GSK_GPU_SKIP.
2024-01-07 07:22:53 +01:00
Benjamin Otte 1723ab34e1 gpu: Setup attribute locations
Make the generator generate calls for the correct glBindAttribLocation()
calls.

Usually this was done correctly, but we can't rely on it. So do it
explicitly.
2024-01-07 07:22:53 +01:00
Benjamin Otte 55dbf0accb gpu: Add GSK_GPU_SKIP=blit
This allows bypassing all blit operations using gsk_gpu_blit_op()
in favor of shaders.
2024-01-07 07:22:53 +01:00
Benjamin Otte b3d044a0b1 gpu: Add more assertions to blitop
The blitop is nasty, so we should make sure we have supported images
when using it.
2024-01-07 07:22:53 +01:00
Benjamin Otte 2fef71da5c gpu: Generate mipmap by default when downscaling too much
When downscaling more than 2x in either dimension, force mipmap use for
the texture in a texture node.
It improves the quality of textures but takes extra work.

The GL renderer does this, too (for textures that aren't in the icon cache).

This can be disabled via GSK_GPU_SKIP=mipmap.

Fixes the big-checkerboard-scaled-down2 test.
2024-01-07 07:22:53 +01:00
Benjamin Otte 48c1f5fd27 gpu: Add supersampling for gradients
Unless GSK_GPU_SKIP=gradients is given, we sample every point 4x instead
of 1x. That makes the shader run slower (by roughly a factor of 2.5x)
but it improves quality quite a bit.
2024-01-07 07:22:53 +01:00
Benjamin Otte 6e4a526ddf gpu: Add a blend mode shader
I'm a bit unsure about using the zero rect in the fallback situtation
where one image doesn't exist, but it seems to work.

This removes the last pattern-only rendernode and with that the last
fallback usage with disabled ubershader.
2024-01-07 07:22:53 +01:00
Benjamin Otte d11886e7ac gpu: Use variations in the blur shader
Have one variation for colorizing to a shadow color and another
variation that just blurs.
2024-01-07 07:22:53 +01:00
Benjamin Otte 177b19a2da gpu: Use variations in the straight-alpha shader
This way we can toggle opacity handling on/off.

THe shader slowly turns into a fancy texture op - but I don't want to
rename it to "fancytexture" just yet.
2024-01-07 07:22:53 +01:00
Benjamin Otte f943469fc9 gpu: Use variations for radial gradients 2024-01-07 07:22:53 +01:00
Benjamin Otte 59d062cb3d gpu: Use variations for the mask mode 2024-01-07 07:22:53 +01:00
Benjamin Otte 8032e30a76 gpu: Make linear gradients use variations 2024-01-07 07:22:53 +01:00
Benjamin Otte 2e81e4d452 gpu: Make box shadow shader use variations
Use it do differentiate between inset and outset shadows.
2024-01-07 07:22:53 +01:00
Benjamin Otte d900407a18 gpu: Introduce the concept of "variation"
A variation is a #define/specialization constant that every shader can
use to specialize itself as it sees fit.

This commit adds the infrastrcture, future commits will add
implementations.
2024-01-07 07:22:53 +01:00
Benjamin Otte 64e5c76323 png: Don't set a size limit when saving
gdk_texture_save_to_png_bytes() cannot fail, so ensure that it doesn't.

Testsuite has been updated to check for this case.

Note that we do not load the PNG file that we generate here.
Loading is a lot more scary than saving after all.
If people want to load oversized PNG files, they should use a real PNG
loader.
2024-01-07 07:22:53 +01:00
Benjamin Otte b9651606d3 gpu: Add a cross-fade shader 2024-01-07 07:22:53 +01:00
Benjamin Otte 2a5f6fdde5 gpu: Handle a clipping cornercase properly
If we enter the situation where we need to redirect the clipping to an
offscreen, make sure that:

* the ubershader gets only used when beneficial

* we size the offscreen properly and don't let it grow infinitely.

Fixes the clip-intersection-fail-opacity test
2024-01-07 07:22:53 +01:00
Benjamin Otte 6dbbd65ef8 gpu: Handle opacity in the Cairo path
Fixes random calls to add_fallback_node() from code that wants to handle
opacity.

Also makes Cairo nodes work with opacity, of course.
2024-01-07 07:22:53 +01:00
Benjamin Otte 9947760d87 gpu: Handle alpha in image_op() wrapper
There are various places where the alpha is implicitly assumed to be
handled, so just handle it.

As a bonus, this simplifies a bunch of code and makes the texture node
rendering work with alpha.
2024-01-07 07:22:53 +01:00
Benjamin Otte 493b83ff24 gpu: Optimize box-shadow shader
Like in the border shader, don't draw the (potentially large for the
window's shadow) inside part that is transparent.
2024-01-07 07:22:53 +01:00
Benjamin Otte b65f6eef59 gpu: Replace a fallback with offscreens
Use an offscreen and mask it if the clips get too complicated.

Technically, the code could be improved to set the rounded clip on the
offscreen instead of rendering it as a mask, but that would require more
sophisticated tracking of clip regions by respecting the scissor, and
the current clip handling can't do that yet.

This removes one of the last places where the GPU renderer was still
using Cairo fallbacks.
2024-01-07 07:22:53 +01:00
Benjamin Otte f6ff0ee18c gpu: Add gsk_gpu_node_processor_add_images()
This is for generating descriptors for more than 1 image. The arguments
for this function are very awkward, but I couldn't come up with better
ones and the function isn't that important.

And the calling places still look a lot nicer now.
2024-01-07 07:22:53 +01:00
Benjamin Otte b388c066dc gpu: Add gsk_gpu_node_processor_init_draw/finish_draw()
These initialize/finish an offscreen and start drawing to it.

It simplifies the process of using offscreens quite a bit that way.
2024-01-07 07:22:53 +01:00
Benjamin Otte 9fe011b98f gpu: Add stroke support
Same as for fill nodes, we render the stroke to a mask and then run a
mask shader.

The color node child optimization is included already.
2024-01-07 07:22:53 +01:00
Benjamin Otte 89ab3a8146 gpu: Optimize solid color fills 2024-01-07 07:22:53 +01:00
Benjamin Otte 5dcaca9b3c gpu: Add fill node support
For now this uses Cairo to generate a mask and then runs a mask op.

This is different from just using fallback in that the child is rendered
with the GPU and not via fallback.
2024-01-07 07:22:53 +01:00
Benjamin Otte 69c8278558 gpu: Add a radial gradient shader
This is mainly copy/paste, so now this almost identical gradient code
exists 3 times.
That's kinda suboptimal.
2024-01-07 07:22:53 +01:00
Benjamin Otte 0e9b967bf9 gpu: Add a conic gradient shader 2024-01-07 07:22:53 +01:00
Benjamin Otte 0c32a94d8e gpu: Split linear gradient shader into 2 parts
A generic part that can be shared by all gradient shaders that does the
color stop handling and a gradient-specific part that needs to be
implemented individually by each gradient implementation.
2024-01-07 07:22:53 +01:00
Benjamin Otte 6d20f4bc60 gpu: Change the cairo upload op prototype
Make it take a draw function instead of a node.

This way, we can draw more fancy stuff with Cairo.
2024-01-07 07:22:53 +01:00
Benjamin Otte 8361949ba1 gpu: Handle >7 color stops
If there are more than 7 color stops, we can split the gradient into
multiple gradients with color stops like so:
  0, 1, 2, 3, 4, 5, transparent
  transparent, 6, 7, 8, 9, 10, transparent
  ...
  transparent, n-2, n-1, n
and use the new BLEND_ADD to draw them on top of each other.

Adapt the testcae that tests this to use colors that work with the fancy
algorithm we use now, so that BLEND_ADD and transitions to transparent
do not cause issues.
2024-01-07 07:22:52 +01:00
Benjamin Otte 8372bc00bd gpu: Make the ubershader use the correct coordinates
Instead of scaled coordinates, use the unscaled ones.

This ensure that gradients get computed correctly as they are not safe
against nonorthogonal transforms - like scales with different scale
factors.
2024-01-07 07:22:52 +01:00
Benjamin Otte 5cf3c70db0 gpu: Make blend modes configurable
For now, we only have OVER and ADD blend modes. This commit doesn't use
ADD, it just sets up all the machinery and refactors things.
2024-01-07 07:22:52 +01:00
Benjamin Otte a031011e5e gpu: Add a linear-gradient shader
The shader can only deal with up to 7 color stops - but that's good
enough for the real world.

Plus, we have the uber shader.

And if that fails, we can still fall back to Cairo.

The code also doesn't handle repeating linear gradients yet.
2024-01-07 07:22:52 +01:00
Benjamin Otte bd901896ee gpu: Add a mask shader
This shader can take over from the ubershader. And it can be used
instead of launching the ubershader when no offscreens are necessary.

Also includes an optimization that uses the colorize shader when
appropriate.
2024-01-07 07:22:52 +01:00
Benjamin Otte cb5c994cd9 rgba: Add a few macros
... and use them.

Those macros hopefully make code more readable.
2024-01-07 07:22:52 +01:00
Benjamin Otte 39a0e27513 gpu: Use ubershader for repeat nodes when possible 2024-01-07 07:22:52 +01:00
Benjamin Otte 832ddb31b7 gpu: Add a repeat node renderer
The ubershader has some corner cases where it can't be used, in
particular when the child is massively larger than the repeat node and
the repeat node is used to clip lots of the source.
2024-01-07 07:22:52 +01:00
Benjamin Otte 8bdc7a3289 renderer: Add Vulkan renderer to the list of renderers
It's better than the Cairo renderer, so use it instead.

It's still only picked once GL fails, so it will probably only ever be
picked when people use GDK_DEBUG=gl-disable, but at least it will be
picked.
2024-01-07 07:22:52 +01:00
Benjamin Otte 57521e6242 renderer: Split function
per-backend renderers and GL renderers are a different thing, so treat
them as such.

Also, try the GL renderer unconditionally. The renderer initialization
code will take care of GL not being available.
2024-01-07 07:22:52 +01:00
Benjamin Otte 93d681ae77 vulkan: Add a Vulkan downloader
This is using the Vulkan renderer.

It also allows claiming support for all the formats that only Vulkan
supports, but that neither GL nor native mmap can handle.
2024-01-07 07:22:52 +01:00
Benjamin Otte a9b27a7de0 gpu: Implement a GdkDmabufDownloader 2024-01-07 07:22:52 +01:00
Benjamin Otte 41d80ac277 gpu: Add a boolean flag allow_dmabuf to the downloadop
It can be set to force the downloadop to not create dmabuf textures.
2024-01-07 07:22:52 +01:00
Benjamin Otte cf9b8231bd gpu: Update to memoryformat Vulkan code
The existing code for setting up formats was copied from the old Vulkan
renderer and never updated.
2024-01-07 07:22:52 +01:00
Benjamin Otte 3b6035a46d testsuite: Add new renderers to the scaling test 2024-01-07 07:22:52 +01:00
Benjamin Otte c7a69882d3 gpu: Reorganize format handling
Add GSK_GPU_IMAGE_RENDERABLE and GSK_GPU_IMAGE_FILTERABLE and make sure
to check formats for this feature.

This requires reorganizing code to actually do this work instead of just
pretending formats are supported.

This fixes GLES upload tests with NGL.
2024-01-07 07:22:52 +01:00
Benjamin Otte e5cd813a24 gpu: Add debug messages
Add FALLBACK debug messages when a texture upload format is not
supported.
2024-01-07 07:22:52 +01:00
Benjamin Otte 62d917eb08 vulkan: Use vulkan feature flags for incremental present
I did it because it unifies the code.

But it also gains the benefit of being debuggable because it can
now be turned off via GDK_VULKAN_SKIP=incremental-present
2024-01-07 07:22:52 +01:00
Benjamin Otte d4c4e4bbc5 gpu: sync dmabufs via semaphores
This ensures both that we signal a semaphore for a dmabuf when we export
an image and that we import semaphores for dmabufs and wait on them.

Fixes Vulkan node-editor displaying the Vulkan renderer in the sidebar.
2024-01-07 07:22:52 +01:00
Benjamin Otte cfcc9658b2 gpu: Make VulkanRealDescriptor keep the frame
There's too much interaction between the two to warrant not having it
around.
2024-01-07 07:22:52 +01:00
Benjamin Otte d8a0cd24d7 gpu: Add support for blend modes 2024-01-07 07:22:52 +01:00
Benjamin Otte 496ecd68f2 gpu: Make Vulkan renderer provide dmabuf textures
Make gsk_renderer_render_texture() create a dmabuf texture if that is
possible.

If it isn't (ie if we're not on Linux or if dmabufs are otherwise not
working) fall back to the previous code of creating a memory texture.
2024-01-07 07:22:52 +01:00
Benjamin Otte 683878c733 gpu: Add gsk_gpu_device_create_download_image()
This way, we can differentiate between regular offscreens and images
that are meant to be used for gsk_renderer_render_texture() or similar.
2024-01-07 07:22:52 +01:00
Benjamin Otte 38c0e2bdf6 gpu: Update the pipeline cache
When a new shader was compiled, queue a save of the pipeline cache.
2024-01-07 07:22:52 +01:00
Benjamin Otte f0fc2709d6 gpu: Implement support for multiple storage buffers
When using the uber shader a lot, we may overflow the (only 16kB large)
storage buffer.

Stop crashing when that happens and instead just allocate a new one.
2024-01-07 07:22:52 +01:00
Benjamin Otte 1b38cbd410 gpu: Handle storage buffers via descriptors
This makes the (currently single) storage buffer handled by
GskGpuDescriptors.
A side effect is that we now have support for multiple buffers in place.
We just have to use it.

Mixed into this commit is a complete rework of the pattern writer.
Instead of writing straight into the buffer (complete with repeatedly
backtracking when we have to do offscreens), write into a temporary
buffer and copy into the storage buffer on committing.
2024-01-07 07:22:52 +01:00
Georges Basile Stavracas Neto c2ec97e922 gpu/renderer: Improve scale detection
The GL branch should eventually call into gdk_gl_context_get_scale(),
which is what checks for GDK_DEBUG=gl-fractional; whereas the Vulkan
branch needs no change.
2024-01-07 07:22:52 +01:00
Benjamin Otte 90a278ce46 gpu: Rename some descriptors APIs
We want tosupport buffers here, too, so make the names unambiguous.
2024-01-07 07:22:52 +01:00
Benjamin Otte 2a5fe8cd0c gpu: Only run uber shaders if beneficial
If we have the choice between running the ubershader or a normal shader
with offscreens, make the choice depend on if the ubershader would
offscreen anyway.
If so, just run the normal shader.

This really gets rid of all ubershader invocations in Adwaita
widget-factory.
2024-01-07 07:22:52 +01:00
Benjamin Otte 42d89a0ff1 gpu: Add a color matrix shader
This allows avoiding the uber shader in 2 important cases:

1. opacity - and Adwaita uses that a lot
2. color-matrix - it's used for symbolic icons
2024-01-07 07:22:52 +01:00
Benjamin Otte 9f65cdf3aa gpu: Add support for subsurfaces 2024-01-07 07:22:52 +01:00
Benjamin Otte 35bc08da5e gpu: Rework caching layer
Instead of using an enum, use a usual custom class struct like we use
for GskGpuOp.

As a side effect of that refactoring, the display gained a hash table
for textures where we can't use the render data because the texture is
used in multiple renderers.
The goal here is that a texture is always cached and we can ensure that
there is a 1:1 relation between textures and their GskGpuImage. This is
important in particular for external textures - like dmabufs - where we
absolutely don't want 2 images with 2 device memories, and where we use
toggle references to keep them alive.
2024-01-07 07:22:52 +01:00
Benjamin Otte 723c2493b2 gpu: Handle opacity in a bunch of nodes 2024-01-07 07:22:52 +01:00
Benjamin Otte 245e51099f gpu: Add optimization for opacity nodes
Track the global opacity and allow nodes to handle it themselves.

If the nodes don't, fall back to what we did previously: Use the
ubershader.
2024-01-07 07:22:52 +01:00
Benjamin Otte a06cd6a821 gpu: Make the uber shader handle affine transforms
Fixes the last (non-blur) Nautilus offscreens in Nautilus.
2024-01-07 07:22:52 +01:00
Benjamin Otte 1c509be875 gpu: Replace clip node fallback with uber or offscreen
We don't need to use a fallback here anymore, we have enough code by now
to do this smarter.
2024-01-07 07:22:52 +01:00
Benjamin Otte 9894417a09 gpu: Split out a function
We want to use it elsewhere.
2024-01-07 07:22:52 +01:00
Benjamin Otte 51f218c877 gpu: Replace fallback with offscreen
We don't need to fallback with transform nodes when the clip is
too complex. We can redirect to an offscreen instead, which doesn't have
a clip.
2024-01-07 07:22:52 +01:00
Benjamin Otte a8bb0a0ee1 gpu: Split out a function
I want to use it in more places.
2024-01-07 07:22:52 +01:00
Benjamin Otte b7414dfbdd gpu: Be stricter about texture units
Reserve 3 texture units per immutable sampler (because that's the
maximum per YUV sampler).
Ensure that the max-sampler calculations always include the immutable
samplers, too.
2024-01-07 07:22:52 +01:00
Benjamin Otte 057479c284 gpu: Improve memory handling on Vulkan
We now handle the case where memory is not HOST_CACHED.

We also track the memory type now so we can avoid mapping image memory
that is not HOST_CACHED and use buffer transfers instead.
2024-01-07 07:22:52 +01:00
Benjamin Otte c5a01cd14b gpu: Make the texture ladder handle 32 textures
So now we can put more textures in one descriptor set even if dynamic
indexing isn't supported.
2024-01-07 07:22:52 +01:00
Benjamin Otte 719ff9eca9 gpu: Require Vulkan 1.2 shaders for dynamic indexing
Shader compilers struggle with compiling code that indexes texture
arrays by indexes, so keep the fallback shaders simple and don't do that
there.

There's not much of a performance difference anyway between those two
methods.
2024-01-07 07:22:52 +01:00
Benjamin Otte d50e235753 gpu: Add back single descriptors set usage with descriptor indexing 2024-01-07 07:22:51 +01:00
Benjamin Otte ae2020aca2 gpu: Make descriptor-indexing optional
Do extra work if it's not available.
2024-01-07 07:22:51 +01:00
Benjamin Otte 450524f6cf gpu: Remove UPDATE_AFTER_BIND flag
We don't update after binding.
2024-01-07 07:22:51 +01:00
Benjamin Otte be09cebb09 gpu: Handle multiple image descriptors
In the case where descriptor indexing is not enabled and the number of
max images is small (or we use extensive amounts of immutable samplers),
we need to be able to switch descriptors.

This patch makes that possible.
2024-01-07 07:22:51 +01:00
Benjamin Otte 6230ff0fc4 gpu: Cache GL state
That way we don't need to setup the textures and program for every
command.
2024-01-07 07:22:51 +01:00
Benjamin Otte 1733671295 gpu: Add a CommandState struct to the command vfuncs
This way, we can make it writable and track things like the active
textures and the current program.

We don't do that yet, but we can.
2024-01-07 07:22:51 +01:00
Benjamin Otte 78a7127b96 gpu: Handle missing support nor nonuniform texture accesses
We compile custom shaders for Vulkan 1.0 that don't require the
extension.

We  also ensure that our accesses are uniform by only executing one
shader at a time.
2024-01-07 07:22:51 +01:00
Benjamin Otte 94063cbe92 gpu: Change the meson code for how SPIR-V is built
This does the same thing, but in a way that's a bit more flexible.
And it prepares the next commit...
2024-01-07 07:22:51 +01:00
Benjamin Otte 96e579501f gpu: Add GDK_VULKAN_SKIP env var
The variable forces skipping of optional Vulkan features. This is useful
for testing.

Also debug-print the features in use.
2024-01-07 07:22:51 +01:00
Benjamin Otte 98c88780bc gpu: Set max samplers/buffers based on features
If we run older code, we don't have enough samplers and buffers
available. So make sure to reflect that.
2024-01-07 07:22:51 +01:00
Benjamin Otte 7dcb7d7d0f gpu: Add Vulkan feature flags for more advanced features
Code continues if those features aren't available, buit is probably
broken.
2024-01-07 07:22:51 +01:00
Benjamin Otte 95e36af46b gpu: Update shader code for different buffer/sampler sizes
Use specialization constants for that.
2024-01-07 07:22:51 +01:00
Benjamin Otte 47a13e601f gpu: Make PipelineLayout objects do more things
Let the objects track the number of samplers or buffers needed.

This is a required step for making Vulkan work with less featureful
(read: mobile) implementations.
2024-01-07 07:22:51 +01:00
Benjamin Otte a301f18ebf gpu: Track position fwidth explicitly
This is relevant went encountering repeat nodes, where the repeat cutoff
will make the fwidth of the position go wild otherwise.

Gradients require more work now, because we need to compute offsets
twice - once for the pixel, once for the offst.
2024-01-07 07:22:51 +01:00
Benjamin Otte 6cbf4667a4 gpu: Add support for dmabuf import to GL 2024-01-07 07:22:51 +01:00
Benjamin Otte ef20b706e2 gpu: Prepare GL rendering for samplerExternalEOS
Carry an n_external_textures variable around when selecting programs and
compile different programs for different amounts of external textures.

For now, this code is unused, but dmabufs will need it.
2024-01-07 07:22:51 +01:00
Benjamin Otte 979e4207f3 gpu: Add importing of GL textures to the GL renderer
syncing with the GLsync is kind of a hack (because we just do it on
import), but it works.
2024-01-07 07:22:51 +01:00
Benjamin Otte c29237c75d gpu: Add support for texture-scale nodes
This adds GSK_GPU_IMAGE_CAN_MIPMAP and GSK_GPU_IMAGE_MIPMAP flags and
support to ensure_image() and image creation functions for creating a
mipmapped image.

Mipmaps are created using the new mipmap op that uses
glGenerateMipmap() on GL and equivalent blit ops on Vulkan.

This is then used to ensure the image is mipmapped when rendering it
with a texture-scale node.
2024-01-07 07:22:51 +01:00
Benjamin Otte 99aa5f398b gpu: Add blitting support
Add GSK_GPU_IMAGE_NO_BLIT flag for textures that can't be blitted from.

Use a blit op to do image copies otherwise.
2024-01-07 07:22:51 +01:00
Benjamin Otte 1858d955de testsuite: Add a test to check scaling behavior
Various GL texture formats do not support linear scaling or mipmap
generation.

Add a test that checks this.
2024-01-07 07:22:51 +01:00
Benjamin Otte 3e5af3afce testsuite: Update memorytexture text to use new renderers
1. Refactor checks for GL support

2. Add NGL and Vulkan
2024-01-07 07:22:51 +01:00
Benjamin Otte b4a1ed2a70 gpu: Add straight alpha support
Add a GSK_GPU_IMAGE_STRAIGHT_ALPHA and use it for images that have
straight alpha.
Make sure those images get passed through a premultiplying pass with
the new straight alpha shader.

Also remove the old Postprocess flags from the Vulkan image that were a
leftover from copying that code from the old Vulkan renderer.
2024-01-07 07:22:51 +01:00
Benjamin Otte f05a8927f3 gpu: Work around Ycbcr not working with dynamically uniform indices
There's a well hidden line in the spec that says in
https://registry.khronos.org/vulkan/specs/1.3/html/chap15.html#interfaces-resources-descset

  If the combined image sampler enables sampler Y′CBCR conversion,
  it **must** be indexed only by constant integral expressions when
  aggregated into arrays in shader code, irrespective of the
  shaderSampledImageArrayDynamicIndexing feature.

So we'll use the same trick that we use for old GL here and do an
if dance that gives us dynamically uniform expressions.
2024-01-07 07:22:51 +01:00
Benjamin Otte a2368803fa gpu: Add dmabuf import for Vulkan
This now uses all the previously added features to allow displaying YUV
images.

Also add a utility function that turns an image into a toggle ref for a
texture. This makes sure that reffing the image also refs the texture
and that ensures that textures stay alive as long as the image is in
use.
2024-01-07 07:22:51 +01:00
Benjamin Otte ee93f88268 vulkan: Add support for enumerating dmabuf formats
This code does not add a downloader, so we do not claim support for all
the new formats.

It just queries the formats. But this can be used to import dmabufs
directly into the Vulkaan renderer.
2024-01-07 07:22:51 +01:00
Benjamin Otte 32d35b1d01 gpu: Handle flags for images
For now, the flags are just there because, and nobody uses them yet.
The only flag is EXTERNAL, which for now I'm using for YUV buffers,
though it's a bit undefined what that means.
2024-01-07 07:22:51 +01:00
Benjamin Otte 528e246f1a gpu: Add a mipmap sampler
It's not used yet, but the sampler infrastructure needs to be expanded,
so I decided to split this out to easier find regressions.
2024-01-07 07:22:51 +01:00
Benjamin Otte 03f820d26c gpu: Add support for immutable samplers to Vulkan
Images can now have samplers - meaning they must be rendered with that
sampler. It also means that sampler must be handled as an immutable
sampler in descriptorsets.
These samplers can be created with a samplerYcbcrConversion, so code has
been added to pass that conversion when creating the imageview.

Also add code to GskVulkanFrame to track immutable samplers.

Nobody is making use of this yet.
2024-01-07 07:22:51 +01:00
Benjamin Otte bf39fa3b3b gpu: Hook up immutable samplers to shaders
Define an array with a compile-time-constant variable size for the
immutable samplers.

A bunch of work is necessary to ensure that at least one element is in
the sampler array, because the GLSL code
  sampler2D immutable_textures[0];
is invalid.
2024-01-07 07:22:51 +01:00
Benjamin Otte d2229e2aed gpu: Add GskVulkanPipelineLayout
This allows having different layouts sothat we can support immutable
samplers, whcih are required for multiplane and YUV formats.

We don't use them yet.
2024-01-07 07:22:51 +01:00
Benjamin Otte 9eac147426 gpu: Add a cache for YcbcrConversions
We index them only by VkFormat for now because we don't have another
differentiator.

It's unused so far.
2024-01-07 07:22:51 +01:00
Benjamin Otte 1b1abba313 gpu: Add an "external" allocator to Vulkan
The allocator is supposed to be used with externally allocated vkMemory
objects that are meant to be freed normally - in particular dmabufs.
2024-01-07 07:22:51 +01:00
Benjamin Otte 223d1343de gpu: Add GdkDisplay::vulkan_features
use it to collect the optional features we are interested in and turn
them on only if available.

For now we add the dmabuf features, but we don't use them yet.
2024-01-07 07:22:51 +01:00
Benjamin Otte f0f6af1cf8 gpu: Create Vulkan samplers on-demand 2024-01-07 07:22:51 +01:00
Benjamin Otte 82eed5d672 gpu: Make Vulkan image formats check use newer functions
This is just an update of all vkGetFoo() calls to use vkGetFoo2().
2024-01-07 07:22:51 +01:00
Benjamin Otte 38f64c2357 gpu: Move caching to the upload_texture() function
So when uploading a texture, we will automatically put it into the cache
now.
2024-01-07 07:22:51 +01:00
Benjamin Otte daadaf8448 gpu: Factor out uploading textures into a vfunc
This way GL and Vulkan can run custom code to import GL textures and
dmabufs.

This function also decides if and how to cache the textures it creates.
2024-01-07 07:22:51 +01:00
Benjamin Otte e86fa6a072 gpu: Apply clip to ubershader bounds
Fixes excessive bounds when using the ubershader for huge nodes
contained inside clip nodes.
2024-01-07 07:22:51 +01:00
Benjamin Otte 1b3eb3ecd1 gpu: Fail to create images that are too big
It's up to the renderers to handle the NULL return value.
2024-01-07 07:22:51 +01:00
Benjamin Otte 94539e6f08 gpu: Allow texture uploads to fail
The main reason here is that we want to not fail when the texture size
is larger than the supported GpuImage size.

When that happens, for now we just fallback slowly - ulitmately to
drawing with Cairo, which is going to be clipped.
2024-01-07 07:22:51 +01:00
Benjamin Otte f5af3fe933 gpu: Add render_texture() fallback impl for huge sizes
This copies over the GLRenderer approach of step-by-step filling a
memorytexture.

It just adds some extra niceties by respecting the best format.
2024-01-07 07:22:51 +01:00
Benjamin Otte bbad290518 gpu: Add gsk_gpu_device_get_max_image_size()
... and initialize it properly.
2024-01-07 07:22:51 +01:00
Benjamin Otte 334e380d31 gpu: Handle overlapping rounded rect corners
Have a fallback in place for the most egregious abuses of rounded
corners, like
  0 0 50 50 / 50 0
and the like.

Fixes obscure border colors.
2024-01-07 07:22:51 +01:00
Benjamin Otte d8db673fb7 gpu: Add a box shadow shader
Code was inspired mainly by
  https://madebyevan.com/shaders/fast-rounded-rectangle-shadows/
and
  https://pcwalton.github.io/_posts/2015-12-21-drawing-css-box-shadows-in-webrender.html

So far the results aren't cached, that's the task of future commits.
2024-01-07 07:22:51 +01:00
Benjamin Otte 268ad54c6a gpu: Add a rounded color shader
There's multiple uses I want it for:

1. Generating the box-shadow area for blurring
2. Generating masks for rounded-rect masking
3. Optimizing the common use case of rounded-clip + color

Only the last one is implemented in this commit.
2024-01-07 07:22:50 +01:00
Benjamin Otte 64a67ac3a8 gpu: Turn globals into macros
This way, we can be more flexible in refactoring how we handle globals
(guess what we're gonna do next).
2024-01-07 07:22:50 +01:00
Benjamin Otte 74ac95dc32 gpu: Don't try to be smart
Don't try to use all those fancy GL features like glMapBuffer() and
such. Just malloc() some buffer memory and glBufferSubData() it later.

That works everywhere and is faster than (almost?) any combination of
fancy new buffer APIs. And yes I'm frustrated because I played with
those flags and none of them were better than this.

Doubles the framerate on my discrete AMD GPU.
2024-01-07 07:22:50 +01:00
Benjamin Otte 7f817fce0a gpu: Use GL_STREAM_DRAW for the push constants buffer
This seems to hit a bunch of optimizations and makes push constants
slightly faster.
2024-01-07 07:22:50 +01:00
Benjamin Otte 5549a7ab5f gpu: Merge ops on GL, too
Just like on Vulkan, try to minimize the glDrawArrays() calls by merging
adjacent ops.
2024-01-07 07:22:50 +01:00
Benjamin Otte 53821da4d6 gpu: Refactor image handling
Introduce a new GskGpuImageDescriptors object that tracks descriptors
for a set of images that can be managed by the GPU.
Then have each GskGpuShaderOp just reference the descriptors object they are
using, so that the coe can set things up properly.

To reference an image, the ops now just reference their descriptor -
which is the uint32 we've been sending to the shaders since forever.
2024-01-07 07:22:50 +01:00
Benjamin Otte f518d780ed gpu: Add atlas support
... and use it for glyphs.
2024-01-07 07:22:50 +01:00
Benjamin Otte 9045431bde gpu: Add a GL optimization
Use glDrawArraysInstancedBaseInstance() to draw. (Yay for GL naming.)
That allows setting up the offset in the vertex array without having to
glVertexAttribPointer() everything again.

However, this is only supported since GL 4.2 and not at all in stock GLES,
so we need to have code that can work without it.
Fortunately, it is mandatory in Vulkan, so every recent GPU supports it.
And if that GPU has a proper driver, it will also expose the GL extension
for it.
(Hint: You can check https://opengles.gpuinfo.org/listextensions.php for
how many proper drivers exist outside of Mesa.)
2024-01-07 07:22:50 +01:00
Benjamin Otte 8271687ef6 gpu: Make border shader usable for inset/outset
... and use it for those when unblurred.
2024-01-07 07:22:50 +01:00
Benjamin Otte 8043d4d6e0 gpu: Add GSK_GPU_SKIP=merge
Disables merging of ops for vkCmdDraw().
2024-01-07 07:22:50 +01:00
Benjamin Otte e7a59d92ac gpu: Add GSK_GPU_SKIP env var
The env var allows skipping various optimizations in the GPU shader.

This is useful for testing during development when trying to figure
out how to make a renderer as fast as possible.

We could also use it to enable/disable optimizations depending on GL
version or so, but I didn't think about that too much yet.
2024-01-07 07:22:50 +01:00
Benjamin Otte e3bac4063c gpu: Copy the clear trick from the Vulkan shader
When drawing opaque color regions that are large enough, use
vkCmdClearAttachments()/glClear() instead of a shader. This speeds up
background rendering on particular on older GPUs.

See the commit messages of
  bb2cd7225e
  ce042f7ba1
  0edd7547c1
for a further discussion of performance impacts.
2024-01-07 07:22:50 +01:00
Benjamin Otte 48012a1ce4 gpu: Add a color shader
We don't want to use the pattern shader for simple colors, slow GPUs do
not like this at all.
2024-01-07 07:22:50 +01:00
Benjamin Otte 63f6e75b38 gpu: Implement blur nodes
With the work already done with shadow nodes, this one was easy.
2024-01-07 07:22:50 +01:00
Benjamin Otte 23c1ec07e7 gpu: Implement shadow nodes 2024-01-07 07:22:50 +01:00
Benjamin Otte 7431a58617 gpu: Change sorting for ops
The previous algorithm would reverse the order of subpasses, whcih leads
to unexpected behavior if dependent subpasses are not added as children
of a subpass, but just as a previous subpass - like when a subpass is
used multiple times later.

An example for this is a shadow node with multiple shadows - the source
of the shadow is used by the multiple shadows.

So ensure that adjacent subpasses stay in the same order.
2024-01-07 07:22:50 +01:00
Benjamin Otte 30e9d98f0d gpu: Add a "transparent" sampler
This is using the equivalent of EXTEND_NONE, but I wasn't sure what to
call it.

It's unused atm.
2024-01-07 07:22:50 +01:00
Benjamin Otte 43d0b0fb3c gpu: Turn off optimizing in glslc
The code generated by glslc -O is optimized worse by Mesa than
code generated unoptimized.

So generate unoptimized code until somebody figures out what's going
wrong here.
2024-01-07 07:22:50 +01:00
Benjamin Otte d47c8613b0 gpu: Add support for mask patterns 2024-01-07 07:22:50 +01:00
Benjamin Otte e01311a565 gpu: Add support for cross-fades 2024-01-07 07:22:50 +01:00
Benjamin Otte 0876089f8f gpu: Add repeat nodes
They're done using the pattern shader.

The pattern shader now gained a stack where vec4's can be pushed and
popped back later, which allows storing the position before computing
the new position inside the repeat node's child.
2024-01-07 07:22:50 +01:00
Benjamin Otte b7a8c2207e gpu: Introduce gsk_texture() shader function/macro
Due to GLES and old GL not allowing non-constant texture array
lookups,we need to turn the array lookup into a big switch statementin
those versions, and that requires putting the texture() call into that
switch.

But with that trick, we can use texture IDs in GLSL.
2024-01-07 07:22:50 +01:00
Benjamin Otte 5ab8fde0bc gpu: Add colorize shader
... and use it for glyphs.

The name is a slight variation of the "coloring" name from the GL
renderer.
The functionality is exactly what the "glyph" shader from the Vulkan
renderer does.
2024-01-07 07:22:50 +01:00
Benjamin Otte d1d1af1a62 gpu: Improve conic gradient rendering
1. Compute the fwidth() twice with offset offsets
   That way, we avoid glitches at the boundary between 0.0 and 1.0,
   because by offsetting it by 0.5, that boundary goes away.
   Then we take the min() of both which gives us the one we care about.

2. Set the gradient to repeating
   By doing that, we don't get values at the 0.0/1.0 boundary clamped,
   but things smoothly transition.
   This smoothes the line at that boundary and makes it look just like
   every other line.
2024-01-07 07:22:50 +01:00
Benjamin Otte 88618952c5 gpu: Round offscreens to pixel boundaries
Instead of strictly rounding to the given clip rectangle, increase the
rectangle to the next pixel boundary.

Also add docs that the clip_bounds do not influence the actual size of
the returned image.
2024-01-07 07:22:50 +01:00
Benjamin Otte 92d1df94fa gpu: Add GskGpuPatternWriter
It's just an object that encapsulates everything needed to create (the
data for) a pattern op.

It also clarifies which code does what, because now the NodeProcessor
and the PatternWriter are 2 different things.
2024-01-07 07:22:50 +01:00
Benjamin Otte 187db92a88 gpu: Make shader image access a vfunc
That allows shaders to handle textures differently.

In particularly, it will allow the pattern shader to take a huge amount
of textures.
2024-01-07 07:22:50 +01:00
Benjamin Otte a9b8551e70 gpu: Add clip pattern
So now we can clip inside an opacity node without needing fallback.
2024-01-07 07:22:50 +01:00
Benjamin Otte 0cac75aff1 gpu: Passthrough subsurface nodes
We don't support subsurfaces for now, so we can just ignore the nodes.
2024-01-07 07:22:50 +01:00
Benjamin Otte 6cf3f6ebff gpu: Add support for debug nodes
Passthrough is always easy.
2024-01-07 07:22:50 +01:00
Benjamin Otte 3efe1bef93 gpu: Add a border shader
Pretty much a copy of the Vulkan border shader.

A notable change is that the input arguments are changed, because GL
gets confused if you put a mat4 at the end.
2024-01-07 07:22:50 +01:00
Benjamin Otte 16c804c5e3 gpu: Handle nested buffer writes
when doing get_node_as_image(), that may spawn a new buffer writer that
writes into the samme buffer when rendering an offscreen with patterns.

So as a more or less hacky workaround, we now abort the current buffer
write and restart it once we've created the image.
2024-01-07 07:22:50 +01:00
Benjamin Otte 28f4666366 gpu: Implement conic gradients 2024-01-07 07:22:50 +01:00
Benjamin Otte 72a5927d38 gpu: Add radial gradients 2024-01-07 07:22:50 +01:00
Benjamin Otte 7473617ffb gpu: Add linear gradients to pattern shader
This copy/pastes the gist of the Vulkan gradient renderer.
2024-01-07 07:22:50 +01:00
Benjamin Otte 7d43e4e56a gpu: Add glyphs support
This is very rudimentary, but it's a step in the direction of getting
text going.

There's lots of things missing still.
2024-01-07 07:22:50 +01:00
Benjamin Otte 8fd2a267ae gpu: Add a utility function for colors in patterns
... and use it.
2024-01-07 07:22:50 +01:00
Benjamin Otte 3809e6efb9 gpu: Add color-matrix handling to pattern shader 2024-01-07 07:22:50 +01:00
Benjamin Otte 9224efd95e gpu: Make pattern creation always succeed
If creation fails, create an offscreen image instead and draw that as a
texture.

Because offscreens basically always succeed, we can pretty much assume
success everywhere - apart from pattern creation functions that also
create images, because they can run out of shader space.
2024-01-07 07:22:50 +01:00
Benjamin Otte 4cbd384e39 gpu: Have a get_node_as_pattern() function
... and use it to replace all the individual parts of code that get the
node as a pattern.
2024-01-07 07:22:50 +01:00
Benjamin Otte 12010a597b gpu: Add a texture pattern
Needs a lot of infrastructure for handling images, but we're handling
images now.
2024-01-07 07:22:50 +01:00
Benjamin Otte 720ac700b3 gpu: Move the pattern code into the nodeprocessor
We need the nodeprocessor infrastructure to create patterns, so keeping
it in a different source file would just cause header headaches.
2024-01-07 07:22:50 +01:00
Benjamin Otte 373a6ab9f1 gpu: Add a texture cache
... and use it when drawing textures.

We'll need it in other places later, but for now that's what we have.
2024-01-07 07:22:50 +01:00
Benjamin Otte 57c1c95e75 gpu: Make frames carry a timestamp
Frames now carry a timestamp for when they are used.

This is mainly intended to attach timestamps to cached items (textures
or glyphs), but it could in theory also be used when profiling.

We use wallclock time here, not server time, because it's cheaper and
because we're more intereseted in the local machine we're rendering on.
2024-01-07 07:22:50 +01:00
Benjamin Otte ffc117564b gpu: Make patterns do opacity nodes
Of course, for now this only works for opacity nodes that contain color
nodes, but we're still building up to ore useful stuff here.
2024-01-07 07:22:50 +01:00
Benjamin Otte ee3367697d gpu: Move pattern code into its own file
Now we can extend the pattern creation easily - and we can add new
patterns quickly later.

Plus, we need to keep this file in sync with pattern.glsl and it's neat
when those 2 files reference only each other.
2024-01-07 07:22:50 +01:00
Benjamin Otte c6e19f0384 gpu: Add float array to shaders and add an ubershader
... and use it for a naive color node implementation using both
so I can test it actually works.
2024-01-07 07:22:50 +01:00
Benjamin Otte 9df265acdc gpu: Clip fallback nodes to current clip
Avoids uploading parts of the node that aren't visible.
2024-01-07 07:22:49 +01:00
Benjamin Otte 461d9b4052 gpu: Set scissor rect before clearing
The render area that restricts clearing on Vulkan needs to be respected
by the GL renderer, too.
2024-01-07 07:22:49 +01:00
Benjamin Otte 0ed45c5f40 gpu: Move global syncing out
This is necessary so that fallback code can properly sync itself,
instead of just add_node().

Fixes a bunch of glitches when fallbacks would be used.
2024-01-07 07:22:49 +01:00
Benjamin Otte 73ac2d0a1c gpu: Add a flip_y argument to shader execution
Because GL flips its shit sometimes (ie when it's the framebuffer),
pass the height of the target as the flip variable, so commands
that need to operate on the pixels can flip the y axis around this value.
2024-01-07 07:22:49 +01:00
Benjamin Otte 57ab670991 gpu: Add handling for (rounded) clip node(s)
This is again mostly a copy of the Vulkan renderer.

It's a bit awkward codewise with the new invalidation framework,
because we need to cache the previous values individually now,
but it's a lot more finegrained, and we don't emit globals multiple
times when clips are nested.
2024-01-07 07:22:49 +01:00
Benjamin Otte e2b5e0d17d gpu: Add scissor operation
Nothing is using it yet (we don't do clipping) apart from initializing
the scissor rect at startup.
2024-01-07 07:22:49 +01:00
Benjamin Otte 77e05a4240 gpu: Add support for transform nodes
This essentially copies the Vulkan renderer machinery, but adapts it to
the new handling with pending globals.
2024-01-07 07:22:49 +01:00
Benjamin Otte 97c5bb284b gpu: Document the coordinate systems we use 2024-01-07 07:22:49 +01:00
Benjamin Otte 286b473f55 gpu: Add gsk_gpu_image_get_projection_matrix()
... and use it to initialize the "proper" projection matrix to use in
shaders.

The resulting viewport will go from top left (0,0) to bottom right
(width, height) and the z clipping plane will go from -10000 to 10000.
2024-01-07 07:22:49 +01:00
Benjamin Otte 1152c93778 gpu: Handle container nodes
Now everything is slower because we upload every other node
individually!
2024-01-07 07:22:49 +01:00
Benjamin Otte 1a85d569e3 gpu: Add ability to run shaders
This heaves over an inital chunk of code from the Vulkan renderer to
execute shaders.

The only shader that exists for now is a shader that draws a single
texture.
We use that to replace the blit op we were doing before.
2024-01-07 07:22:49 +01:00
Benjamin Otte bd114ab1a8 inspector: Learn about new renderers 2024-01-07 07:22:49 +01:00
Benjamin Otte 7a1f764910 gsk: Add new renderers to the GSK_RENDERER env var
Use:
  "ngl" for the new GL renderer
  "vulkan" for the new Vulkan renderer
2024-01-07 07:22:49 +01:00
Benjamin Otte 10f934f782 node-editor: Add the new renderer(s) 2024-01-07 07:22:49 +01:00
Benjamin Otte 97c60b84c8 gl: Undeprecate the NGL renderer for now
It's used for the new GPU renderer.
2024-01-07 07:22:49 +01:00
Benjamin Otte bf89431464 gpu: Use gdk_draw_context_empty_frame() when appropriate
It's a new function, so make use of it.
2024-01-07 07:22:49 +01:00
Benjamin Otte 9ddae8aebc gpu: Add outline of new GPU renderer
For now, it just renders using cairo, uploads the result to the GPU,
blits it onto the framebuffer and then is happy.

But it can do that using Vulkan and using GL (no idea which version).

The most important thing still missing is shaders.

It also has a bunch of copy/paste from the Vulkan renderer that isn't
used yet.
But I didn't want to rip it out and then try to copy it back later
2024-01-07 07:22:49 +01:00
Benjamin Otte e3c70645f9 vulkan: Turn Vulkan instances into init/ref/unref
This is not yet used.
2024-01-07 07:22:49 +01:00
Benjamin Otte 1e54e838e0 vulkan: Remove GskVulkanRenderer
We want to introduce a new one next.

Technically, this breaks API, because gsk_vulkan_renderer_new() is going
away, but practically, we're gonna bring it back once we introduce that
renderer in a few commits.
2024-01-07 07:22:49 +01:00
Benjamin Otte 40854f2ae9 gsk: Add header guard to missing header 2024-01-07 07:22:49 +01:00
Matthias Clasen 5e8e877f95 Merge branch 'matthiasc/for-main' into 'main'
rect: Annotate some functions as pure

See merge request GNOME/gtk!6713
2024-01-06 22:47:49 +00:00
Matthias Clasen 99844c8ccf rect: Annotate some functions as pure
gdk_rectangle_equal and gdk_rectangle_contains_point are pure.
2024-01-06 17:18:18 -05:00
Matthias Clasen 8418e4276a Merge branch 'matthiasc/for-main' into 'main'
gdk: Make a warning more useful

See merge request GNOME/gtk!6712
2024-01-06 20:43:43 +00:00
Matthias Clasen 7693e7133d inspector: Reorder the general tab
Put the devices below the monitors, for a more logical arrangement.
2024-01-06 09:49:37 -05:00
Matthias Clasen e56f9dbeb8 inspector: Drop a size group
All this size group did was causing values to be needlessly
ellipsized. Drop it.
2024-01-06 09:49:37 -05:00
Matthias Clasen 282d66a604 inspector: Clean up the general tab
Put the Wayland protocols, GL and Vulkan extensions behind expanders,
so we have less scrolling surface by default.
2024-01-06 09:49:37 -05:00
Matthias Clasen 3f513f3cc7 x11: Add a forgotten empty_frame implementation
This was causing warnings when using GLX.
2024-01-06 09:36:25 -05:00
Matthias Clasen 854910cc17 gdk: Make a warning more useful
We can just print out what is missing where, instead of a riddle.
2024-01-06 09:36:25 -05:00
Matthias Clasen 6bc7ec3d4d Merge branch 'fix-docs-links' into 'main'
docs: Fix: gdk->gtk links

See merge request GNOME/gtk!6711
2024-01-05 20:10:33 +00:00
Matthias Clasen bda6530fea docs: Fix: gsk->gtk links
gi-docgen can only generate links for dependencies, so we have
to manually expand to a relative url here.
2024-01-05 14:57:16 -05:00
Matthias Clasen 6227592dfa docs: Fix: gdk->gtk and gdk->gsk links
gi-docgen can only generate links for dependencies, so we have
to manually expand to a relative url here.

fixup
2024-01-05 14:57:07 -05:00
Matthias Clasen bc066de998 Merge branch 'wip/chergert/fix-6308' into 'main'
texthistory: fix potential NULL dereference

Closes #6308

See merge request GNOME/gtk!6709
2024-01-05 16:43:19 +00:00
Benjamin Otte 68980a5e3b Merge branch 'wip/otte/for-main' into 'main'
testsuite: Add a test for a recent mipmap generation bug

See merge request GNOME/gtk!6710
2024-01-05 07:28:19 +00:00
Benjamin Otte f200e8b132 reftests: Add a testcase for GtkGLArea::allowed-apis
See code comments for how it uses GL commands that should fail with GLES.

Related: !6520
2024-01-05 07:30:38 +01:00
Benjamin Otte dde2d9b545 gl: Don't initialize texture storage in wrong format
We're calling glTexImage2D() right after with the correct format.

So add the special format "0" to avoid intializing the texture memory.
2024-01-05 07:20:32 +01:00
Benjamin Otte ac64948efd testsuite: Add a test for a recent mipmap generation bug
Tests the fix in ab1fba6fdc.

Related: #6298
Related: !6704
2024-01-05 07:20:32 +01:00
Christian Hergert dfe2141227 texthistory: fix potential NULL dereference
Fixes #6308
2024-01-04 09:40:04 -08:00
Emmanuele Bassi 1e1c973d71 Merge branch 'ebassi/doc-link-fixes' into 'main'
docs: Use second level headings for sections

See merge request GNOME/gtk!6708
2024-01-04 14:48:38 +00:00
Emmanuele Bassi b69898228d docs: Use second level headings for sections
The first level heading should be reserved for the class description.
2024-01-04 13:48:29 +00:00
Emmanuele Bassi 9c71469c67 docs: Fix link to GtkLabel.set_mnemonic_widget() 2024-01-04 13:48:06 +00:00
Emmanuele Bassi a8b1c90303 docs: Fix link to GtkSnapshot.restore() 2024-01-04 13:47:29 +00:00
Matthias Clasen 69ffaab09f Merge branch 'reduce-shortcuts-searchentry-width' into 'main'
shortcutswindow: Reduce default width of search entry

See merge request GNOME/gtk!6707
2024-01-04 13:42:18 +00:00
Mohammed Sadiq 9730d44252 shortcutswindow: Reduce default width of search entry
Reduce the default width of search entry so that it fits on smaller
screens (ie, screens having 360px or less width).  Also, set max width
to the old value of 40, so that the search entry will have the same
old size if window width permits.

This commit won't make any difference on larger screens.
2024-01-04 18:51:42 +05:30
Matthias Clasen f99e725391 Merge branch 'fix-dropdown-checkmark' into 'main'
dropdown: Fix initial checkmark

Closes #6305

See merge request GNOME/gtk!6705
2024-01-04 03:22:25 +00:00
Matthias Clasen 8e4a42a214 dropdown: Fix initial checkmark
When the ::bind signal is emitted, the list item may not be added
to the list view yet, so we can't consult the widget hierarchy at
that point to decide whether to show or hide the icon. List for
notify::root instead.

Fixes: #6305
2024-01-03 14:58:49 -05:00
Matthias Clasen 603de8361c Merge branch 'mipmap-fixes' into 'main'
Mipmap handling fixes

Closes #6298

See merge request GNOME/gtk!6704
2024-01-03 18:06:23 +00:00
Matthias Clasen 51fd7cf35a Merge branch 'wip/otte/for-main' into 'main'
testsuite: Replace g_random_*() with g_test_rand_*()

See merge request GNOME/gtk!6703
2024-01-03 17:50:29 +00:00
Matthias Clasen ab1fba6fdc gl: When loading a texture, really create a mipmap
If we need a mipmap, and we find an existing texture that can't
mipmap, we need to recreate it.
2024-01-03 12:26:13 -05:00
Matthias Clasen cfa53de9af gl: Check if texture has a mipmap
When reusing an exiting texture, check if it has a mipmap, in case
we need one.
2024-01-03 12:22:28 -05:00
Matthias Clasen 3ebbcc981a Annotate gtk_ordering_from_cmpfunc as skip
We do extra work here to make the introspection scanner pick up
the docs for the static inline function, but that doesn't make the
function actually work in language bindings, so mark it as skip.

Fixes: #6298
2024-01-03 11:43:37 -05:00
Benjamin Otte 96a71d515b gl: Track if mipmap generation is allowed
... and if it isn't, switch to a format that does allow mipmaps.
2024-01-03 16:56:43 +01:00
Benjamin Otte b830ca8fab gl: Pass correct format/type to function
Instead of querying the format again and potentially coming out with a
different format, use the one we queried in the calling function.
2024-01-03 16:56:31 +01:00
Benjamin Otte 825c97be6c glcontext: Mark RGB16F as not renderable
According to EXT_color_buffer_half_float it should be renderable, but it
fails to glGenerateMipmap() with Mesa 23.3 so just pretend it's not
renderable until that is fixed.

Fixes CI from failing.
2024-01-03 16:05:25 +01:00
Benjamin Otte 25f99f35f6 glcontext: RGB32F is not renderable
I naively assumed the EXT_color_buffer_float and
EXT_color_buffer_half_float extensions would mirror each other, but they
do not. The float extension explicitly excludes RGB32F from the
renderable formats.
2024-01-03 16:05:25 +01:00
Benjamin Otte b719f3bd60 glcontext: Fix a mixup of flags
I swapped RENDERABLE and FILTERABLE when building this table.
2024-01-03 16:05:25 +01:00
Benjamin Otte b16d01e018 testsuite: Replace g_random_*() with g_test_rand_*()
... in the whole testsuite
2024-01-03 16:05:25 +01:00
Matthias Clasen c56360f20b Merge branch 'matthiasc/for-main' into 'main'
gsk: Mark some subsurface node apis as skip

See merge request GNOME/gtk!6702
2024-01-03 14:09:38 +00:00
Matthias Clasen 726d5b25e8 Merge branch 'bilelmoussaoui/add-missing-annotations' into 'main'
gi: Add missing Since annotations

See merge request GNOME/gtk!6701
2024-01-03 13:35:44 +00:00
Matthias Clasen 681aac7317 gsk: Mark some subsurface node apis as skip
These are not usable outside of GTK, so lets not burden bindings
with them.

I'll keep the get_child() function exposed, since it is needed to
iterate over node trees containing subsurface nodes.
2024-01-03 07:53:27 -05:00
Bilal Elmoussaoui 2cd550cdbc gi: Add missing Since annotations 2024-01-03 08:49:39 +01:00
Benjamin Otte 766048b8e4 Merge branch 'wip/otte/for-main' into 'main'
testsuite: Add a test for conic gradients

See merge request GNOME/gtk!6700
2024-01-03 04:37:00 +00:00
Benjamin Otte 63615c05bc rendernode: Allocate right amount of memory
asan randomly failed when this almost correct code wasn't quite correct.

Hopefully this is the correct incantation to compute the size.

Related: glib#205
2024-01-03 05:01:08 +01:00
Benjamin Otte cdf5d08294 rendernode: Fix a memleak 2024-01-03 04:58:08 +01:00
Benjamin Otte 3e4d0b69d4 gdkpng: Make the png loader safer against overflows
Load images that result in a texture >4GB in size.

And now let me keep playing with my 60k x 60k image, thanks.
I'm trying to OOM my GPU.
2024-01-03 04:11:35 +01:00
Benjamin Otte 7742434dde rendernode: Allow drawing oversized textures
Create surfaces for tiles of the image and then combine those tiles.

Use an offscreen and OPERATOR_ADD to avoid seams.
2024-01-03 04:11:35 +01:00
Benjamin Otte f0e6c03d94 testsuite: Add a test for pixel alignment of offscreens
The test ensures that offscreens render to the same pixel grid as the
actual image, and they are not offset by fractions of a pixel.

The Cairo renderer fails here because Cairo's clipping code rounds pixel
values wrong.
2024-01-03 04:11:35 +01:00
Benjamin Otte 09882701c2 rendernode: Fix various places where clip was double applied
This is mostly untested and a result of reading the code.

The main effect here happens when a node was drawn that didn't start on
an integer boundary, which is very rare.
However, with specially crafted tests and when using fractional scaling,
this can happen.

This happened most often when clipping by the node bounds to restrict a
push_group() call. Enlarge that rectangle to fall on a pixel boundary.
2024-01-03 04:11:35 +01:00
Benjamin Otte a19bc6620a rendernode: Apply the same radius for begin and end
Somebody fixed the end() call but not the begin() call when the too
large blur radius was fixed.
2024-01-03 04:11:35 +01:00
Benjamin Otte da5de1ba99 nodeparser: Fix SEGV in shadows parsing code
Testcase included

The code was writing invalid memory, so this might not have always
crashed, but I did my best to write the test so it causes a SEGV.

Also included is a fix for the testsuite where the expected result was
wrong.
2024-01-03 04:11:35 +01:00
Benjamin Otte e9d2f832a1 testsuite: Add a test for a clipping cornercase
If the new clip cannot intersect with the old clip and there is a global
opacity setting, things can go wrong.

So test that they don't.
2024-01-03 04:11:35 +01:00
Benjamin Otte 4fac0f713a testsuite: Add clipped overly large paths
... to make sure that renderers clip any masks they generate for paths.
2024-01-03 04:11:35 +01:00
Benjamin Otte fff8198393 testsuite: GTK_MODULES doesn't exist anymore 2024-01-03 04:11:34 +01:00
Benjamin Otte df2cbb4e9f testsuite: make compare-render --replay store results
The replayed node/images weren't saved.

I wanted to check that an optimization is done when replaying a test,
but without a saved node file, I couldn't.
2024-01-03 04:11:34 +01:00
Benjamin Otte 2990c1d8d8 testsuite: Add a test for conic gradients
Make all colorstops red, so that it's obvious what color each pixel is.
2024-01-03 04:11:34 +01:00
Benjamin Otte 4b5adcd374 testsuite: Fix CRC error in reference image
How did that get there?
2024-01-03 04:11:34 +01:00
Matthias Clasen 0b861cf159 Post-release version bump 2023-12-30 21:31:43 -05:00
Daniel Boles 473881357c Notebook: Update doc on how to accept dropped tabs
It was still giving out-of-date info about how GTK3 did this. Update per
reading the current code, so readers have proper guidance on doing this.
2023-10-02 16:39:49 +01:00
467 changed files with 38329 additions and 18055 deletions
+2 -1
View File
@@ -19,6 +19,7 @@ flatpak build ${builddir} meson \
--buildtype=debugoptimized \
-Dx11-backend=true \
-Dwayland-backend=true \
-Dvulkan=disabled \
-Dbuild-tests=false \
-Dbuild-testsuite=false \
-Dbuild-examples=false \
@@ -27,7 +28,7 @@ flatpak build ${builddir} meson \
-Ddemo-profile=devel \
_flatpak_build
flatpak build ${builddir} ninja -C _flatpak_build install
flatpak build --env=CI_COMMIT_SHORT_SHA=$CI_COMMIT_SHORT_SHA ${builddir} ninja -C _flatpak_build install
flatpak-builder \
--user --disable-rofiles-fuse \
+1 -1
View File
@@ -6,7 +6,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliar
:: FIXME: make warnings fatal
pip3 install --upgrade --user meson~=0.64 || goto :error
meson setup -Dbackend_max_links=1 -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
meson setup -Dbackend_max_links=1 -Ddebug=false -Dmedia-gstreamer=disabled -Dvulkan=disabled _build || goto :error
ninja -C _build || goto :error
goto :EOF
+2 -2
View File
@@ -33,7 +33,8 @@ pacman --noconfirm -S --needed \
mingw-w64-$MSYS2_ARCH-gst-plugins-bad-libs \
mingw-w64-$MSYS2_ARCH-shared-mime-info \
mingw-w64-$MSYS2_ARCH-python-gobject \
mingw-w64-$MSYS2_ARCH-shaderc
mingw-w64-$MSYS2_ARCH-shaderc \
mingw-w64-$MSYS2_ARCH-vulkan
mkdir -p _ccache
export CCACHE_BASEDIR="$(pwd)"
@@ -47,7 +48,6 @@ meson \
-Dx11-backend=false \
-Dwayland-backend=false \
-Dwin32-backend=true \
-Dvulkan=disabled \
-Dintrospection=enabled \
-Dgtk:werror=true \
_build
+1 -1
View File
@@ -213,7 +213,7 @@ Closes #1234
`git commit -a --author "Joe Coder <joe@coder.org>"` and `--signoff`.
- If your commit is addressing an issue, use the
[GitLab syntax](https://docs.gitlab.com/ce/user/project/issues/automatic_issue_closing.html)
[GitLab syntax](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
to automatically close the issue when merging the commit with the upstream
repository:
+50 -4
View File
@@ -1,3 +1,49 @@
Overview of Changes in 4.13.6, xx-xx-xxxx
=========================================
Overview of Changes in 4.13.5, 07-01-2024
=========================================
This release adds two new GSK renderers called vulkan and ngl,
that are built from the same sources. The new renderers can
handle many corner cases correctly that the current gl renderer
does not handle, and they offer advantages such as antialiasing
and supersampled gradients.
The new renderers are still considered experimental, and GTK
will only use them if they are explicitly selected using the
GSK_RENDERER environment variable.
As part of this work, the GSK include files have been rearranged.
It is no longer necessary to include renderer-specific headers for
ngl and vulkan (and doing so will trigger deprecation warnings),
and their constructors are always available.
The previously available experimental GdkVulkanContext APIs and
the old Vulkan renderer have been removed.
Vulkan is now enabled by default, and Linux distributions should
build GTK with Vulkan support. This requires the glslc shader
compiler as a new dependency.
Vulkan is now also used for dmabuf support.
* GtkDropdown:
- Fix display of initial selection
* GtkShortcutsWindow:
- Make the window adapt to smaller screen widths
* GtkTextView:
- Fix a possible NULL dereference in history
* GDK:
- Make the png loader safer against overflows
* GL:
- Fix some errors in handling of texture formats and mipmaps
Overview of Changes in 4.13.4, 30-12-2023
=========================================
@@ -476,7 +522,7 @@ Overview of Changes in 4.11.4, 03-07-2023
- Center newly created transient windows
* Vulkan:
- Add antialising for gradients
- Add antialiasing for gradients
- Do less work on clipped away nodes
- Redo image uploading
- Support different image depths and formats
@@ -1460,7 +1506,7 @@ Overview of Changes in 4.7.0, 07-05-2022
- Event handling fixes
- Fix keyboard input on popovers
- Support OpenGL-based video playback
- Suport fullscreen
- Support fullscreen
- Improve native filechoooser size allocation
- Use CALayer and IOSurface for rendering
- Use a per-monitor CVDisplayLink
@@ -1857,7 +1903,7 @@ Overview of Changes in 4.4.0
- Activate when moving focus
* GtkLabel:
- Propertly ignore double underscores for mnemonics
- Properly ignore double underscores for mnemonics
* GtkPopoverMenu:
- Fix focus cycling
@@ -2404,7 +2450,7 @@ Overview of Changes in 4.1.0
- Set sort arrows in CSS
- Set menu button arrows in CSS
- Make scrollbars larger
- Supprt circular menubuttons
- Support circular menubuttons
* CSS:
- Implement transform-origin
+1 -1
View File
@@ -1586,7 +1586,7 @@ update_font_variations (void)
}
gtk_grid_attach (GTK_GRID (demo->variations_grid), combo, 1, -1, 3, 1);
g_signal_connect (combo, "notify::selecte", G_CALLBACK (instance_changed), NULL);
g_signal_connect (combo, "notify::selected", G_CALLBACK (instance_changed), NULL);
demo->instance_combo = combo;
}
+1 -1
View File
@@ -24,7 +24,7 @@
#include "demos.h"
#include "fontify.h"
#include "demo_conf.h"
#include "profile_conf.h"
static GtkWidget *info_view;
static GtkWidget *source_view;
+1 -1
View File
@@ -236,7 +236,7 @@ foreach flag: common_cflags
endif
endforeach
gtkdemo_deps += [ demo_conf_h ]
gtkdemo_deps += [ profile_conf_h ]
executable('gtk4-demo',
sources: [demos, demos_h, extra_demo_sources, gtkdemo_resources],
+23 -16
View File
@@ -53,7 +53,9 @@ gtk_nuclear_snapshot (GtkSnapshot *snapshot,
double rotation)
{
#define RADIUS 0.3
cairo_t *cr;
GskPathBuilder *builder;
GskPath *path;
GskStroke *stroke;
double size;
gtk_snapshot_append_color (snapshot,
@@ -61,24 +63,29 @@ gtk_nuclear_snapshot (GtkSnapshot *snapshot,
&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);
cairo_arc (cr, 0, 0, 0.1, - G_PI, G_PI);
cairo_fill (cr);
gtk_snapshot_save (snapshot);
cairo_set_line_width (cr, RADIUS);
cairo_set_dash (cr, (double[1]) { RADIUS * G_PI / 3 }, 1, 0.0);
cairo_arc (cr, 0, 0, RADIUS, - G_PI, G_PI);
cairo_stroke (cr);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width / 2.0, height / 2.0));
gtk_snapshot_scale (snapshot, size, size);
gtk_snapshot_rotate (snapshot, rotation);
cairo_destroy (cr);
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, graphene_point_zero (), 0.1);
path = gsk_path_builder_free_to_path (builder);
gtk_snapshot_append_fill (snapshot, path, GSK_FILL_RULE_WINDING, foreground);
gsk_path_unref (path);
stroke = gsk_stroke_new (RADIUS);
gsk_stroke_set_dash (stroke, (float[1]) { RADIUS * G_PI / 3 }, 1);
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, graphene_point_zero(), RADIUS);
path = gsk_path_builder_free_to_path (builder);
gtk_snapshot_append_stroke (snapshot, path, stroke, foreground);
gsk_path_unref (path);
gsk_stroke_free (stroke);
gtk_snapshot_restore (snapshot);
}
/* Here, we implement the functionality required by the GdkPaintable interface */
+2 -2
View File
@@ -70,7 +70,7 @@ gtk_nuclear_animation_snapshot (GdkPaintable *paintable,
? &(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);
360 * nuclear->progress / MAX_PROGRESS);
}
static GdkPaintable *
@@ -85,7 +85,7 @@ gtk_nuclear_animation_get_current_image (GdkPaintable *paintable)
* Luckily we added the rotation property to the nuclear icon
* object previously, so we can just return an instance of that one.
*/
return gtk_nuclear_icon_new (2 * G_PI * nuclear->progress / MAX_PROGRESS);
return gtk_nuclear_icon_new (360 * nuclear->progress / MAX_PROGRESS);
}
static GdkPaintableFlags
+2 -2
View File
@@ -76,7 +76,7 @@ gtk_nuclear_media_stream_snapshot (GdkPaintable *paintable,
&(GdkRGBA) { 0, 0, 0, 1 }, /* black */
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 }, /* yellow */
width, height,
2 * G_PI * nuclear->progress / DURATION);
360 * nuclear->progress / DURATION);
}
static GdkPaintable *
@@ -85,7 +85,7 @@ gtk_nuclear_media_stream_get_current_image (GdkPaintable *paintable)
GtkNuclearMediaStream *nuclear = GTK_NUCLEAR_MEDIA_STREAM (paintable);
/* Same thing as with the animation */
return gtk_nuclear_icon_new (2 * G_PI * nuclear->progress / DURATION);
return gtk_nuclear_icon_new (360 * nuclear->progress / DURATION);
}
static GdkPaintableFlags
+1 -1
View File
@@ -4,7 +4,7 @@
#include "iconbrowserapp.h"
#include "iconbrowserwin.h"
#include "demo_conf.h"
#include "profile_conf.h"
struct _IconBrowserApp
{
+1 -1
View File
@@ -14,7 +14,7 @@ iconbrowser_resources = gnome.compile_resources('iconbrowser_resources',
executable('gtk4-icon-browser',
sources: [iconbrowser_sources, iconbrowser_resources],
c_args: common_cflags,
dependencies: [ libgtk_dep, demo_conf_h ],
dependencies: [ libgtk_dep, profile_conf_h ],
include_directories: confinc,
win_subsystem: 'windows',
link_args: extra_demo_ldflags,
-13
View File
@@ -1,16 +1,3 @@
gen_demo_header = find_program('../build-aux/meson/gen-demo-header.py')
demo_profile = get_option('demo-profile')
demo_conf_h = declare_dependency(
sources: custom_target('demo-header',
command: [gen_demo_header, meson.project_source_root(), demo_profile],
capture: true,
output: 'demo_conf.h',
build_by_default: true,
build_always_stale: true,
)
)
# appdata
appdata_config = configuration_data()
+1 -1
View File
@@ -12,7 +12,7 @@ node_editor_resources = gnome.compile_resources('node_editor_resources',
executable('gtk4-node-editor',
sources: [node_editor_sources, node_editor_resources],
dependencies: [ libgtk_dep, demo_conf_h ],
dependencies: [ libgtk_dep, profile_conf_h ],
include_directories: confinc,
c_args: common_cflags,
win_subsystem: 'windows',
+59 -5
View File
@@ -19,11 +19,13 @@
#include "config.h"
#include <glib/gstdio.h>
#include "node-editor-application.h"
#include "node-editor-window.h"
#include "demo_conf.h"
#include "profile_conf.h"
static const char *css =
"textview.editor {"
@@ -247,11 +249,63 @@ node_editor_application_class_init (NodeEditorApplicationClass *class)
application_class->open = node_editor_application_open;
}
static void
print_version (void)
{
g_print ("gtk4-node-editor %s%s%s\n",
PACKAGE_VERSION,
g_strcmp0 (PROFILE, "devel") == 0 ? "-" : "",
g_strcmp0 (PROFILE, "devel") == 0 ? VCS_TAG : "");
}
static int
local_options (GApplication *app,
GVariantDict *options,
gpointer data)
{
gboolean version = FALSE;
gboolean reset = FALSE;
g_variant_dict_lookup (options, "version", "b", &version);
if (version)
{
print_version ();
return 0;
}
g_variant_dict_lookup (options, "reset", "b", &reset);
if (reset)
{
char *path;
path = get_autosave_path ("-unsafe");
g_remove (path);
g_free (path);
path = get_autosave_path (NULL);
g_remove (path);
g_free (path);
}
return -1;
}
NodeEditorApplication *
node_editor_application_new (void)
{
return g_object_new (NODE_EDITOR_APPLICATION_TYPE,
"application-id", "org.gtk.gtk4.NodeEditor",
"flags", G_APPLICATION_HANDLES_OPEN,
NULL);
NodeEditorApplication *app;
app = g_object_new (NODE_EDITOR_APPLICATION_TYPE,
"application-id", "org.gtk.gtk4.NodeEditor",
"flags", G_APPLICATION_HANDLES_OPEN,
NULL);
g_application_add_main_option (G_APPLICATION (app), "version", 0, 0,G_OPTION_ARG_NONE, "Show program version", NULL);
g_application_add_main_option (G_APPLICATION (app), "reset", 0, 0,G_OPTION_ARG_NONE, "Remove autosave content", NULL);
g_signal_connect (app, "handle-local-options", G_CALLBACK (local_options), NULL);
return app;
}
+321 -97
View File
@@ -24,13 +24,11 @@
#include "gtkrendererpaintableprivate.h"
#include "gsk/gskrendernodeparserprivate.h"
#include "gsk/gl/gskglrenderer.h"
#ifdef GDK_WINDOWING_BROADWAY
#include "gsk/broadway/gskbroadwayrenderer.h"
#endif
#ifdef GDK_RENDERING_VULKAN
#include "gsk/vulkan/gskvulkanrenderer.h"
#endif
#include <glib/gstdio.h>
#include <cairo.h>
#ifdef CAIRO_HAS_SVG_SURFACE
@@ -59,6 +57,7 @@ struct _NodeEditorWindow
GtkWidget *testcase_name_entry;
GtkWidget *testcase_save_button;
GtkWidget *scale_scale;
GtkWidget *crash_warning;
GtkWidget *renderer_listbox;
GListStore *renderers;
@@ -68,6 +67,9 @@ struct _NodeEditorWindow
GFileMonitor *file_monitor;
GArray *errors;
guint update_timeout;
gboolean auto_reload;
};
struct _NodeEditorWindowClass
@@ -75,6 +77,13 @@ struct _NodeEditorWindowClass
GtkApplicationWindowClass parent_class;
};
enum {
PROP_AUTO_RELOAD = 1,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
G_DEFINE_TYPE(NodeEditorWindow, node_editor_window, GTK_TYPE_APPLICATION_WINDOW);
static void
@@ -167,19 +176,84 @@ text_iter_skip_whitespace_backward (GtkTextIter *iter)
}
static void
text_changed (GtkTextBuffer *buffer,
NodeEditorWindow *self)
highlight_text (NodeEditorWindow *self)
{
GtkTextIter iter;
GtkTextIter start, end;
gtk_text_buffer_get_start_iter (self->text_buffer, &iter);
while (!gtk_text_iter_is_end (&iter))
{
gunichar c = gtk_text_iter_get_char (&iter);
if (c == '{')
{
GtkTextIter word_end = iter;
GtkTextIter word_start;
gtk_text_iter_backward_char (&word_end);
text_iter_skip_whitespace_backward (&word_end);
word_start = word_end;
gtk_text_iter_backward_word_start (&word_start);
text_iter_skip_alpha_backward (&word_start);
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "nodename", &word_start, &word_end);
}
else if (c == ':')
{
GtkTextIter word_end = iter;
GtkTextIter word_start;
gtk_text_iter_backward_char (&word_end);
text_iter_skip_whitespace_backward (&word_end);
word_start = word_end;
gtk_text_iter_backward_word_start (&word_start);
text_iter_skip_alpha_backward (&word_start);
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "propname", &word_start, &word_end);
}
else if (c == '"')
{
GtkTextIter string_start = iter;
GtkTextIter string_end = iter;
gtk_text_iter_forward_char (&iter);
while (!gtk_text_iter_is_end (&iter))
{
c = gtk_text_iter_get_char (&iter);
if (c == '"')
{
gtk_text_iter_forward_char (&iter);
string_end = iter;
break;
}
gtk_text_iter_forward_char (&iter);
}
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "string", &string_start, &string_end);
}
gtk_text_iter_forward_char (&iter);
}
gtk_text_buffer_get_bounds (self->text_buffer, &start, &end);
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "no-hyphens", &start, &end);
}
static void
reload (NodeEditorWindow *self)
{
char *text;
GBytes *bytes;
GtkTextIter iter;
GtkTextIter start, end;
float scale;
GskRenderNode *big_node;
g_array_remove_range (self->errors, 0, self->errors->len);
text = get_current_text (self->text_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);
@@ -240,73 +314,19 @@ text_changed (GtkTextBuffer *buffer,
}
g_clear_pointer (&big_node, gsk_render_node_unref);
}
gtk_text_buffer_get_start_iter (self->text_buffer, &iter);
static void
text_changed (GtkTextBuffer *buffer,
NodeEditorWindow *self)
{
g_array_remove_range (self->errors, 0, self->errors->len);
text_buffer_remove_all_tags (self->text_buffer);
while (!gtk_text_iter_is_end (&iter))
{
gunichar c = gtk_text_iter_get_char (&iter);
if (self->auto_reload)
reload (self);
if (c == '{')
{
GtkTextIter word_end = iter;
GtkTextIter word_start;
gtk_text_iter_backward_char (&word_end);
text_iter_skip_whitespace_backward (&word_end);
word_start = word_end;
gtk_text_iter_backward_word_start (&word_start);
text_iter_skip_alpha_backward (&word_start);
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "nodename",
&word_start, &word_end);
}
else if (c == ':')
{
GtkTextIter word_end = iter;
GtkTextIter word_start;
gtk_text_iter_backward_char (&word_end);
text_iter_skip_whitespace_backward (&word_end);
word_start = word_end;
gtk_text_iter_backward_word_start (&word_start);
text_iter_skip_alpha_backward (&word_start);
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "propname",
&word_start, &word_end);
}
else if (c == '"')
{
GtkTextIter string_start = iter;
GtkTextIter string_end = iter;
gtk_text_iter_forward_char (&iter);
while (!gtk_text_iter_is_end (&iter))
{
c = gtk_text_iter_get_char (&iter);
if (c == '"')
{
gtk_text_iter_forward_char (&iter);
string_end = iter;
break;
}
gtk_text_iter_forward_char (&iter);
}
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "string",
&string_start, &string_end);
}
gtk_text_iter_forward_char (&iter);
}
gtk_text_buffer_get_bounds (self->text_buffer, &start, &end);
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "no-hyphens",
&start, &end);
highlight_text (self);
}
static void
@@ -794,7 +814,7 @@ create_cairo_texture (NodeEditorWindow *self)
return NULL;
renderer = gsk_cairo_renderer_new ();
gsk_renderer_realize (renderer, NULL, NULL);
gsk_renderer_realize_for_display (renderer, gtk_widget_get_display (GTK_WIDGET (self)), NULL);
texture = gsk_renderer_render_texture (renderer, node, NULL);
gsk_render_node_unref (node);
@@ -866,11 +886,11 @@ export_image_response_cb (GObject *source,
GskRenderer *renderer;
renderer = gsk_gl_renderer_new ();
if (!gsk_renderer_realize (renderer, NULL, NULL))
if (!gsk_renderer_realize_for_display (renderer, gdk_display_get_default (), NULL))
{
g_object_unref (renderer);
renderer = gsk_cairo_renderer_new ();
if (!gsk_renderer_realize (renderer, NULL, NULL))
if (!gsk_renderer_realize_for_display (renderer, gdk_display_get_default (), NULL))
{
g_assert_not_reached ();
}
@@ -1105,6 +1125,9 @@ node_editor_window_finalize (GObject *object)
{
NodeEditorWindow *self = (NodeEditorWindow *)object;
if (self->update_timeout)
g_source_remove (self->update_timeout);
g_array_free (self->errors, TRUE);
g_clear_pointer (&self->node, gsk_render_node_unref);
@@ -1121,8 +1144,11 @@ node_editor_window_add_renderer (NodeEditorWindow *self,
const char *description)
{
GdkPaintable *paintable;
GdkDisplay *display;
if (!gsk_renderer_realize (renderer, NULL, NULL))
display = gtk_widget_get_display (GTK_WIDGET (self));
if (!gsk_renderer_realize_for_display (renderer, display, NULL))
{
GdkSurface *surface = gtk_native_get_surface (GTK_NATIVE (self));
g_assert (surface != NULL);
@@ -1157,6 +1183,9 @@ node_editor_window_realize (GtkWidget *widget)
node_editor_window_add_renderer (self,
gsk_gl_renderer_new (),
"OpenGL");
node_editor_window_add_renderer (self,
gsk_ngl_renderer_new (),
"NGL");
#ifdef GDK_RENDERING_VULKAN
node_editor_window_add_renderer (self,
gsk_vulkan_renderer_new (),
@@ -1538,6 +1567,79 @@ edit_action_cb (GtkWidget *widget,
node_editor_window_edit (self, &start);
}
static void
node_editor_window_map (GtkWidget *widget)
{
char *path;
GTK_WIDGET_CLASS (node_editor_window_parent_class)->map (widget);
path = get_autosave_path (NULL);
if (g_file_test (path, G_FILE_TEST_EXISTS))
{
g_free (path);
return;
}
g_free (path);
}
static void
node_editor_window_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NodeEditorWindow *self = NODE_EDITOR_WINDOW (object);
switch (prop_id)
{
case PROP_AUTO_RELOAD:
{
gboolean auto_reload = g_value_get_boolean (value);
if (self->auto_reload != auto_reload)
{
self->auto_reload = auto_reload;
if (self->auto_reload)
reload (self);
}
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
node_editor_window_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NodeEditorWindow *self = NODE_EDITOR_WINDOW (object);
switch (prop_id)
{
case PROP_AUTO_RELOAD:
g_value_set_boolean (value, self->auto_reload);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
close_crash_warning (GtkButton *button,
NodeEditorWindow *self)
{
gtk_revealer_set_reveal_child (GTK_REVEALER (self->crash_warning), FALSE);
}
static void
node_editor_window_class_init (NodeEditorWindowClass *class)
{
@@ -1549,6 +1651,8 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
object_class->dispose = node_editor_window_dispose;
object_class->finalize = node_editor_window_finalize;
object_class->set_property = node_editor_window_set_property;
object_class->get_property = node_editor_window_get_property;
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/node-editor/node-editor-window.ui");
@@ -1556,6 +1660,14 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
widget_class->realize = node_editor_window_realize;
widget_class->unrealize = node_editor_window_unrealize;
widget_class->map = node_editor_window_map;
properties[PROP_AUTO_RELOAD] = g_param_spec_boolean ("auto-reload", NULL, NULL,
TRUE,
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, text_view);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, picture);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, renderer_listbox);
@@ -1565,6 +1677,7 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, testcase_name_entry);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, testcase_save_button);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, scale_scale);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, crash_warning);
gtk_widget_class_bind_template_callback (widget_class, text_view_query_tooltip_cb);
gtk_widget_class_bind_template_callback (widget_class, open_cb);
@@ -1577,6 +1690,7 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
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);
gtk_widget_class_bind_template_callback (widget_class, click_gesture_pressed);
gtk_widget_class_bind_template_callback (widget_class, close_crash_warning);
gtk_widget_class_install_action (widget_class, "smart-edit", NULL, edit_action_cb);
@@ -1628,11 +1742,133 @@ static GActionEntry win_entries[] = {
{ "open", window_open, NULL, NULL, NULL },
};
char *
get_autosave_path (const char *suffix)
{
char *path;
char *name;
name = g_strconcat ("autosave", suffix, NULL);
path = g_build_filename (g_get_user_cache_dir (), "gtk4-node-editor", name, NULL);
g_free (name);
return path;
}
static void
set_initial_text (NodeEditorWindow *self)
{
char *path, *path1;
char *initial_text;
gsize len;
path = get_autosave_path (NULL);
path1 = get_autosave_path ("-unsafe");
if (g_file_get_contents (path, &initial_text, &len, NULL))
{
gtk_text_buffer_set_text (self->text_buffer, initial_text, len);
g_free (initial_text);
}
else if (g_file_get_contents (path1, &initial_text, &len, NULL))
{
self->auto_reload = FALSE;
gtk_revealer_set_reveal_child (GTK_REVEALER (self->crash_warning), TRUE);
gtk_text_buffer_set_text (self->text_buffer, initial_text, len);
g_free (initial_text);
}
else
{
/* Default */
gtk_text_buffer_set_text (self->text_buffer,
"shadow {\n"
" child: texture {\n"
" bounds: 0 0 128 128;\n"
" texture: url(\"resource:///org/gtk/gtk4/node-editor/icons/apps/org.gtk.gtk4.NodeEditor.svg\");\n"
" }\n"
" shadows: rgba(0,0,0,0.5) 0 1 12;\n"
"}\n"
"\n"
"transform {\n"
" child: text {\n"
" color: rgb(46,52,54);\n"
" font: \"Cantarell Bold 11\";\n"
" glyphs: \"GTK Node Editor\";\n"
" offset: 8 14.418;\n"
" }\n"
" transform: translate(0, 140);\n"
"}", -1);
}
g_free (path);
g_free (path1);
}
static void
autosave_contents (NodeEditorWindow *self)
{
char *path = NULL;
char *dir = NULL;
char *contents;
GtkTextIter start, end;
gtk_text_buffer_get_bounds (self->text_buffer, &start, &end);
contents = gtk_text_buffer_get_text (self->text_buffer, &start, &end, TRUE);
path = get_autosave_path ("-unsafe");
dir = g_path_get_dirname (path);
g_mkdir_with_parents (dir, 0755);
g_file_set_contents (path, contents, -1, NULL);
g_free (dir);
g_free (path);
g_free (contents);
}
static void
mark_autosave_as_safe (void)
{
char *path1 = NULL;
char *path2 = NULL;
path1 = get_autosave_path ("-unsafe");
path2 = get_autosave_path (NULL);
g_rename (path1, path2);
}
static gboolean
update_timeout_cb (gpointer data)
{
NodeEditorWindow *self = data;
self->update_timeout = 0;
mark_autosave_as_safe ();
return G_SOURCE_REMOVE;
}
static void
initiate_autosave (NodeEditorWindow *self)
{
autosave_contents (self);
if (self->update_timeout != 0)
g_source_remove (self->update_timeout);
self->update_timeout = g_timeout_add (100, update_timeout_cb, self);
}
static void
node_editor_window_init (NodeEditorWindow *self)
{
GAction *action;
gtk_widget_init_template (GTK_WIDGET (self));
self->auto_reload = TRUE;
self->renderers = g_list_store_new (GDK_TYPE_PAINTABLE);
gtk_list_box_bind_model (GTK_LIST_BOX (self->renderer_listbox),
G_LIST_MODEL (self->renderers),
@@ -1645,6 +1881,10 @@ node_editor_window_init (NodeEditorWindow *self)
g_action_map_add_action_entries (G_ACTION_MAP (self), win_entries, G_N_ELEMENTS (win_entries), self);
action = G_ACTION (g_property_action_new ("auto-reload", self, "auto-reload"));
g_action_map_add_action (G_ACTION_MAP (self), action);
g_object_unref (action);
self->tag_table = gtk_text_tag_table_new ();
gtk_text_tag_table_add (self->tag_table,
g_object_new (GTK_TYPE_TEXT_TAG,
@@ -1682,25 +1922,9 @@ node_editor_window_init (NodeEditorWindow *self)
g_signal_connect (self->scale_scale, "notify::value", G_CALLBACK (scale_changed), self);
gtk_text_view_set_buffer (GTK_TEXT_VIEW (self->text_view), self->text_buffer);
/* Default */
gtk_text_buffer_set_text (self->text_buffer,
"shadow {\n"
" child: texture {\n"
" bounds: 0 0 128 128;\n"
" texture: url(\"resource:///org/gtk/gtk4/node-editor/icons/apps/org.gtk.gtk4.NodeEditor.svg\");\n"
" }\n"
" shadows: rgba(0,0,0,0.5) 0 1 12;\n"
"}\n"
"\n"
"transform {\n"
" child: text {\n"
" color: rgb(46,52,54);\n"
" font: \"Cantarell Bold 11\";\n"
" glyphs: \"GTK Node Editor\";\n"
" offset: 8 14.418;\n"
" }\n"
" transform: translate(0, 140);\n"
"}", -1);
set_initial_text (self);
g_signal_connect_swapped (self->text_buffer, "changed", G_CALLBACK (initiate_autosave), self);
if (g_getenv ("GSK_RENDERER"))
{
+2
View File
@@ -37,3 +37,5 @@ NodeEditorWindow * node_editor_window_new (NodeEditorApplication
gboolean node_editor_window_load (NodeEditorWindow *self,
GFile *file);
char * get_autosave_path (const char *suffix);
+113 -65
View File
@@ -2,6 +2,14 @@
<interface>
<menu id="gear_menu">
<section>
<item>
<attribute name="label" translatable="yes">_Reload automatically</attribute>
<attribute name="action">win.auto-reload</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Help</attribute>
<attribute name="action">app.help</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Help</attribute>
<attribute name="action">app.help</attribute>
@@ -24,7 +32,6 @@
</item>
</section>
</menu>
<object class="GtkPopover" id="testcase_popover">
<child>
<object class="GtkGrid">
@@ -39,7 +46,7 @@
<object class="GtkEntry" id="testcase_name_entry">
<property name="hexpand">1</property>
<property name="activates-default">1</property>
<signal name="notify::text" handler="testcase_name_entry_changed_cb" />
<signal name="notify::text" handler="testcase_name_entry_changed_cb"/>
</object>
</child>
<child>
@@ -52,7 +59,6 @@
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="wrap">1</property>
@@ -66,7 +72,6 @@
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="testcase_error_label">
<property name="wrap">1</property>
@@ -78,7 +83,6 @@
</layout>
</object>
</child>
<child>
<object class="GtkButton" id="testcase_save_button">
<property name="label">Save</property>
@@ -86,9 +90,9 @@
<property name="halign">end</property>
<property name="receives-default">1</property>
<property name="sensitive">0</property>
<signal name="clicked" handler="testcase_save_clicked_cb" />
<signal name="clicked" handler="testcase_save_clicked_cb"/>
<style>
<class name="suggested-action" />
<class name="suggested-action"/>
</style>
<layout>
<property name="row">4</property>
@@ -100,7 +104,6 @@
</object>
</child>
</object>
<template class="NodeEditorWindow" parent="GtkApplicationWindow">
<property name="title" translatable="yes">GTK Node Editor</property>
<property name="default-width">1024</property>
@@ -185,83 +188,128 @@
</object>
</child>
<child>
<object class="GtkPaned">
<property name="shrink-start-child">false</property>
<property name="shrink-end-child">false</property>
<property name="position">400</property>
<property name="start-child">
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkTextView" id="text_view">
<property name="wrap-mode">word</property>
<property name="monospace">1</property>
<property name="top-margin">6</property>
<property name="left-margin">6</property>
<property name="right-margin">6</property>
<property name="bottom-margin">6</property>
<property name="has-tooltip">1</property>
<property name="extra-menu">extra_menu</property>
<signal name="query-tooltip" handler="text_view_query_tooltip_cb"/>
<object class="GtkOverlay">
<child type="overlay">
<object class="GtkRevealer" id="crash_warning">
<property name="transition-type">slide-down</property>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="child">
<object class="GtkFrame">
<style>
<class name="editor" />
<class name="app-notification"/>
</style>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">20</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<child>
<object class="GtkLabel">
<property name="hexpand">1</property>
<property name="halign">1</property>
<property name="label" translatable="1">The application may have crashed.
As a precaution, auto-loading has been turned off.
</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="valign">3</property>
<property name="use-underline">1</property>
<property name="label" translatable="1">_Close</property>
<signal name="clicked" handler="close_crash_warning"/>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</child>
<property name="child">
<object class="GtkPaned">
<property name="shrink-start-child">false</property>
<property name="shrink-end-child">false</property>
<property name="position">400</property>
<property name="start-child">
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkGestureClick">
<property name="button">1</property>
<signal name="pressed" handler="click_gesture_pressed"/>
<object class="GtkTextView" id="text_view">
<property name="wrap-mode">word</property>
<property name="monospace">1</property>
<property name="top-margin">6</property>
<property name="left-margin">6</property>
<property name="right-margin">6</property>
<property name="bottom-margin">6</property>
<property name="has-tooltip">1</property>
<property name="extra-menu">extra_menu</property>
<signal name="query-tooltip" handler="text_view_query_tooltip_cb"/>
<style>
<class name="editor"/>
</style>
<child>
<object class="GtkGestureClick">
<property name="button">1</property>
<signal name="pressed" handler="click_gesture_pressed"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
<property name="end-child">
<object class="GtkBox">
<child>
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="min-content-height">100</property>
<property name="min-content-width">100</property>
</property>
<property name="end-child">
<object class="GtkBox">
<child>
<object class="GtkViewport">
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="min-content-height">100</property>
<property name="min-content-width">100</property>
<child>
<object class="GtkPicture" id="picture">
<property name="can-shrink">0</property>
<property name="halign">center</property>
<property name="valign">center</property>
<object class="GtkViewport">
<child>
<object class="GtkDragSource">
<object class="GtkPicture" id="picture">
<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>
<signal name="prepare" handler="on_picture_drag_prepare_cb" swapped="no"/>
<property name="formats">application/x-gtk-render-node</property>
<signal name="drop" handler="on_picture_drop_cb" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<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 class="GtkListBox" id="renderer_listbox">
<property name="selection-mode">none</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkListBox" id="renderer_listbox">
<property name="selection-mode">none</property>
</object>
</child>
</object>
</child>
</property>
</object>
</property>
</object>
+22 -10
View File
@@ -322,27 +322,39 @@ stroke bounds of the path.
### text
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| color | `<color>` | black | non-default |
| font | `<string>` | "Cantarell 11" | always |
| glyphs | `<glyphs>` | "Hello" | always |
| offset | `<point>` | 0 0 | non-default |
| property | syntax | default | printed |
| -------- | ------------------- | ------------------- | ----------- |
| color | `<color>` | black | non-default |
| font | `<string>` `<url>`? | "Cantarell 11" | always |
| glyphs | `<glyphs>` | "Hello" | always |
| offset | `<point>` | 0 0 | non-default |
Creates a node like `gsk_text_node_new()` with the given properties.
If a url is specified for the font, it must point to a font file for the
font that is specified in the string. It can be either a data url containing
a base64-encoded font file, or a regular url that points to a font file.
Glyphs can be specified as an ASCII string, or as a comma-separated list of
their glyph ID and advance width. Optionally, x and y offsets and flags can
be specified as well, like this: 40 10 0 0 color.
If the given font does not exist or the given glyphs are invalid for the given
font, an error node will be returned.
### texture
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| texture | `<url>` | *see below* | always |
| property | syntax | default | printed |
| -------- | ------------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| texture | `<string>`?`<url>`? | *see below* | always |
Creates a node like `gsk_texture_node_new()` with the given properties.
If a string is specified for the texture, it will be used as a name for the text.
Textures can be reused by specifying the name of a previously used texture. In
that case, the url can be omitted.
The default texture is a 10x10 checkerboard with the top left and bottom right
5x5 being in the color #FF00CC and the other part being transparent. A possible
representation for this texture is `url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABmJLR0QA/wD/AP+gvaeTAAAAKUlEQVQYlWP8z3DmPwMaYGQwYUQXY0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5CYII=")
+1 -1
View File
@@ -1,7 +1,7 @@
executable('gtk4-print-editor',
sources: ['print-editor.c'],
c_args: common_cflags,
dependencies: [ libgtk_dep, demo_conf_h ],
dependencies: [ libgtk_dep, profile_conf_h ],
include_directories: confinc,
win_subsystem: 'windows',
link_args: extra_demo_ldflags,
+1 -1
View File
@@ -4,7 +4,7 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "demo_conf.h"
#include "profile_conf.h"
static GtkWidget *main_window;
static GFile *filename = NULL;
+1 -1
View File
@@ -66,7 +66,7 @@ endif
executable('gtk4-widget-factory',
sources: ['widget-factory.c', widgetfactory_resources],
c_args: common_cflags,
dependencies: [ libgtk_dep, demo_conf_h ],
dependencies: [ libgtk_dep, profile_conf_h ],
include_directories: confinc,
win_subsystem: 'windows',
link_args: extra_demo_ldflags,
+1 -1
View File
@@ -25,7 +25,7 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "demo_conf.h"
#include "profile_conf.h"
static void
change_dark_state (GSimpleAction *action,
+1 -1
View File
@@ -75,7 +75,7 @@ define colors. Color expressions resemble functions, taking 1 or more colors
and in some cases a number as arguments.
`lighter(Color)`
: produces a brigher variant of Color
: produces a brighter variant of Color
`darker(Color)`
: produces a darker variant of Color
+24 -2
View File
@@ -11,13 +11,17 @@ Editor render nodes
SYNOPSIS
--------
| **gtk4-node-editor** [OPTIONS...]
| **gtk4-node-editor** [OPTIONS...] [FILE]
DESCRIPTION
-----------
``gtk4-node-editor`` is a utility to show and edit render node files.
Such render node files can be obtained e.g. from the GTK inspector.
Such render node files can be obtained e.g. from the GTK inspector or
as part of the testsuite in the GTK sources.
``gtk4-node-editor`` is used by GTK developers for debugging and testing,
and it has built-in support for saving testcases as part of the GTK testsuite.
OPTIONS
-------
@@ -25,3 +29,21 @@ OPTIONS
``-h, --help``
Show the application help.
``--version``
Show the program version.
``--reset``
Don't restore autosaved content and remove autosave files.
ENVIRONMENT
-----------
``GTK_SOURCE_DIR``
can be set to point to the location where the GTK sources reside, so that
testcases can be saved to the right location. If unsed, `gtk4-node-editor``
checks if the current working directory looks like a GTK checkout, and failing
that, saves testcase in the the current working directory.
+30 -1
View File
@@ -12,9 +12,10 @@ SYNOPSIS
--------
| **gtk4-rendernode-tool** <COMMAND> [OPTIONS...] <FILE>
|
| **gtk4-rendernode-tool** benchmark [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** info [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** show [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** render [OPTIONS...] <FILE> [<FILE>]
| **gtk4-rendernode-tool** show [OPTIONS...] <FILE>
DESCRIPTION
-----------
@@ -50,3 +51,31 @@ The name of the file to write can be specified as a second FILE argument.
Use the given renderer. Use ``--renderer=help`` to get a information
about poassible values for the ``RENDERER``.
Benchmark
^^^^^^^^^
The ``benchmark`` command benchmarks rendering of a node with the existing renderers
and prints the runtimes.
``--renderer=RENDERER``
Add the given renderer. This argument can be passed multiple times to test multiple
renderers. By default, all major GTK renderers are run.
``--runs=RUNS``
Number of times to render the node on each renderer. By default, this is 3 times.
Keep in mind that the first run is often used to populate caches and might be
significantly slower.
``--no-download``
Do not attempt to download the result. This may cause the measurement to not include
the execution of the commands on the GPU. It can be useful to use this flag to test
command submission performance.
+98 -33
View File
@@ -62,7 +62,7 @@ are only available when GTK has been configured with `-Ddebug=true`.
`layout`
: Layout managers
`acccessibility`
`accessibility`
: Accessibility state changs
A number of keys are influencing behavior instead of just logging:
@@ -274,49 +274,46 @@ are only available when GTK has been configured with `-Ddebug=true`.
`renderer`
: General renderer information
`cairo`
: cairo renderer information
`opengl`
: OpenGL renderer information
`shaders`
: Shaders
`surface`
: Surfaces
`vulkan`
: Vulkan renderer information
`shaders`
: Information about shaders
`surface`
: Information about surfaces
`fallback`
: Information about fallbacks
: Information about fallback usage in renderers
`glyphcache`
: Information about glyph caching
`verbose`
: Print verbose output while rendering
A number of options affect behavior instead of logging:
`diff`
: Show differences
`geometry`
: Show borders
: Show borders (when using cairo)
`full-redraw`
: Force full redraws for every frame
: Force full redraws
`sync`
: Sync after each frame
`staging`
: Use a staging image for texture upload (Vulkan only)
`offload-disable`
: Disable graphics offload to subsurfaces
`vulkan-staging-image`
: Use a staging image for Vulkan texture upload
`vulkan-staging-buffer`
: Use a staging buffer for Vulkan texture upload
`cairo`
: Overlay error pattern over cairo drawing (finds fallbacks)
The special value `all` can be used to turn on all debug options. The special
value `help` can be used to obtain a list of all supported debug options.
@@ -357,6 +354,40 @@ the default selection of the device that is used for Vulkan rendering.
The special value `list` can be used to obtain a list of all Vulkan
devices.
### `GDK_VULKAN_SKIP`
This variable can be set to a list of values, which cause GDK to
disable features of the Vulkan support.
Note that these features may already be disabled if the Vulkan driver
does not support them.
`dmabuf`
: Never import Dmabufs
`ycbr`
: Do not support Ycbcr textures
`descriptor-indexing`
: Force slow descriptor set layout codepath
`dynamic-indexing`
: Hardcode small number of buffer and texture arrays
`nonuniform-indexing`
: Split draw calls to ensure uniform texture accesses
`semaphore-export`
: Disable sync of exported dmabufs
`semaphore-import`
: Disable sync of imported dmabufs
`incremental-present`
: Do not send damage regions
The special value `all` can be used to turn on all values. The special
value `help` can be used to obtain a list of all supported values.
### `GSK_RENDERER`
If set, selects the GSK renderer to use. The following renderers can
@@ -378,22 +409,56 @@ using and the GDK backend supports them:
`gl`
: Selects the "gl" OpenGL renderer
`ngl`
: Selects the "ngl" OpenGL renderer
`vulkan`
: Selects the Vulkan renderer
Note that on Windows, if one is running Nahimic 3 on a system with
nVidia graphics, one needs to stop the "Nahimic service" or insert
the GTK application into the Nahimic blacklist, as noted in
https://www.nvidia.com/en-us/geforce/forums/game-ready-drivers/13/297952/nahimic-and-nvidia-drivers-conflict/2334568/, or use the cairo renderer (at the cost of being unable to use
OpenGL features), or use GDK_DEBUG=gl-gles if you know that GLES
support is enabled for the build.
This is a known issue, as the above link indicates, and affects quite
a number of applications--sadly, since this issue lies within the
nVidia graphics driver and/or the Nahimic 3 code, we are not able
to rememdy this on the GTK side; the best bet before trying the above
workarounds is to try to update your graphics drivers and Nahimic
installation.
::: note
If you are running the Nahimic 3 service on a Windows system with
nVidia graphics, you need to perform one of the following:
- stop the "Nahimic service"
- insert the GTK application into the Nahimic blocklist, as noted in the
[nVidia forums](https://www.nvidia.com/en-us/geforce/forums/game-ready-drivers/13/297952/nahimic-and-nvidia-drivers-conflict/2334568/)
- use the cairo renderer (at the cost of being unable to use OpenGL features)
- use `GDK_DEBUG=gl-gles`, if you know that GLES support is enabled for the build.
This is a known issue, as the above link indicates, and affects quite
a number of applications—sadly, since this issue lies within the
nVidia graphics driver and/or the Nahimic 3 code, we are not able
to rememdy this on the GTK side; the best bet before trying the above
workarounds is to try to update your graphics drivers and Nahimic
installation.
### `GSK_GPU_SKIP`
This variable can be set to a list of values, which cause GSK to
disable certain optimizations of the "ngl" and "vulkan" renderer.
`uber`
: Don't use the uber shader
`clear`
: Use shaders instead of vkCmdClearAttachment()/glClear()
`blit`
: Use shaders instead of vkCmdBlit()/glBlitFramebuffer()
`gradients`
: Don't supersample gradients
`mipmap`
: Avoid creating mipmaps
`gl-baseinstance`
: Assume no ARB/EXT_base_instance support
The special value `all` can be used to turn on all values. The special
value `help` can be used to obtain a list of all supported values.
### `GSK_MAX_TEXTURE_SIZE`
+1 -1
View File
@@ -207,7 +207,7 @@ you should ensure that:
GTK will try to fill in some information by using ancillary UI control properties,
for instance the accessible name will be taken from the label used by the UI control,
or from its tooltip, if the `GTK_ACCESSIBLE_PROPERTY_LABEL` property or the
`GTK_ACCESSIBLE_RELATION_LABELLED_BY` relation are unset. Similary for the accessible
`GTK_ACCESSIBLE_RELATION_LABELLED_BY` relation are unset. Similarly for the accessible
description. Nevertheless, it is good practice and project hygiene to explicitly specify
the accessible properties, just like it's good practice to specify tooltips and style classes.
+3 -2
View File
@@ -529,8 +529,9 @@ gdk_clipboard_get_content (GdkClipboard *clipboard)
* exit. Depending on the platform, the functionality may not be available
* unless a "clipboard manager" is running.
*
* This function is called automatically when a [class@Gtk.Application] is
* shut down, so you likely don't need to call it.
* This function is called automatically when a
* [GtkApplication](../gtk4/class.Application.html)
* is shut down, so you likely don't need to call it.
*/
void
gdk_clipboard_store_async (GdkClipboard *clipboard,
+2 -1
View File
@@ -47,7 +47,8 @@
* Cursors by themselves are not very interesting: they must be bound to a
* window for users to see them. This is done with [method@Gdk.Surface.set_cursor]
* or [method@Gdk.Surface.set_device_cursor]. Applications will typically
* use higher-level GTK functions such as [method@Gtk.Widget.set_cursor] instead.
* use higher-level GTK functions such as [gtk_widget_set_cursor()](../gtk4/method.Widget.set_cursor.html)
* instead.
*
* Cursors are not bound to a given [class@Gdk.Display], so they can be shared.
* However, the appearance of cursors may vary when used on different
+2 -1
View File
@@ -289,7 +289,8 @@ gdk_device_class_init (GdkDeviceClass *klass)
*/
device_props[PROP_MODIFIER_STATE] =
g_param_spec_flags ("modifier-state", NULL, NULL,
GDK_TYPE_MODIFIER_TYPE, 0,
GDK_TYPE_MODIFIER_TYPE,
GDK_NO_MODIFIER_MASK,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, LAST_PROP, device_props);
+54 -10
View File
@@ -40,7 +40,7 @@
#include "gdkglcontextprivate.h"
#include "gdkmonitorprivate.h"
#include "gdkrectangle.h"
#include "gdkvulkancontext.h"
#include "gdkvulkancontextprivate.h"
#ifdef HAVE_EGL
#include <epoxy/egl.h>
@@ -253,6 +253,13 @@ gdk_display_class_init (GdkDisplayClass *class)
TRUE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
/**
* GdkDisplay:dmabuf-formats:
*
* The dma-buf formats that are supported on this display
*
* Since: 4.14
*/
props[PROP_DMABUF_FORMATS] =
g_param_spec_boxed ("dmabuf-formats", NULL, NULL,
GDK_TYPE_DMABUF_FORMATS,
@@ -409,6 +416,13 @@ gdk_display_dispose (GObject *object)
g_clear_pointer (&display->egl_dmabuf_formats, gdk_dmabuf_formats_unref);
g_clear_pointer (&display->egl_external_formats, gdk_dmabuf_formats_unref);
#ifdef GDK_RENDERING_VULKAN
if (display->vk_dmabuf_formats)
{
gdk_display_unref_vulkan (display);
g_assert (display->vk_dmabuf_formats == NULL);
}
#endif
g_clear_object (&priv->gl_context);
#ifdef HAVE_EGL
@@ -1182,9 +1196,9 @@ _gdk_display_get_next_serial (GdkDisplay *display)
* Indicates to the GUI environment that the application has
* finished loading, using a given identifier.
*
* GTK will call this function automatically for [class@Gtk.Window]
* GTK will call this function automatically for [GtkWindow](../gtk4/class.Window.html)
* with custom startup-notification identifier unless
* [method@Gtk.Window.set_auto_startup_notification]
* [gtk_window_set_auto_startup_notification()](../gtk4/method.Window.set_auto_startup_notification.html)
* is called to disable that feature.
*
* Deprecated: 4.10: Using [method@Gdk.Toplevel.set_startup_id] is sufficient
@@ -1253,12 +1267,14 @@ gdk_display_get_keymap (GdkDisplay *display)
/*<private>
* gdk_display_create_vulkan_context:
* @self: a `GdkDisplay`
* @surface: (nullable): the `GdkSurface` to use or %NULL for a surfaceless
* context
* @error: return location for an error
*
* Creates a new `GdkVulkanContext` for use with @display.
*
* The context can not be used to draw to surfaces, it can only be
* used for custom rendering or compute.
* If @surface is NULL, the context can not be used to draw to surfaces,
* it can only be used for custom rendering or compute.
*
* If the creation of the `GdkVulkanContext` failed, @error will be set.
*
@@ -1267,9 +1283,11 @@ gdk_display_get_keymap (GdkDisplay *display)
*/
GdkVulkanContext *
gdk_display_create_vulkan_context (GdkDisplay *self,
GdkSurface *surface,
GError **error)
{
g_return_val_if_fail (GDK_IS_DISPLAY (self), NULL);
g_return_val_if_fail (surface == NULL || GDK_IS_SURFACE (surface), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (gdk_display_get_debug_flags (self) & GDK_DEBUG_VULKAN_DISABLE)
@@ -1286,11 +1304,33 @@ gdk_display_create_vulkan_context (GdkDisplay *self,
return FALSE;
}
return g_initable_new (GDK_DISPLAY_GET_CLASS (self)->vk_context_type,
NULL,
error,
"display", self,
NULL);
if (surface)
{
return g_initable_new (GDK_DISPLAY_GET_CLASS (self)->vk_context_type,
NULL,
error,
"surface", surface,
NULL);
}
else
{
return g_initable_new (GDK_DISPLAY_GET_CLASS (self)->vk_context_type,
NULL,
error,
"display", self,
NULL);
}
}
gboolean
gdk_display_has_vulkan_feature (GdkDisplay *self,
GdkVulkanFeatures feature)
{
#ifdef GDK_RENDERING_VULKAN
return !!(self->vulkan_features & feature);
#else
return FALSE;
#endif
}
static void
@@ -1932,6 +1972,10 @@ gdk_display_init_dmabuf (GdkDisplay *self)
#ifdef HAVE_DMABUF
if (!GDK_DISPLAY_DEBUG_CHECK (self, DMABUF_DISABLE))
{
#ifdef GDK_RENDERING_VULKAN
gdk_display_add_dmabuf_downloader (self, gdk_vulkan_get_dmabuf_downloader (self, builder));
#endif
#ifdef HAVE_EGL
gdk_display_add_dmabuf_downloader (self, gdk_dmabuf_get_egl_downloader (self, builder));
#endif
+16
View File
@@ -41,6 +41,17 @@ G_BEGIN_DECLS
typedef struct _GdkDisplayClass GdkDisplayClass;
typedef enum {
GDK_VULKAN_FEATURE_DMABUF = 1 << 0,
GDK_VULKAN_FEATURE_YCBCR = 1 << 1,
GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING = 1 << 2,
GDK_VULKAN_FEATURE_DYNAMIC_INDEXING = 1 << 3,
GDK_VULKAN_FEATURE_NONUNIFORM_INDEXING = 1 << 4,
GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT = 1 << 5,
GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT = 1 << 6,
GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT = 1 << 7,
} GdkVulkanFeatures;
/* Tracks information about the device grab on this display */
typedef struct
{
@@ -107,6 +118,8 @@ struct _GdkDisplay
char *vk_pipeline_cache_etag;
guint vk_save_pipeline_cache_source;
GHashTable *vk_shader_modules;
GdkDmabufFormats *vk_dmabuf_formats;
GdkVulkanFeatures vulkan_features;
guint vulkan_refcount;
#endif /* GDK_RENDERING_VULKAN */
@@ -220,7 +233,10 @@ void _gdk_display_unpause_events (GdkDisplay *display
void gdk_display_init_dmabuf (GdkDisplay *self);
gboolean gdk_display_has_vulkan_feature (GdkDisplay *self,
GdkVulkanFeatures feature);
GdkVulkanContext * gdk_display_create_vulkan_context (GdkDisplay *self,
GdkSurface *surface,
GError **error);
GdkGLContext * gdk_display_get_gl_context (GdkDisplay *display);
+13
View File
@@ -1919,6 +1919,19 @@ gdk_dmabuf_get_memory_format (guint32 fourcc,
}
#ifdef GDK_RENDERING_VULKAN
gboolean
gdk_dmabuf_vk_get_nth (gsize n,
guint32 *fourcc,
VkFormat *vk_format)
{
if (n >= G_N_ELEMENTS (supported_formats))
return FALSE;
*fourcc = supported_formats[n].fourcc;
*vk_format = supported_formats[n].vk.format;
return TRUE;
}
VkFormat
gdk_dmabuf_get_vk_format (guint32 fourcc,
VkComponentMapping *out_components)
+5 -5
View File
@@ -140,10 +140,10 @@ gdk_dmabuf_egl_downloader_collect_formats (GdkDisplay *display,
typedef struct _GskRenderer GskRenderer;
extern GskRenderer * gsk_gl_renderer_new (void);
extern gboolean gsk_renderer_realize (GskRenderer *renderer,
GdkSurface *surface,
GError **error);
extern GskRenderer * gsk_gl_renderer_new (void);
extern gboolean gsk_renderer_realize_for_display (GskRenderer *renderer,
GdkDisplay *display,
GError **error);
GdkDmabufDownloader *
gdk_dmabuf_get_egl_downloader (GdkDisplay *display,
@@ -176,7 +176,7 @@ gdk_dmabuf_get_egl_downloader (GdkDisplay *display,
renderer = gsk_gl_renderer_new ();
if (!gsk_renderer_realize (renderer, NULL, &error))
if (!gsk_renderer_realize_for_display (renderer, display, &error))
{
g_warning ("Failed to realize GL renderer: %s", error->message);
g_error_free (error);
+4 -4
View File
@@ -25,7 +25,7 @@
/**
* GdkDmabufFormats:
*
* The `GdkDmabufFormats struct provides information about
* The `GdkDmabufFormats` struct provides information about
* supported DMA buffer formats.
*
* You can query whether a given format is supported with
@@ -37,7 +37,7 @@
* The list of supported formats is sorted by preference,
* with the best formats coming first.
*
* The list may contains (format, modfier) pairs where the modifier
* The list may contains (format, modifier) pairs where the modifier
* is `DMA_FORMAT_MOD_INVALID`, indicating that **_implicit modifiers_**
* may be used with this format.
*
@@ -152,10 +152,10 @@ gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats,
}
/**
* gdk_dmabuf_format_contains:
* gdk_dmabuf_formats_contains:
* @formats: a `GdkDmabufFormats`
* @fourcc: a format code
* @modfier: a format modifier
* @modifier: a format modifier
*
* Returns whether a given format is contained in @formats.
*
+3
View File
@@ -54,6 +54,9 @@ gboolean gdk_dmabuf_get_memory_format (guint32
gboolean premultiplied,
GdkMemoryFormat *out_format);
#ifdef GDK_RENDERING_VULKAN
gboolean gdk_dmabuf_vk_get_nth (gsize n,
guint32 *fourcc,
VkFormat *vk_format);
VkFormat gdk_dmabuf_get_vk_format (guint32 fourcc,
VkComponentMapping *out_components);
#endif
+2
View File
@@ -39,6 +39,8 @@
* [class@Gdk.DmabufTextureBuilder] object.
*
* Dma-buf textures can only be created on Linux.
*
* Since: 4.14
*/
struct _GdkDmabufTexture
+3 -3
View File
@@ -57,7 +57,7 @@ struct _GdkDmabufTextureBuilderClass
*
* DMA buffers are commonly called **_dma-bufs_**.
*
* DMA buffers a feature of the Linux kernel to enable efficient buffer and
* DMA buffers are a feature of the Linux kernel to enable efficient buffer and
* memory sharing between hardware such as codecs, GPUs, displays, cameras and the
* kernel drivers controlling them. For example, a decoder may want its output to
* be directly shared with the display server for rendering without a copy.
@@ -67,7 +67,7 @@ struct _GdkDmabufTextureBuilderClass
*
* The memory that is shared via DMA buffers is usually stored in non-system memory
* (maybe in device's local memory or something else not directly accessible by the
* CPU), and accessing this memory from the CPU may have higher than usual overhead.
* CPU), and accessing this memory from the CPU may have higher-than-usual overhead.
*
* In particular for graphics data, it is not uncommon that data consists of multiple
* separate blocks of memory, for example one block for each of the red, green and
@@ -87,7 +87,7 @@ struct _GdkDmabufTextureBuilderClass
*
* For historical reasons, some producers of dma-bufs don't provide an explicit modifier, but
* instead return `DMA_FORMAT_MOD_INVALID` to indicate that their modifier is **_implicit_**.
* GTK tries to accomodate this situation by accepting `DMA_FORMAT_MOD_INVALID` as modifier.
* GTK tries to accommodate this situation by accepting `DMA_FORMAT_MOD_INVALID` as modifier.
*
* The operation of `GdkDmabufTextureBuilder` is quite simple: Create a texture builder,
* set all the necessary properties, and then call [method@Gdk.DmabufTextureBuilder.build]
+4 -4
View File
@@ -56,10 +56,10 @@ static struct {
GdkCursor *cursor;
} drag_cursors[] = {
{ GDK_ACTION_ASK, "dnd-ask", NULL },
{ GDK_ACTION_COPY, "dnd-copy", NULL },
{ GDK_ACTION_MOVE, "dnd-move", NULL },
{ GDK_ACTION_LINK, "dnd-link", NULL },
{ 0, "dnd-none", NULL },
{ GDK_ACTION_COPY, "copy", NULL },
{ GDK_ACTION_MOVE, "move", NULL },
{ GDK_ACTION_LINK, "alias", NULL },
{ 0, "no-drop", NULL },
};
enum {
+4 -4
View File
@@ -71,7 +71,7 @@ gdk_draw_context_default_surface_resized (GdkDrawContext *context)
static void
gdk_draw_context_default_empty_frame (GdkDrawContext *context)
{
g_warning ("FIXME: Implement");
g_warning ("FIXME: Implement GdkDrawContext.empty_frame in %s", G_OBJECT_TYPE_NAME (context));
}
static void
@@ -305,8 +305,8 @@ gdk_draw_context_get_surface (GdkDrawContext *context)
*
* When using GTK, the widget system automatically places calls to
* gdk_draw_context_begin_frame() and gdk_draw_context_end_frame() via the
* use of [class@Gsk.Renderer]s, so application code does not need to call
* these functions explicitly.
* use of [GskRenderer](../gsk4/class.Renderer.html)s, so application code
* does not need to call these functions explicitly.
*/
void
gdk_draw_context_begin_frame (GdkDrawContext *context,
@@ -331,7 +331,7 @@ gdk_draw_context_begin_frame (GdkDrawContext *context,
*
* This is only a request and if the GDK backend does not support HDR rendering
* or does not consider it worthwhile, it may choose to not honor the request.
* It may also choose to provide a differnet depth even if it was not requested.
* It may also choose to provide a different depth even if it was not requested.
* Typically the steps undertaken by a backend are:
* 1. Check if high depth is supported by this drawing backend.
* 2. Check if the compositor supports high depth.
+2
View File
@@ -160,6 +160,8 @@ typedef enum
* reasons
*
* Error enumeration for `GdkDmabufTexture`.
*
* Since: 4.14
*/
typedef enum {
GDK_DMABUF_ERROR_NOT_AVAILABLE,
+4 -2
View File
@@ -166,7 +166,8 @@ gdk_frame_clock_class_init (GdkFrameClockClass *klass)
*
* Animations should be updated using [method@Gdk.FrameClock.get_frame_time].
* Applications can connect directly to this signal, or use
* [method@Gtk.Widget.add_tick_callback] as a more convenient interface.
* [gtk_widget_add_tick_callback()](../gtk4/method.Widget.add_tick_callback.html)
* as a more convenient interface.
*/
signals[UPDATE] =
g_signal_new (g_intern_static_string ("update"),
@@ -203,7 +204,8 @@ gdk_frame_clock_class_init (GdkFrameClockClass *klass)
*
* The frame is repainted. GDK normally handles this internally and
* emits [signal@Gdk.Surface::render] signals which are turned into
* [signal@Gtk.Widget::snapshot] signals by GTK.
* [GtkWidget::snapshot](../gtk4/signal.Widget.snapshot.html) signals
* by GTK.
*/
signals[PAINT] =
g_signal_new (g_intern_static_string ("paint"),
+13 -12
View File
@@ -1569,10 +1569,10 @@ gdk_gl_context_init_memory_flags (GdkGLContext *self)
priv->memory_flags[GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_RENDERABLE | GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R8G8B8A8] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_RENDERABLE | GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R8G8B8X8] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_RENDERABLE | GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16_FLOAT] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_A16_FLOAT] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16_FLOAT] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_A16_FLOAT] |= GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R32G32B32_FLOAT] |= GDK_GL_FORMAT_USABLE;
priv->memory_flags[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] |= GDK_GL_FORMAT_USABLE;
priv->memory_flags[GDK_MEMORY_R32G32B32A32_FLOAT] |= GDK_GL_FORMAT_USABLE;
@@ -1583,12 +1583,12 @@ gdk_gl_context_init_memory_flags (GdkGLContext *self)
if (gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (3, 2)))
{
/* GLES 3.2 spec, table 8.10 */
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] |= GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT] |= GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_A16_FLOAT] |= GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] |= GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R32G32B32A32_FLOAT] |= GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_A32_FLOAT] |= GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] |= GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT] |= GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_A16_FLOAT] |= GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] |= GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_R32G32B32A32_FLOAT] |= GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_A32_FLOAT] |= GDK_GL_FORMAT_RENDERABLE;
}
}
@@ -1639,7 +1639,8 @@ gdk_gl_context_init_memory_flags (GdkGLContext *self)
flags |= GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] |= flags;
priv->memory_flags[GDK_MEMORY_R16G16B16A16_FLOAT] |= flags;
priv->memory_flags[GDK_MEMORY_R16G16B16_FLOAT] |= flags;
/* disabled for now, see https://gitlab.freedesktop.org/mesa/mesa/-/issues/10378 */
priv->memory_flags[GDK_MEMORY_R16G16B16_FLOAT] |= flags & ~GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_A16_FLOAT] |= flags;
}
if (epoxy_has_gl_extension ("GL_OES_texture_float"))
@@ -1651,7 +1652,7 @@ gdk_gl_context_init_memory_flags (GdkGLContext *self)
flags |= GDK_GL_FORMAT_FILTERABLE;
priv->memory_flags[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] |= flags;
priv->memory_flags[GDK_MEMORY_R32G32B32A32_FLOAT] |= flags;
priv->memory_flags[GDK_MEMORY_R32G32B32_FLOAT] |= flags;
priv->memory_flags[GDK_MEMORY_R32G32B32_FLOAT] |= flags & ~GDK_GL_FORMAT_RENDERABLE;
priv->memory_flags[GDK_MEMORY_A32_FLOAT] |= flags;
}
}
+10 -2
View File
@@ -161,7 +161,12 @@ gdk_gl_texture_find_format (GdkGLContext *context,
if (!(gdk_gl_context_get_format_flags (context, format) & GDK_GL_FORMAT_RENDERABLE))
continue;
gdk_memory_format_gl_format (format, &q_internal_format, &q_format, &q_type, q_swizzle);
gdk_memory_format_gl_format (format,
gdk_gl_context_get_use_es (context),
&q_internal_format,
&q_format,
&q_type,
q_swizzle);
if (q_format != gl_format || q_type != gl_type)
continue;
@@ -193,6 +198,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
((gdk_gl_context_get_format_flags (context, format) & GDK_GL_FORMAT_USABLE) == GDK_GL_FORMAT_USABLE))
{
gdk_memory_format_gl_format (format,
gdk_gl_context_get_use_es (context),
&gl_internal_format,
&gl_format, &gl_type, gl_swizzle);
if (download->stride == expected_stride &&
@@ -255,6 +261,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
actual_format = gdk_memory_format_get_straight (actual_format);
gdk_memory_format_gl_format (actual_format,
gdk_gl_context_get_use_es (context),
&gl_internal_format,
&gl_read_format, &gl_read_type, gl_swizzle);
}
@@ -266,6 +273,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
actual_format = gdk_memory_format_get_straight (actual_format);
gdk_memory_format_gl_format (actual_format,
gdk_gl_context_get_use_es (context),
&gl_internal_format,
&gl_read_format, &gl_read_type, gl_swizzle);
}
@@ -653,7 +661,7 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
* Return value: (transfer full) (type GdkGLTexture): A newly-created
* `GdkTexture`
*
* Deprecated: 4.12: [class@Gdk.GLTextureBuilder] supercedes this function
* Deprecated: 4.12: [class@Gdk.GLTextureBuilder] supersedes this function
* and provides extended functionality for creating GL textures.
*/
GdkTexture *
+1 -1
View File
@@ -51,7 +51,7 @@ struct _GdkGLTextureBuilderClass
/**
* GdkGLTextureBuilder:
*
* `GdkGLTextureBuilder` is a buider used to construct [class@Gdk.Texture] objects from
* `GdkGLTextureBuilder` is a builder used to construct [class@Gdk.Texture] objects from
* GL textures.
*
* The operation is quite simple: Create a texture builder, set all the necessary
+80 -37
View File
@@ -335,7 +335,8 @@ struct _GdkMemoryFormatDescription
GdkMemoryDepth depth;
const GdkMemoryFormat *fallbacks;
struct {
GLint internal_format;
GLint internal_gl_format;
GLint internal_gles_format;
GLenum format;
GLenum type;
GLint swizzle[4];
@@ -375,7 +376,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_BGRA,
.format = GL_BGRA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -402,7 +404,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.format = GL_BGRA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -429,7 +432,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.format = GL_RGBA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -455,7 +459,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.format = GL_RGBA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -482,7 +487,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_BGRA,
.format = GL_BGRA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -509,7 +515,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.format = GL_BGRA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -536,7 +543,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.format = GL_RGBA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -562,7 +570,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.format = GL_RGBA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -590,7 +599,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_BGRA,
.format = GL_BGRA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
@@ -618,7 +628,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.format = GL_BGRA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
@@ -646,7 +657,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.format = GL_RGBA,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
@@ -673,7 +685,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA8,
.internal_gl_format = GL_RGBA8,
.internal_gles_format = GL_RGBA8,
.format = GL_RGBA,
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
@@ -701,7 +714,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGB8,
.internal_gl_format = GL_RGB8,
.internal_gles_format = GL_RGB8,
.format = GL_RGB,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -728,7 +742,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGB8,
.internal_gl_format = GL_RGB8,
.internal_gles_format = GL_RGB8,
.format = GL_BGR,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -759,7 +774,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGB16,
.internal_gl_format = GL_RGB16,
.internal_gles_format = GL_RGB16,
.format = GL_RGB,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -788,7 +804,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA16,
.internal_gl_format = GL_RGBA16,
.internal_gles_format = GL_RGBA16,
.format = GL_RGBA,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -817,7 +834,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA16,
.internal_gl_format = GL_RGBA16,
.internal_gles_format = GL_RGBA16,
.format = GL_RGBA,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -846,7 +864,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGB16F,
.internal_gl_format = GL_RGB16F,
.internal_gles_format = GL_RGB16F,
.format = GL_RGB,
.type = GL_HALF_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -874,7 +893,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA16F,
.internal_gl_format = GL_RGBA16F,
.internal_gles_format = GL_RGBA16F,
.format = GL_RGBA,
.type = GL_HALF_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -902,7 +922,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA16F,
.internal_gl_format = GL_RGBA16F,
.internal_gles_format = GL_RGBA16F,
.format = GL_RGBA,
.type = GL_HALF_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -931,7 +952,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGB32F,
.internal_gl_format = GL_RGB32F,
.internal_gles_format = GL_RGB32F,
.format = GL_RGB,
.type = GL_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -959,7 +981,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA32F,
.internal_gl_format = GL_RGBA32F,
.internal_gles_format = GL_RGBA32F,
.format = GL_RGBA,
.type = GL_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -987,7 +1010,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RGBA32F,
.internal_gl_format = GL_RGBA32F,
.internal_gles_format = GL_RGBA32F,
.format = GL_RGBA,
.type = GL_FLOAT,
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
@@ -1014,7 +1038,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RG8,
.internal_gl_format = GL_RG8,
.internal_gles_format = GL_RG8,
.format = GL_RG,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
@@ -1041,7 +1066,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RG8,
.internal_gl_format = GL_RG8,
.internal_gles_format = GL_RG8,
.format = GL_RG,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
@@ -1068,7 +1094,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_R8,
.internal_gl_format = GL_R8,
.internal_gles_format = GL_R8,
.format = GL_RED,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_ONE },
@@ -1098,7 +1125,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RG16,
.internal_gl_format = GL_RG16,
.internal_gles_format = GL_RG16,
.format = GL_RG,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
@@ -1128,7 +1156,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_RG16,
.internal_gl_format = GL_RG16,
.internal_gles_format = GL_RG16,
.format = GL_RG,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
@@ -1158,7 +1187,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_R16,
.internal_gl_format = GL_R16,
.internal_gles_format = GL_R16,
.format = GL_RED,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_ONE },
@@ -1185,7 +1215,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_R8,
.internal_gl_format = GL_R8,
.internal_gles_format = GL_R8,
.format = GL_RED,
.type = GL_UNSIGNED_BYTE,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
@@ -1215,7 +1246,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_R16,
.internal_gl_format = GL_R16,
.internal_gles_format = GL_R16,
.format = GL_RED,
.type = GL_UNSIGNED_SHORT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
@@ -1244,7 +1276,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_R16F,
.internal_gl_format = GL_R16F,
.internal_gles_format = GL_R16F,
.format = GL_RED,
.type = GL_HALF_FLOAT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
@@ -1273,7 +1306,8 @@ static const GdkMemoryFormatDescription memory_formats[] = {
-1,
},
.gl = {
.internal_format = GL_R32F,
.internal_gl_format = GL_R32F,
.internal_gles_format = GL_R32F,
.format = GL_RED,
.type = GL_FLOAT,
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
@@ -1387,7 +1421,7 @@ gdk_memory_format_get_depth (GdkMemoryFormat format)
* @depth1: the first depth
* @depth2: the second depth
*
* Returns a depth that can accomodate both given depths
* Returns a depth that can accommodate both given depths
* without any loss of precision.
*
* Returns: The merged depth
@@ -1473,12 +1507,16 @@ gdk_memory_depth_get_alpha_format (GdkMemoryDepth depth)
void
gdk_memory_format_gl_format (GdkMemoryFormat format,
gboolean gles,
GLint *out_internal_format,
GLenum *out_format,
GLenum *out_type,
GLint out_swizzle[4])
{
*out_internal_format = memory_formats[format].gl.internal_format;
if (gles)
*out_internal_format = memory_formats[format].gl.internal_gles_format;
else
*out_internal_format = memory_formats[format].gl.internal_gl_format;
*out_format = memory_formats[format].gl.format;
*out_type = memory_formats[format].gl.type;
memcpy (out_swizzle, memory_formats[format].gl.swizzle, sizeof(GLint) * 4);
@@ -1487,6 +1525,7 @@ gdk_memory_format_gl_format (GdkMemoryFormat format,
/*
* gdk_memory_format_gl_rgba_format:
* @format: The format to query
* @gles: TRUE for GLES, FALSE for GL
* @out_actual_format: The actual RGBA format
* @out_internal_format: the GL internal format
* @out_format: the GL format
@@ -1504,6 +1543,7 @@ gdk_memory_format_gl_format (GdkMemoryFormat format,
**/
gboolean
gdk_memory_format_gl_rgba_format (GdkMemoryFormat format,
gboolean gles,
GdkMemoryFormat *out_actual_format,
GLint *out_internal_format,
GLenum *out_format,
@@ -1516,7 +1556,10 @@ gdk_memory_format_gl_rgba_format (GdkMemoryFormat format,
return FALSE;
*out_actual_format = actual;
*out_internal_format = memory_formats[actual].gl.internal_format;
if (gles)
*out_internal_format = memory_formats[actual].gl.internal_gles_format;
else
*out_internal_format = memory_formats[actual].gl.internal_gl_format;
*out_format = memory_formats[actual].gl.format;
*out_type = memory_formats[actual].gl.type;
memcpy (out_swizzle, memory_formats[format].gl.rgba_swizzle, sizeof(GLint) * 4);
+2
View File
@@ -55,11 +55,13 @@ GdkMemoryDepth gdk_memory_depth_merge (GdkMemoryDepth
GdkMemoryFormat gdk_memory_depth_get_format (GdkMemoryDepth depth) G_GNUC_CONST;
GdkMemoryFormat gdk_memory_depth_get_alpha_format (GdkMemoryDepth depth) G_GNUC_CONST;
void gdk_memory_format_gl_format (GdkMemoryFormat format,
gboolean gles,
GLint *out_internal_format,
GLenum *out_format,
GLenum *out_type,
GLint out_swizzle[4]);
gboolean gdk_memory_format_gl_rgba_format (GdkMemoryFormat format,
gboolean gles,
GdkMemoryFormat *out_actual_format,
GLint *out_internal_format,
GLenum *out_format,
+2 -1
View File
@@ -681,7 +681,8 @@ gdk_empty_paintable_init (GdkEmptyPaintable *self)
* This is often useful for implementing the
* [vfunc@Gdk.Paintable.get_current_image] virtual function
* when the paintable is in an incomplete state (like a
* [class@Gtk.MediaStream] before receiving the first frame).
* [GtkMediaStream](../gtk4/class.MediaStream.html) before receiving
* the first frame).
*
* Returns: (transfer full): a `GdkPaintable`
*/
+3 -3
View File
@@ -56,9 +56,9 @@
* [method@Gdk.Popup.get_position_x], [method@Gdk.Popup.get_position_y],
* [method@Gdk.Popup.get_rect_anchor] and [method@Gdk.Popup.get_surface_anchor]
* after the popup has been presented. This can be used to adjust the rendering.
* For example, [class@Gtk.Popover] changes its arrow position accordingly.
* But you have to be careful avoid changing the size of the popover, or it
* has to be presented again.
* For example, [GtkPopover](../gtk4/class.Popover.html) changes its arrow position
* accordingly. But you have to be careful avoid changing the size of the popover,
* or it has to be presented again.
*/
struct _GdkPopupLayout
+2 -2
View File
@@ -45,12 +45,12 @@ void gdk_rectangle_union (const GdkRectangle *src1,
GDK_AVAILABLE_IN_ALL
gboolean gdk_rectangle_equal (const GdkRectangle *rect1,
const GdkRectangle *rect2);
const GdkRectangle *rect2) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
gboolean gdk_rectangle_contains_point (const GdkRectangle *rect,
int x,
int y);
int y) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
GType gdk_rectangle_get_type (void) G_GNUC_CONST;
+1 -1
View File
@@ -642,7 +642,7 @@ gdk_rgba_parser_parse (GtkCssParser *parser,
{
if (gtk_css_token_is_ident (token, "transparent"))
{
*rgba = (GdkRGBA) { 0, 0, 0, 0 };
*rgba = GDK_RGBA_TRANSPARENT;
}
else if (gdk_rgba_parse (rgba, gtk_css_token_get_string (token)))
{
+5
View File
@@ -34,6 +34,11 @@
((_GDK_RGBA_SELECT_COLOR(str, 2, 4) << 4) | _GDK_RGBA_SELECT_COLOR(str, 2, 5)) / 255., \
((sizeof(str) % 4 == 1) ? ((_GDK_RGBA_SELECT_COLOR(str, 3, 6) << 4) | _GDK_RGBA_SELECT_COLOR(str, 3, 7)) : 0xFF) / 255. })
#define GDK_RGBA_INIT_ALPHA(rgba,opacity) ((GdkRGBA) { (rgba)->red, (rgba)->green, (rgba)->blue, (rgba)->alpha * (opacity) })
#define GDK_RGBA_TRANSPARENT ((GdkRGBA) { 0, 0, 0, 0 })
#define GDK_RGBA_BLACK ((GdkRGBA) { 0, 0, 0, 1 })
#define GDK_RGBA_WHITE ((GdkRGBA) { 1, 1, 1, 1 })
gboolean gdk_rgba_parser_parse (GtkCssParser *parser,
GdkRGBA *rgba);
+1 -1
View File
@@ -26,7 +26,7 @@
*
* Base type for snapshot operations.
*
* The subclass of `GdkSnapshot` used by GTK is [class@Gtk.Snapshot].
* The subclass of `GdkSnapshot` used by GTK is [GtkSnapshot](../gtk4/class.Snapshot.html).
*/
G_DEFINE_ABSTRACT_TYPE (GdkSnapshot, gdk_snapshot, G_TYPE_OBJECT)
+10 -33
View File
@@ -57,7 +57,7 @@
* A `GdkSurface` is a rectangular region on the screen.
*
* Its a low-level object, used to implement high-level objects
* such as [class@Gtk.Window] or [class@Gtk.Dialog] in GTK.
* such as [GtkWindow](../gtk4/class.Window.html).
*
* The surfaces you see in practice are either [iface@Gdk.Toplevel] or
* [iface@Gdk.Popup], and those interfaces provide much of the required
@@ -1246,43 +1246,20 @@ gdk_surface_create_cairo_context (GdkSurface *surface)
* @surface: a `GdkSurface`
* @error: return location for an error
*
* Creates a new `GdkVulkanContext` for rendering on @surface.
* Sets an error and returns %NULL.
*
* If the creation of the `GdkVulkanContext` failed, @error will be set.
* Returns: (transfer full): %NULL
*
* Returns: (transfer full): the newly created `GdkVulkanContext`, or
* %NULL on error
* Deprecated: 4.14: GTK does not expose any Vulkan internals. This
* function is a leftover that was accidentally exposed.
*/
GdkVulkanContext *
gdk_surface_create_vulkan_context (GdkSurface *surface,
GError **error)
{
GdkDisplay *display;
g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (gdk_display_get_debug_flags (surface->display) & GDK_DEBUG_VULKAN_DISABLE)
{
g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE,
_("Vulkan support disabled via GDK_DEBUG"));
return NULL;
}
display = surface->display;
if (GDK_DISPLAY_GET_CLASS (display)->vk_extension_name == NULL)
{
g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
"The %s backend has no Vulkan support.", G_OBJECT_TYPE_NAME (display));
return FALSE;
}
return g_initable_new (GDK_DISPLAY_GET_CLASS (display)->vk_context_type,
NULL,
error,
"surface", surface,
NULL);
g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
"GTK does not expose Vulkan internals.");
return FALSE;
}
static gboolean
@@ -1716,7 +1693,7 @@ gdk_surface_get_device_position (GdkSurface *surface,
* For toplevel surfaces, withdraws them, so they will no longer be
* known to the window manager; for all surfaces, unmaps them, so
* they wont be displayed. Normally done automatically as
* part of [method@Gtk.Widget.hide].
* part of [gtk_widget_hide()](../gtk4/method.Widget.hide.html).
*/
void
gdk_surface_hide (GdkSurface *surface)
@@ -2636,7 +2613,7 @@ gdk_surface_get_scale (GdkSurface *surface)
* GTK will update this property automatically if the @surface background
* is opaque, as we know where the opaque regions are. If your surface
* background is not opaque, please update this property in your
* [vfunc@Gtk.Widget.css_changed] handler.
* [GtkWidgetClass.css_changed](../gtk4/vfunc.Widget.css_changed.html) handler.
*/
void
gdk_surface_set_opaque_region (GdkSurface *surface,
+1 -1
View File
@@ -134,7 +134,7 @@ GdkCairoContext *gdk_surface_create_cairo_context(GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
GdkGLContext * gdk_surface_create_gl_context (GdkSurface *surface,
GError **error);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_14
GdkVulkanContext *
gdk_surface_create_vulkan_context(GdkSurface *surface,
GError **error);
+1 -1
View File
@@ -870,7 +870,7 @@ gdk_texture_download_surface (GdkTexture *texture)
* cairo_surface_mark_dirty (surface);
* ```
*
* For more flexible download capabilites, see
* For more flexible download capabilities, see
* [struct@Gdk.TextureDownloader].
*/
void
+1 -1
View File
@@ -22,7 +22,7 @@
* [class@Gdk.Texture].
*
* It is intended to be created as a short-term object for a single download,
* but can be used for multipe downloads of different textures or with different
* but can be used for multiple downloads of different textures or with different
* settings.
*
* `GdkTextureDownloader` can be used to convert data between different formats.
+7 -6
View File
@@ -377,8 +377,9 @@ gdk_toplevel_lower (GdkToplevel *toplevel)
*
* Sets keyboard focus to @surface.
*
* In most cases, [method@Gtk.Window.present_with_time] should be
* used on a [class@Gtk.Window], rather than calling this function.
* In most cases, [gtk_window_present_with_time()](../gtk4/method.Window.present_with_time.html)
* should be used on a [GtkWindow](../gtk4/class.Window.html), rather than
* calling this function.
*/
void
gdk_toplevel_focus (GdkToplevel *toplevel,
@@ -437,8 +438,8 @@ gdk_toplevel_set_title (GdkToplevel *toplevel,
* Sets the startup notification ID.
*
* When using GTK, typically you should use
* [method@Gtk.Window.set_startup_id] instead of this
* low-level function.
* [gtk_window_set_startup_id()](../gtk4/method.Window.set_startup_id.html)
* instead of this low-level function.
*/
void
gdk_toplevel_set_startup_id (GdkToplevel *toplevel,
@@ -461,8 +462,8 @@ gdk_toplevel_set_startup_id (GdkToplevel *toplevel,
* allows the window manager to do things like center @surface
* on @parent and keep @surface above @parent.
*
* See [method@Gtk.Window.set_transient_for] if youre using
* [class@Gtk.Window] or [class@Gtk.Dialog].
* See [gtk_window_set_transient_for()](../gtk4/method.Window.set_transient_for.html)
* if youre using [GtkWindow](../gtk4/class.Window.html).
*/
void
gdk_toplevel_set_transient_for (GdkToplevel *toplevel,
+296 -67
View File
@@ -24,10 +24,27 @@
#include "gdkvulkancontextprivate.h"
#include "gdkdebugprivate.h"
#include "gdkdmabufformatsbuilderprivate.h"
#include "gdkdmabuffourccprivate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkdisplayprivate.h"
#include <glib/gi18n-lib.h>
#include <math.h>
#ifdef GDK_RENDERING_VULKAN
static const GdkDebugKey gsk_vulkan_feature_keys[] = {
{ "dmabuf", GDK_VULKAN_FEATURE_DMABUF, "Never import Dmabufs" },
{ "ycbcr", GDK_VULKAN_FEATURE_YCBCR, "Do not support Ycbcr textures" },
{ "descriptor-indexing", GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING, "Force slow descriptor set layout codepath" },
{ "dynamic-indexing", GDK_VULKAN_FEATURE_DYNAMIC_INDEXING, "Hardcode small number of buffer and texture arrays" },
{ "nonuniform-indexing", GDK_VULKAN_FEATURE_NONUNIFORM_INDEXING, "Split draw calls to ensure uniform texture accesses" },
{ "semaphore-export", GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT, "Disable sync of exported dmabufs" },
{ "semaphore-import", GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT, "Disable sync of imported dmabufs" },
{ "incremental-present", GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT, "Do not send damage regions" },
};
#endif
/**
* GdkVulkanContext:
*
@@ -60,9 +77,6 @@ struct _GdkVulkanContextPrivate {
guint n_images;
VkImage *images;
cairo_region_t **regions;
gboolean has_present_region;
#endif
guint32 draw_index;
@@ -533,6 +547,74 @@ physical_device_supports_extension (VkPhysicalDevice device,
return FALSE;
}
static gboolean
physical_device_check_features (VkPhysicalDevice device,
GdkVulkanFeatures *out_features)
{
VkPhysicalDeviceVulkan12Features v12_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
};
VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcr_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
.pNext = &v12_features
};
VkPhysicalDeviceFeatures2 features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
.pNext = &ycbcr_features
};
VkExternalSemaphoreProperties semaphore_props = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
};
vkGetPhysicalDeviceFeatures2 (device, &features);
vkGetPhysicalDeviceExternalSemaphoreProperties (device,
&(VkPhysicalDeviceExternalSemaphoreInfo) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
},
&semaphore_props);
*out_features = 0;
if (features.features.shaderUniformBufferArrayDynamicIndexing &&
features.features.shaderSampledImageArrayDynamicIndexing)
*out_features |= GDK_VULKAN_FEATURE_DYNAMIC_INDEXING;
if (v12_features.descriptorIndexing &&
v12_features.descriptorBindingPartiallyBound &&
v12_features.descriptorBindingVariableDescriptorCount &&
v12_features.descriptorBindingSampledImageUpdateAfterBind &&
v12_features.descriptorBindingStorageBufferUpdateAfterBind)
*out_features |= GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING;
else if (physical_device_supports_extension (device, VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
*out_features |= GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING;
if (v12_features.shaderSampledImageArrayNonUniformIndexing &&
v12_features.shaderStorageBufferArrayNonUniformIndexing)
*out_features |= GDK_VULKAN_FEATURE_NONUNIFORM_INDEXING;
if (ycbcr_features.samplerYcbcrConversion)
*out_features |= GDK_VULKAN_FEATURE_YCBCR;
if (physical_device_supports_extension (device, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME) &&
physical_device_supports_extension (device, VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME))
*out_features |= GDK_VULKAN_FEATURE_DMABUF;
if (physical_device_supports_extension (device, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME))
{
if (semaphore_props.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT)
*out_features |= GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT;
if (semaphore_props.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT)
*out_features |= GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT;
}
if (physical_device_supports_extension (device, VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME))
*out_features |= GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT;
return TRUE;
}
static void
gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context,
GdkMemoryDepth depth,
@@ -578,42 +660,38 @@ gdk_vulkan_context_end_frame (GdkDrawContext *draw_context,
GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context);
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
GdkSurface *surface = gdk_draw_context_get_surface (draw_context);
VkPresentRegionsKHR *regionsptr = VK_NULL_HANDLE;
VkPresentRegionsKHR regions;
GdkDisplay *display = gdk_draw_context_get_display (draw_context);
VkRectLayerKHR *rectangles;
double scale;
int n_regions;
scale = gdk_surface_get_scale (surface);
n_regions = cairo_region_num_rectangles (painted);
rectangles = g_alloca (sizeof (VkRectLayerKHR) * n_regions);
for (int i = 0; i < n_regions; i++)
if (display->vulkan_features & GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT)
{
cairo_rectangle_int_t r;
double scale;
cairo_region_get_rectangle (painted, i, &r);
scale = gdk_surface_get_scale (surface);
n_regions = cairo_region_num_rectangles (painted);
rectangles = g_alloca (sizeof (VkRectLayerKHR) * n_regions);
rectangles[i] = (VkRectLayerKHR) {
.layer = 0,
.offset.x = (int) floor (r.x * scale),
.offset.y = (int) floor (r.y * scale),
.extent.width = (int) ceil (r.width * scale),
.extent.height = (int) ceil (r.height * scale),
};
for (int i = 0; i < n_regions; i++)
{
cairo_rectangle_int_t r;
cairo_region_get_rectangle (painted, i, &r);
rectangles[i] = (VkRectLayerKHR) {
.layer = 0,
.offset.x = (int) floor (r.x * scale),
.offset.y = (int) floor (r.y * scale),
.extent.width = (int) ceil (r.width * scale),
.extent.height = (int) ceil (r.height * scale),
};
}
}
else
{
rectangles = NULL;
n_regions = 0;
}
regions = (VkPresentRegionsKHR) {
.sType = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR,
.swapchainCount = 1,
.pRegions = &(VkPresentRegionKHR) {
.rectangleCount = n_regions,
.pRectangles = rectangles,
},
};
if (priv->has_present_region)
regionsptr = &regions;
GDK_VK_CHECK (vkQueuePresentKHR, gdk_vulkan_context_get_queue (context),
&(VkPresentInfoKHR) {
@@ -629,7 +707,14 @@ gdk_vulkan_context_end_frame (GdkDrawContext *draw_context,
.pImageIndices = (uint32_t[]) {
priv->draw_index
},
.pNext = regionsptr,
.pNext = rectangles == NULL ? NULL : &(VkPresentRegionsKHR) {
.sType = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR,
.swapchainCount = 1,
.pRegions = &(VkPresentRegionKHR) {
.rectangleCount = n_regions,
.pRectangles = rectangles,
},
}
});
cairo_region_destroy (priv->regions[priv->draw_index]);
@@ -699,7 +784,7 @@ gdk_vulkan_context_real_init (GInitable *initable,
VkBool32 supported;
uint32_t i;
priv->vulkan_ref = gdk_display_ref_vulkan (display, error);
priv->vulkan_ref = gdk_display_init_vulkan (display, error);
if (!priv->vulkan_ref)
return FALSE;
@@ -819,9 +904,6 @@ gdk_vulkan_context_real_init (GInitable *initable,
if (priv->formats[GDK_MEMORY_U16].vk_format.format == VK_FORMAT_UNDEFINED)
priv->formats[GDK_MEMORY_U16] = priv->formats[GDK_MEMORY_FLOAT32];
priv->has_present_region = physical_device_supports_extension (display->vk_physical_device,
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
if (!gdk_vulkan_context_check_swapchain (context, error))
goto out_surface;
@@ -1122,10 +1204,8 @@ gdk_vulkan_save_pipeline_cache_cb (gpointer data)
}
void
gdk_vulkan_context_pipeline_cache_updated (GdkVulkanContext *self)
gdk_display_vulkan_pipeline_cache_updated (GdkDisplay *display)
{
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (self));
g_clear_handle_id (&display->vk_save_pipeline_cache_source, g_source_remove);
display->vk_save_pipeline_cache_source = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE - 10,
10, /* random choice that is not now */
@@ -1150,14 +1230,6 @@ gdk_display_create_pipeline_cache (GdkDisplay *display)
}
}
VkPipelineCache
gdk_vulkan_context_get_pipeline_cache (GdkVulkanContext *self)
{
g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (self), NULL);
return gdk_draw_context_get_display (GDK_DRAW_CONTEXT (self))->vk_pipeline_cache;
}
/**
* gdk_vulkan_context_get_image_format:
* @context: a `GdkVulkanContext`
@@ -1268,6 +1340,7 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
const char *override;
gboolean list_devices;
int first, last;
GdkVulkanFeatures skip_features;
uint32_t n_devices = 0;
GDK_VK_CHECK(vkEnumeratePhysicalDevices, display->vk_instance, &n_devices, NULL);
@@ -1287,6 +1360,10 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
first = 0;
last = n_devices;
skip_features = gdk_parse_debug_var ("GDK_VULKAN_SKIP",
gsk_vulkan_feature_keys,
G_N_ELEMENTS (gsk_vulkan_feature_keys));
override = g_getenv ("GDK_VULKAN_DEVICE");
list_devices = FALSE;
if (override)
@@ -1368,11 +1445,14 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
for (i = first; i < last; i++)
{
GdkVulkanFeatures features, device_features;
uint32_t n_queue_props;
if (!physical_device_supports_extension (devices[i], VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
if (!physical_device_check_features (devices[i], &device_features))
continue;
features = device_features & ~skip_features;
vkGetPhysicalDeviceQueueFamilyProperties (devices[i], &n_queue_props, NULL);
VkQueueFamilyProperties *queue_props = g_newa (VkQueueFamilyProperties, n_queue_props);
vkGetPhysicalDeviceQueueFamilyProperties (devices[i], &n_queue_props, queue_props);
@@ -1381,18 +1461,22 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
if (queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT)
{
GPtrArray *device_extensions;
gboolean has_incremental_present;
has_incremental_present = physical_device_supports_extension (devices[i],
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
device_extensions = g_ptr_array_new ();
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_SWAPCHAIN_EXTENSION_NAME);
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
g_ptr_array_add (device_extensions, (gpointer) VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
if (has_incremental_present)
if (features & GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING)
g_ptr_array_add (device_extensions, (gpointer) VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
if (features & GDK_VULKAN_FEATURE_DMABUF)
{
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
g_ptr_array_add (device_extensions, (gpointer) VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
}
if (features & (GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT | GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT))
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);
if (features & GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT)
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
#define ENABLE_IF(flag) ((features & (flag)) ? VK_TRUE : VK_FALSE)
GDK_DISPLAY_DEBUG (display, VULKAN, "Using Vulkan device %u, queue %u", i, j);
if (GDK_VK_CHECK (vkCreateDevice, devices[i],
&(VkDeviceCreateInfo) {
@@ -1406,15 +1490,19 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
},
.enabledExtensionCount = device_extensions->len,
.ppEnabledExtensionNames = (const char * const *) device_extensions->pdata,
.pNext = &(VkPhysicalDeviceVulkan12Features) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
.shaderSampledImageArrayNonUniformIndexing = VK_TRUE,
.shaderStorageBufferArrayNonUniformIndexing = VK_TRUE,
.descriptorIndexing = VK_TRUE,
.descriptorBindingPartiallyBound = VK_TRUE,
.descriptorBindingVariableDescriptorCount = VK_TRUE,
.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE,
.descriptorBindingStorageBufferUpdateAfterBind = VK_TRUE,
.pNext = &(VkPhysicalDeviceVulkan11Features) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
.samplerYcbcrConversion = ENABLE_IF (GDK_VULKAN_FEATURE_YCBCR),
.pNext = &(VkPhysicalDeviceVulkan12Features) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
.shaderSampledImageArrayNonUniformIndexing = ENABLE_IF (GDK_VULKAN_FEATURE_NONUNIFORM_INDEXING),
.shaderStorageBufferArrayNonUniformIndexing = ENABLE_IF (GDK_VULKAN_FEATURE_NONUNIFORM_INDEXING),
.descriptorIndexing = ENABLE_IF (GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING),
.descriptorBindingPartiallyBound = ENABLE_IF (GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING),
.descriptorBindingVariableDescriptorCount = ENABLE_IF (GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING),
.descriptorBindingSampledImageUpdateAfterBind = ENABLE_IF (GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING),
.descriptorBindingStorageBufferUpdateAfterBind = ENABLE_IF (GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING),
}
}
},
NULL,
@@ -1423,12 +1511,26 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
g_ptr_array_unref (device_extensions);
continue;
}
#undef ENABLE_IF
g_ptr_array_unref (device_extensions);
display->vk_physical_device = devices[i];
vkGetDeviceQueue(display->vk_device, j, 0, &display->vk_queue);
display->vk_queue_family_index = j;
display->vulkan_features = features;
GDK_DISPLAY_DEBUG (display, VULKAN, "Enabled features (use GDK_VULKAN_SKIP env var to disable):");
for (i = 0; i < G_N_ELEMENTS (gsk_vulkan_feature_keys); i++)
{
GDK_DISPLAY_DEBUG (display, VULKAN, " %s: %s",
gsk_vulkan_feature_keys[i].key,
(features & gsk_vulkan_feature_keys[i].value) ? "YES" :
((skip_features & gsk_vulkan_feature_keys[i].value) ? "disabled via env var" :
(((device_features & gsk_vulkan_feature_keys[i].value) == 0) ? "not supported" :
"Hum, what? This should not happen.")));
}
return TRUE;
}
}
@@ -1625,9 +1727,23 @@ gdk_display_create_vulkan_instance (GdkDisplay *display,
return TRUE;
}
/*
* gdk_display_init_vulkan:
* @display: a display
* @error: A potential error message
*
* Initializes Vulkan and returns an error on failure.
*
* If Vulkan is already initialized, this function returns
* %TRUE and increases the refcount of the existing instance.
*
* You need to gdk_display_unref_vulkan() to close it again.
*
* Returns: %TRUE if Vulkan is initialized.
**/
gboolean
gdk_display_ref_vulkan (GdkDisplay *display,
GError **error)
gdk_display_init_vulkan (GdkDisplay *display,
GError **error)
{
if (display->vulkan_refcount == 0)
{
@@ -1640,6 +1756,23 @@ gdk_display_ref_vulkan (GdkDisplay *display,
return TRUE;
}
/*
* gdk_display_ref_vulkan:
* @display: a GdkDisplay
*
* Increases the refcount of an existing Vulkan instance.
*
* This function must not be called if Vulkan may not be initialized
* yet, call gdk_display_init_vulkan() in that case.
**/
void
gdk_display_ref_vulkan (GdkDisplay *display)
{
g_assert (display->vulkan_refcount > 0);
display->vulkan_refcount++;
}
void
gdk_display_unref_vulkan (GdkDisplay *display)
{
@@ -1653,6 +1786,9 @@ gdk_display_unref_vulkan (GdkDisplay *display)
if (display->vulkan_refcount > 0)
return;
GDK_DEBUG (VULKAN, "Closing Vulkan instance");
display->vulkan_features = 0;
g_clear_pointer (&display->vk_dmabuf_formats, gdk_dmabuf_formats_unref);
g_hash_table_iter_init (&iter, display->vk_shader_modules);
while (g_hash_table_iter_next (&iter, &key, &value))
{
@@ -1690,6 +1826,99 @@ gdk_display_unref_vulkan (GdkDisplay *display)
display->vk_instance = VK_NULL_HANDLE;
}
#ifdef HAVE_DMABUF
/* Hack. We don't include gsk/gsk.h here to avoid a build order problem
* with the generated header gskenumtypes.h, so we need to hack around
* a bit to access the gsk api we need.
*/
typedef struct _GskRenderer GskRenderer;
extern GskRenderer * gsk_vulkan_renderer_new (void);
extern gboolean gsk_renderer_realize_for_display (GskRenderer *renderer,
GdkDisplay *display,
GError **error);
GdkDmabufDownloader *
gdk_vulkan_get_dmabuf_downloader (GdkDisplay *display,
GdkDmabufFormatsBuilder *builder)
{
GdkDmabufFormatsBuilder *vulkan_builder;
GskRenderer *renderer;
VkDrmFormatModifierPropertiesEXT modifier_list[100];
VkDrmFormatModifierPropertiesListEXT modifier_props = {
.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
.pNext = NULL,
.pDrmFormatModifierProperties = modifier_list,
};
VkFormatProperties2 props = {
.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
.pNext = &modifier_props,
};
VkFormat vk_format;
guint32 fourcc;
GError *error = NULL;
gsize i, j;
g_assert (display->vk_dmabuf_formats == NULL);
if (!gdk_display_init_vulkan (display, NULL))
return NULL;
if ((display->vulkan_features & GDK_VULKAN_FEATURE_DMABUF) == 0)
return NULL;
vulkan_builder = gdk_dmabuf_formats_builder_new ();
for (i = 0; gdk_dmabuf_vk_get_nth (i, &fourcc, &vk_format); i++)
{
if (vk_format == VK_FORMAT_UNDEFINED)
continue;
modifier_props.drmFormatModifierCount = sizeof (modifier_list);
vkGetPhysicalDeviceFormatProperties2 (display->vk_physical_device,
vk_format,
&props);
g_warn_if_fail (modifier_props.drmFormatModifierCount < sizeof (modifier_list));
for (j = 0; j < modifier_props.drmFormatModifierCount; j++)
{
GDK_DISPLAY_DEBUG (display, DMABUF,
"Vulkan supports dmabuf format %.4s::%016llx with %u planes and features 0x%x",
(char *) &fourcc,
(long long unsigned) modifier_list[j].drmFormatModifier,
modifier_list[j].drmFormatModifierPlaneCount,
modifier_list[j].drmFormatModifierTilingFeatures);
if (modifier_list[j].drmFormatModifier == DRM_FORMAT_MOD_LINEAR)
continue;
gdk_dmabuf_formats_builder_add_format (vulkan_builder,
fourcc,
modifier_list[j].drmFormatModifier);
}
}
display->vk_dmabuf_formats = gdk_dmabuf_formats_builder_free_to_formats (vulkan_builder);
gdk_dmabuf_formats_builder_add_formats (builder, display->vk_dmabuf_formats);
renderer = gsk_vulkan_renderer_new ();
if (!gsk_renderer_realize_for_display (renderer, display, &error))
{
g_warning ("Failed to realize GL renderer: %s", error->message);
g_error_free (error);
g_object_unref (renderer);
return NULL;
}
return GDK_DMABUF_DOWNLOADER (renderer);
}
#endif
VkShaderModule
gdk_display_get_vk_shader_module (GdkDisplay *self,
const char *resource_name)
-35
View File
@@ -26,10 +26,6 @@
#include <gdk/gdktypes.h>
#ifdef GDK_RENDERING_VULKAN
#include <vulkan/vulkan.h>
#endif
G_BEGIN_DECLS
#define GDK_TYPE_VULKAN_CONTEXT (gdk_vulkan_context_get_type ())
@@ -44,37 +40,6 @@ GQuark gdk_vulkan_error_quark (void);
GDK_AVAILABLE_IN_ALL
GType gdk_vulkan_context_get_type (void) G_GNUC_CONST;
#ifndef __GI_SCANNER__
#ifdef GDK_RENDERING_VULKAN
GDK_AVAILABLE_IN_ALL
const char * gdk_vulkan_strerror (VkResult result);
GDK_AVAILABLE_IN_ALL
VkInstance gdk_vulkan_context_get_instance (GdkVulkanContext *context);
GDK_AVAILABLE_IN_ALL
VkPhysicalDevice gdk_vulkan_context_get_physical_device (GdkVulkanContext *context);
GDK_AVAILABLE_IN_ALL
VkDevice gdk_vulkan_context_get_device (GdkVulkanContext *context);
GDK_AVAILABLE_IN_ALL
VkQueue gdk_vulkan_context_get_queue (GdkVulkanContext *context);
GDK_AVAILABLE_IN_ALL
uint32_t gdk_vulkan_context_get_queue_family_index (GdkVulkanContext *context);
GDK_AVAILABLE_IN_ALL
VkFormat gdk_vulkan_context_get_image_format (GdkVulkanContext *context);
GDK_AVAILABLE_IN_ALL
uint32_t gdk_vulkan_context_get_n_images (GdkVulkanContext *context);
GDK_AVAILABLE_IN_ALL
VkImage gdk_vulkan_context_get_image (GdkVulkanContext *context,
guint id);
GDK_AVAILABLE_IN_ALL
uint32_t gdk_vulkan_context_get_draw_index (GdkVulkanContext *context);
GDK_AVAILABLE_IN_ALL
VkSemaphore gdk_vulkan_context_get_draw_semaphore (GdkVulkanContext *context);
#endif /* GDK_RENDERING_VULKAN */
#endif /* __GI_SCANNER__ */
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkVulkanContext, g_object_unref)
G_END_DECLS
+24 -3
View File
@@ -23,6 +23,8 @@
#include "gdkvulkancontext.h"
#include "gdkdebugprivate.h"
#include "gdkdmabufprivate.h"
#include "gdkdmabufdownloaderprivate.h"
#include "gdkdrawcontextprivate.h"
#include "gdkenums.h"
@@ -55,6 +57,8 @@ struct _GdkVulkanContextClass
#ifdef GDK_RENDERING_VULKAN
const char * gdk_vulkan_strerror (VkResult result);
static inline VkResult
gdk_vulkan_handle_result (VkResult res,
const char *called_function)
@@ -69,15 +73,32 @@ gdk_vulkan_handle_result (VkResult res,
#define GDK_VK_CHECK(func, ...) gdk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func))
gboolean gdk_display_ref_vulkan (GdkDisplay *display,
gboolean gdk_display_init_vulkan (GdkDisplay *display,
GError **error);
void gdk_display_ref_vulkan (GdkDisplay *display);
void gdk_display_unref_vulkan (GdkDisplay *display);
#ifdef HAVE_DMABUF
GdkDmabufDownloader * gdk_vulkan_get_dmabuf_downloader (GdkDisplay *display,
GdkDmabufFormatsBuilder *builder);
#endif
VkShaderModule gdk_display_get_vk_shader_module (GdkDisplay *display,
const char *resource_name);
VkPipelineCache gdk_vulkan_context_get_pipeline_cache (GdkVulkanContext *self);
void gdk_vulkan_context_pipeline_cache_updated (GdkVulkanContext *self);
void gdk_display_vulkan_pipeline_cache_updated (GdkDisplay *display);
VkInstance gdk_vulkan_context_get_instance (GdkVulkanContext *context);
VkPhysicalDevice gdk_vulkan_context_get_physical_device (GdkVulkanContext *context);
VkDevice gdk_vulkan_context_get_device (GdkVulkanContext *context);
VkQueue gdk_vulkan_context_get_queue (GdkVulkanContext *context);
uint32_t gdk_vulkan_context_get_queue_family_index (GdkVulkanContext *context);
VkFormat gdk_vulkan_context_get_image_format (GdkVulkanContext *context);
uint32_t gdk_vulkan_context_get_n_images (GdkVulkanContext *context);
VkImage gdk_vulkan_context_get_image (GdkVulkanContext *context,
guint id);
uint32_t gdk_vulkan_context_get_draw_index (GdkVulkanContext *context);
VkSemaphore gdk_vulkan_context_get_draw_semaphore (GdkVulkanContext *context);
GdkMemoryFormat gdk_vulkan_context_get_offscreen_format (GdkVulkanContext *context,
GdkMemoryDepth depth);
+14 -5
View File
@@ -137,8 +137,9 @@ gdk_load_png (GBytes *bytes,
png_struct *png = NULL;
png_info *info;
guint width, height;
gsize i, stride;
int depth, color_type;
int interlace, stride;
int interlace;
GdkMemoryFormat format;
guchar *buffer = NULL;
guchar **row_pointers = NULL;
@@ -263,9 +264,14 @@ gdk_load_png (GBytes *bytes,
}
bpp = gdk_memory_format_bytes_per_pixel (format);
stride = width * bpp;
if (stride % 8)
stride += 8 - stride % 8;
if (!g_size_checked_mul (&stride, width, bpp) ||
!g_size_checked_add (&stride, stride, (8 - stride % 8) % 8))
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_TOO_LARGE,
_("Image stride too large for image size %ux%u"), width, height);
return NULL;
}
buffer = g_try_malloc_n (height, stride);
row_pointers = g_try_malloc_n (height, sizeof (char *));
@@ -281,7 +287,7 @@ gdk_load_png (GBytes *bytes,
return NULL;
}
for (int i = 0; i < height; i++)
for (i = 0; i < height; i++)
row_pointers[i] = &buffer[i * stride];
png_read_image (png, row_pointers);
@@ -413,6 +419,9 @@ gdk_save_png (GdkTexture *texture)
if (!png)
return NULL;
/* 2^31-1 is the maximum size for PNG files */
png_set_user_limits (png, (1u << 31) - 1, (1u << 31) - 1);
info = png_create_info_struct (png);
if (!info)
{
+1 -1
View File
@@ -188,7 +188,7 @@ _edge_snapping_motion (EdgeSnapping *self,
edge_snapping_constrain_horizontal (self, change.x, &self->geometry, &new_window);
}
/* Now constrain veritcally */
/* Now constrain vertically */
if (change.y)
{
edge_snapping_constrain_vertical (self, change.y, &self->workarea, &new_window, FALSE);
+1 -1
View File
@@ -170,7 +170,7 @@ static int getting_events = 0;
************************************************************/
/* The states in our state machine, see comments in select_thread_func()
* for descriptiions of each state
* for descriptions of each state
*/
typedef enum {
BEFORE_START,
+1 -1
View File
@@ -598,7 +598,7 @@ gdk_macos_gl_context_make_current (GdkGLContext *context,
* are submitted.
*
* TODO: investigate if we need this because we may switch contexts
* durring composition and only need it when returning to a
* during composition and only need it when returning to a
* previous context that uses the other context.
*/
if (current != NULL)
+1 -1
View File
@@ -194,7 +194,7 @@ _gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display,
if ((image->width % cursor_scale != 0) ||
(image->height % cursor_scale != 0))
{
g_warning (G_STRLOC " cursor image size (%dx%d) not an integer"
g_warning (G_STRLOC " cursor image size (%dx%d) not an integer "
"multiple of scale (%d)", image->width, image->height,
cursor_scale);
cursor_scale = 1;
+2 -8
View File
@@ -1796,6 +1796,7 @@ static TranslationEntry translations[] = {
{ FALSE, "org.gnome.desktop.wm.preferences", "action-right-click-titlebar", "gtk-titlebar-right-click", G_TYPE_STRING, { .s = "menu" } },
{ FALSE, "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } },
{ FALSE, "org.gnome.desktop.a11y.interface", "high-contrast", "high-contast", G_TYPE_NONE, { .b = FALSE } },
{ FALSE, "org.gnome.desktop.a11y.interface", "show-status-shapes", "gtk-show-status-shapes", G_TYPE_BOOLEAN, { .b = FALSE } },
/* Note, this setting doesn't exist, the portal and gsd fake it */
{ FALSE, "org.gnome.fontconfig", "serial", "gtk-fontconfig-timestamp", G_TYPE_NONE, { .i = 0 } },
};
@@ -1845,13 +1846,6 @@ find_translation_entry_by_setting (const char *setting)
return NULL;
}
static void
high_contrast_changed (GdkDisplay *display)
{
gdk_display_setting_changed (display, "gtk-theme-name");
gdk_display_setting_changed (display, "gtk-icon-theme-name");
}
static void
settings_changed (GSettings *settings,
const char *key,
@@ -1866,7 +1860,7 @@ settings_changed (GSettings *settings,
if (entry->type != G_TYPE_NONE)
gdk_display_setting_changed (display, entry->setting);
else if (strcmp (key, "high-contrast") == 0)
high_contrast_changed (display);
gdk_display_setting_changed (display, "gtk-theme-name");
else
update_xft_settings (display);
}
+1
View File
@@ -2859,6 +2859,7 @@ tablet_tool_handle_proximity_out (void *data,
gdk_device_update_tool (tablet->stylus_device, NULL);
g_clear_object (&tablet->pointer_info.cursor);
tablet->pointer_info.cursor_is_default = FALSE;
}
static double *
+6 -5
View File
@@ -1973,8 +1973,10 @@ gdk_wayland_toplevel_titlebar_gesture (GdkToplevel *toplevel,
return FALSE;
seat = gdk_display_get_default_seat (surface->display);
wl_seat = gdk_wayland_seat_get_wl_seat (seat);
if (!seat)
return FALSE;
wl_seat = gdk_wayland_seat_get_wl_seat (seat);
serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (seat), NULL);
gtk_surface1_titlebar_gesture (wayland_toplevel->display_server.gtk_surface,
@@ -2155,15 +2157,14 @@ gdk_wayland_toplevel_focus (GdkToplevel *toplevel,
GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (toplevel);
GdkDisplay *display = gdk_surface_get_display (surface);
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GdkWaylandSeat *seat =
GDK_WAYLAND_SEAT (gdk_display_get_default_seat (display));
gchar *startup_id = NULL;
startup_id = g_steal_pointer (&display_wayland->startup_notification_id);
if (display_wayland->xdg_activation)
if (seat && display_wayland->xdg_activation)
{
GdkWaylandSeat *seat =
GDK_WAYLAND_SEAT (gdk_display_get_default_seat (display));
/* If the focus request does not have a startup ID associated, get a
* new token to activate the window.
*/
+2 -2
View File
@@ -28,7 +28,7 @@ GTK has two clipboards - normal clipboard and primary clipboard
Primary clipboard is only handled
internally by GTK (it's not portable to Windows).
("C:" means clipboard client (requestor), "S:" means clipboard server (provider))
("C:" means clipboard client (requester), "S:" means clipboard server (provider))
("transmute" here means "change the format of some data"; this term is used here
instead of "convert" to avoid clashing with the old g(t|d)k_selection_convert() APIs,
which are completely unrelated)
@@ -1356,7 +1356,7 @@ inner_clipboard_window_procedure (HWND hwnd,
else if (returned_render->main_thread_data_handle)
{
BOOL set_data_succeeded;
/* The requestor is holding the clipboard, no
/* The requester is holding the clipboard, no
* OpenClipboard() is required/possible
*/
GDK_NOTE (DND,
+2 -2
View File
@@ -3029,7 +3029,7 @@ gdk_event_translate (MSG *msg,
unset_bits |= GDK_TOPLEVEL_STATE_MAXIMIZED;
/*
* If we are minizing, pause all surface layout computations, and re-start the
* If we are minimizing, pause all surface layout computations, and re-start the
* computation once we are coming out of a minimized state
*/
if (!(old_state & GDK_TOPLEVEL_STATE_MINIMIZED) && set_bits & GDK_TOPLEVEL_STATE_MINIMIZED)
@@ -3045,7 +3045,7 @@ gdk_event_translate (MSG *msg,
/* Whenever one window changes iconified state we need to also
* change the iconified state in all transient related windows,
* as windows doesn't give icons for transient childrens.
* as windows doesn't give icons for transient children.
*/
if ((old_state & GDK_TOPLEVEL_STATE_MINIMIZED) !=
(new_state & GDK_TOPLEVEL_STATE_MINIMIZED))
+1 -1
View File
@@ -211,7 +211,7 @@ struct _GdkW32DragMoveResizeContext
gboolean revealed;
/* Arrays of GdkRectangle pairs, describing the areas of the virtual
* desktop that trigger various AeroSnap window transofrmations
* desktop that trigger various AeroSnap window transformations
* Coordinates are GDK screen coordinates.
*/
GArray *halfleft_regions;
+8
View File
@@ -39,9 +39,17 @@
G_DEFINE_ABSTRACT_TYPE (GdkX11GLContext, gdk_x11_gl_context, GDK_TYPE_GL_CONTEXT)
static void
gdk_x11_gl_context_empty_frame (GdkDrawContext *draw_context)
{
}
static void
gdk_x11_gl_context_class_init (GdkX11GLContextClass *klass)
{
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
draw_context_class->empty_frame = gdk_x11_gl_context_empty_frame;
}
static void
+1
View File
@@ -39,6 +39,7 @@ static const struct {
{"Gtk/CursorThemeSize", "gtk-cursor-theme-size"},
{"Gtk/ColorScheme", "gtk-color-scheme"},
{"Gtk/EnableAnimations", "gtk-enable-animations"},
{"Gtk/ShowStatusStates", "gtk-show-status-shapes"},
{"Xft/Antialias", "gtk-xft-antialias"},
{"Xft/Hinting", "gtk-xft-hinting"},
{"Xft/HintStyle", "gtk-xft-hintstyle"},
+1
View File
@@ -35,6 +35,7 @@ G_DEFINE_TYPE (GskBroadwayRenderer, gsk_broadway_renderer, GSK_TYPE_RENDERER)
static gboolean
gsk_broadway_renderer_realize (GskRenderer *renderer,
GdkDisplay *display,
GdkSurface *surface,
GError **error)
{
+14 -5
View File
@@ -23,20 +23,24 @@ def replace_if_changed(new, old):
gl_source_shaders = []
ngl_source_shaders = []
vulkan_compiled_shaders = []
gpu_vulkan_compiled_shaders = []
vulkan_shaders = []
for f in sys.argv[2:]:
if f.endswith('.glsl'):
if f.startswith('ngl'):
ngl_source_shaders.append(f);
if f.find('gsk/gpu') > -1:
ngl_source_shaders.append(f)
else:
gl_source_shaders.append(f)
elif f.endswith('.spv'):
vulkan_compiled_shaders.append(f)
if f.find('gsk/gpu') > -1:
gpu_vulkan_compiled_shaders.append(f)
else:
vulkan_compiled_shaders.append(f)
elif f.endswith('.frag') or f.endswith('.vert'):
vulkan_shaders.append(f)
else:
sys.exit(-1) # FIXME: error message
raise Exception(f"No idea what XML to generate for {f}")
xml = '''<?xml version='1.0' encoding='UTF-8'?>
<gresources>
@@ -50,7 +54,7 @@ for f in gl_source_shaders:
xml += '\n'
for f in ngl_source_shaders:
xml += ' <file alias=\'ngl/{0}\'>ngl/resources/{0}</file>\n'.format(os.path.basename(f))
xml += ' <file alias=\'shaders/gl/{0}\'>gpu/shaders/{0}</file>\n'.format(os.path.basename(f))
xml += '\n'
@@ -59,6 +63,11 @@ for f in vulkan_compiled_shaders:
xml += '\n'
for f in gpu_vulkan_compiled_shaders:
xml += ' <file alias=\'shaders/vulkan/{0}\'>gpu/shaders/{0}</file>\n'.format(os.path.basename(f))
xml += '\n'
for f in vulkan_shaders:
xml += ' <file alias=\'vulkan/{0}\'>vulkan/resources/{0}</file>\n'.format(os.path.basename(f))
+42 -23
View File
@@ -1435,6 +1435,8 @@ gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
switch (format)
{
case 0:
break;
case GL_RGBA8:
glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
break;
@@ -1477,12 +1479,14 @@ gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self)
static GdkMemoryFormat
memory_format_gl_format (GskGLCommandQueue *self,
GdkMemoryFormat data_format,
gboolean ensure_mipmap,
gboolean *out_can_mipmap,
GLint *gl_internalformat,
GLenum *gl_format,
GLenum *gl_type,
GLint gl_swizzle[4])
{
GdkGLMemoryFlags flags;
GdkGLMemoryFlags flags, required_flags;
GdkMemoryFormat alt_format;
const GdkMemoryFormat *fallbacks;
gsize i;
@@ -1491,20 +1495,27 @@ memory_format_gl_format (GskGLCommandQueue *self,
if (gdk_memory_format_alpha (data_format) == GDK_MEMORY_ALPHA_STRAIGHT)
data_format = gdk_memory_format_get_premultiplied (data_format);
required_flags = GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE;
if (ensure_mipmap)
required_flags |= GDK_GL_FORMAT_RENDERABLE;
/* First, try the format itself */
flags = gdk_gl_context_get_format_flags (self->context, data_format);
if ((flags & (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE)) == (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE))
if ((flags & required_flags) == required_flags)
{
gdk_memory_format_gl_format (data_format,
gdk_gl_context_get_use_es (self->context),
gl_internalformat,
gl_format,
gl_type,
gl_swizzle);
*out_can_mipmap = (flags & GDK_GL_FORMAT_RENDERABLE) ? TRUE : FALSE;
return data_format;
}
/* Second, try the potential RGBA format */
if (gdk_memory_format_gl_rgba_format (data_format,
gdk_gl_context_get_use_es (self->context),
&alt_format,
gl_internalformat,
gl_format,
@@ -1512,12 +1523,15 @@ memory_format_gl_format (GskGLCommandQueue *self,
gl_swizzle))
{
flags = gdk_gl_context_get_format_flags (self->context, alt_format);
if ((flags & (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE)) == (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE))
if ((flags & required_flags) == required_flags)
{
*out_can_mipmap = (flags & GDK_GL_FORMAT_RENDERABLE) ? TRUE : FALSE;
if (self->can_swizzle)
return data_format;
gdk_memory_format_gl_format (alt_format,
gdk_gl_context_get_use_es (self->context),
gl_internalformat,
gl_format,
gl_type,
@@ -1532,13 +1546,16 @@ memory_format_gl_format (GskGLCommandQueue *self,
for (i = 0; fallbacks[i] != -1; i++)
{
flags = gdk_gl_context_get_format_flags (self->context, fallbacks[i]);
if (((flags & (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE)) == (GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE)))
if (((flags & required_flags) == required_flags))
{
gdk_memory_format_gl_format (fallbacks[i],
gdk_gl_context_get_use_es (self->context),
gl_internalformat,
gl_format,
gl_type,
gl_swizzle);
*out_can_mipmap = (flags & GDK_GL_FORMAT_RENDERABLE) ? TRUE : FALSE;
return fallbacks[i];
}
}
@@ -1552,32 +1569,24 @@ static void
gsk_gl_command_queue_do_upload_texture_chunk (GskGLCommandQueue *self,
GdkTexture *texture,
int x,
int y)
int y,
GdkMemoryFormat data_format,
GLenum gl_format,
GLenum gl_type,
GLint gl_swizzle[4])
{
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
const guchar *data;
gsize stride;
GBytes *bytes;
GdkTextureDownloader downloader;
GdkMemoryFormat data_format;
int width, height;
GLint gl_internalformat;
GLenum gl_format;
GLenum gl_type;
GLint gl_swizzle[4];
gsize bpp;
data_format = gdk_texture_get_format (texture);
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
data_format = memory_format_gl_format (self,
data_format,
&gl_internalformat,
&gl_format,
&gl_type,
gl_swizzle);
if (GSK_DEBUG_CHECK (FALLBACK) &&
data_format != gdk_texture_get_format (texture))
{
@@ -1652,8 +1661,10 @@ gsk_gl_command_queue_do_upload_texture_chunk (GskGLCommandQueue *self,
int
gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self,
gboolean ensure_mipmap,
unsigned int n_chunks,
GskGLTextureChunk *chunks)
GskGLTextureChunk *chunks,
gboolean *out_can_mipmap)
{
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
int width, height;
@@ -1684,7 +1695,7 @@ gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self,
height = MIN (height, self->max_texture_size);
}
texture_id = gsk_gl_command_queue_create_texture (self, width, height, GL_RGBA8);
texture_id = gsk_gl_command_queue_create_texture (self, width, height, 0);
if (texture_id == -1)
return texture_id;
@@ -1698,6 +1709,8 @@ gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self,
data_format = gdk_texture_get_format (chunks[0].texture);
data_format = memory_format_gl_format (self,
data_format,
ensure_mipmap,
out_can_mipmap,
&gl_internalformat,
&gl_format,
&gl_type,
@@ -1708,7 +1721,7 @@ gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self,
for (unsigned int i = 0; i < n_chunks; i++)
{
GskGLTextureChunk *c = &chunks[i];
gsk_gl_command_queue_do_upload_texture_chunk (self, c->texture, c->x, c->y);
gsk_gl_command_queue_do_upload_texture_chunk (self, c->texture, c->x, c->y, data_format, gl_format, gl_type, gl_swizzle);
}
/* Restore previous texture state if any */
@@ -1726,9 +1739,15 @@ gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self,
int
gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
GdkTexture *texture)
GdkTexture *texture,
gboolean ensure_mipmap,
gboolean *out_can_mipmap)
{
return gsk_gl_command_queue_upload_texture_chunks (self, 1, &(GskGLTextureChunk){ texture, 0, 0});
return gsk_gl_command_queue_upload_texture_chunks (self,
ensure_mipmap,
1,
&(GskGLTextureChunk){ texture, 0, 0},
out_can_mipmap);
}
void
+6 -2
View File
@@ -313,7 +313,9 @@ void gsk_gl_command_queue_execute (GskGLCommandQueue
const cairo_region_t *scissor,
guint default_framebuffer);
int gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
GdkTexture *texture);
GdkTexture *texture,
gboolean ensure_mipmap,
gboolean *out_can_mipmap);
int gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
int width,
int height,
@@ -327,8 +329,10 @@ typedef struct {
} GskGLTextureChunk;
int gsk_gl_command_queue_upload_texture_chunks(GskGLCommandQueue *self,
gboolean ensure_mipmap,
unsigned int n_chunks,
GskGLTextureChunk *chunks);
GskGLTextureChunk *chunks,
gboolean *out_can_mipmap);
guint gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self);
gboolean gsk_gl_command_queue_create_render_target (GskGLCommandQueue *self,
+17 -7
View File
@@ -925,6 +925,7 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
guint texture_id;
int height;
int width;
gboolean can_mipmap = FALSE;
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0);
@@ -938,17 +939,20 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
t = gdk_texture_get_render_data (texture, self);
if (t && t->texture_id)
{
if (ensure_mipmap && !t->has_mipmap)
if (ensure_mipmap && t->can_mipmap && !t->has_mipmap)
{
glBindTexture (GL_TEXTURE_2D, t->texture_id);
glGenerateMipmap (GL_TEXTURE_2D);
t->has_mipmap = TRUE;
}
return t->texture_id;
if (!ensure_mipmap || t->has_mipmap)
return t->texture_id;
gdk_texture_clear_render_data (texture);
}
if (GDK_IS_DMABUF_TEXTURE (texture))
if (GDK_IS_DMABUF_TEXTURE (texture) && !ensure_mipmap)
{
texture_id = gsk_gl_driver_import_dmabuf_texture (self, GDK_DMABUF_TEXTURE (texture));
}
@@ -975,7 +979,7 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
*/
gdk_gl_context_make_current (context);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, GDK_TEXTURE (downloaded_texture));
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, GDK_TEXTURE (downloaded_texture), ensure_mipmap, &can_mipmap);
}
width = gdk_texture_get_width (texture);
@@ -984,8 +988,10 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
t = gsk_gl_texture_new (texture_id,
width, height,
self->current_frame_id);
t->can_mipmap = can_mipmap;
if (ensure_mipmap)
{
g_assert (can_mipmap);
glBindTexture (GL_TEXTURE_2D, t->texture_id);
glGenerateMipmap (GL_TEXTURE_2D);
t->has_mipmap = TRUE;
@@ -1230,7 +1236,7 @@ gsk_gl_driver_release_render_target (GskGLDriver *self,
* @shader: the shader to lookup or load
* @error: a location for a `GError`
*
* Attepts to load @shader from the shader cache.
* Attempts to load @shader from the shader cache.
*
* If it has not been loaded, then it will compile the shader on demand.
*
@@ -1433,6 +1439,7 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
GdkMemoryTexture *memtex2 = NULL;
GdkMemoryTexture *memtex3 = NULL;
GdkMemoryTexture *memtex4 = NULL;
gboolean can_mipmap = TRUE, slice_can_mipmap;
g_assert (GSK_IS_GL_DRIVER (self));
g_assert (GDK_IS_TEXTURE (texture));
@@ -1694,7 +1701,7 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
n_chunks++;
}
texture_id = gsk_gl_command_queue_upload_texture_chunks (self->command_queue, n_chunks, chunks);
texture_id = gsk_gl_command_queue_upload_texture_chunks (self->command_queue, TRUE, n_chunks, chunks, &slice_can_mipmap);
glBindTexture (GL_TEXTURE_2D, texture_id);
glGenerateMipmap (GL_TEXTURE_2D);
@@ -1707,10 +1714,12 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
GdkTexture *subtex;
subtex = gdk_memory_texture_new_subtexture (memtex, x, y, slice_width, slice_height);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, subtex);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, subtex, FALSE, &slice_can_mipmap);
g_object_unref (subtex);
}
can_mipmap &= slice_can_mipmap;
slices[slice_index].rect.x = x;
slices[slice_index].rect.y = y;
slices[slice_index].rect.width = slice_width;
@@ -1737,6 +1746,7 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
t = gsk_gl_texture_new (0,
tex_width, tex_height,
self->current_frame_id);
t->can_mipmap = can_mipmap;
t->has_mipmap = ensure_mipmap;
/* Use gsk_gl_texture_free() as destroy notify here since we are
+6 -1
View File
@@ -202,6 +202,7 @@ gsk_gl_driver_get_texture_by_id (GskGLDriver *self,
* gsk_gl_driver_lookup_texture:
* @self: a `GskGLDriver`
* @key: the key for the texture
* @has_mipmap: (out): Return location for whether the texture has a mipmap
*
* Looks up a texture in the texture cache by @key.
*
@@ -211,7 +212,8 @@ gsk_gl_driver_get_texture_by_id (GskGLDriver *self,
*/
static inline guint
gsk_gl_driver_lookup_texture (GskGLDriver *self,
const GskTextureKey *key)
const GskTextureKey *key,
gboolean *has_mipmap)
{
gpointer id;
@@ -222,6 +224,9 @@ gsk_gl_driver_lookup_texture (GskGLDriver *self,
if (texture != NULL)
texture->last_used_in_frame = self->current_frame_id;
if (has_mipmap)
*has_mipmap = texture ? texture->has_mipmap : FALSE;
return GPOINTER_TO_UINT (id);
}
+3 -57
View File
@@ -162,6 +162,7 @@ gsk_gl_renderer_new (void)
static gboolean
gsk_gl_renderer_realize (GskRenderer *renderer,
GdkDisplay *display,
GdkSurface *surface,
GError **error)
{
@@ -169,7 +170,6 @@ gsk_gl_renderer_realize (GskRenderer *renderer,
GskGLRenderer *self = (GskGLRenderer *)renderer;
GdkGLContext *context = NULL;
GskGLDriver *driver = NULL;
GdkDisplay *display;
gboolean ret = FALSE;
gboolean debug_shaders = FALSE;
GdkGLAPI api;
@@ -182,15 +182,9 @@ gsk_gl_renderer_realize (GskRenderer *renderer,
g_assert (self->command_queue == NULL);
if (surface == NULL)
{
display = gdk_display_get_default (); /* FIXME: allow different displays somehow ? */
context = gdk_display_create_gl_context (display, error);
}
context = gdk_display_create_gl_context (display, error);
else
{
display = gdk_surface_get_display (surface);
context = gdk_surface_create_gl_context (surface, error);
}
context = gdk_surface_create_gl_context (surface, error);
if (!context || !gdk_gl_context_realize (context, error))
goto failure;
@@ -537,51 +531,3 @@ gsk_gl_renderer_try_compile_gl_shader (GskGLRenderer *renderer,
return program != NULL;
}
typedef struct {
GskRenderer parent_instance;
} GskNglRenderer;
typedef struct {
GskRendererClass parent_class;
} GskNglRendererClass;
G_DEFINE_TYPE (GskNglRenderer, gsk_ngl_renderer, GSK_TYPE_RENDERER)
static void
gsk_ngl_renderer_init (GskNglRenderer *renderer)
{
}
static gboolean
gsk_ngl_renderer_realize (GskRenderer *renderer,
GdkSurface *surface,
GError **error)
{
g_set_error_literal (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"please use the GL renderer instead");
return FALSE;
}
static void
gsk_ngl_renderer_class_init (GskNglRendererClass *class)
{
GSK_RENDERER_CLASS (class)->realize = gsk_ngl_renderer_realize;
}
/**
* gsk_ngl_renderer_new:
*
* Same as gsk_gl_renderer_new().
*
* Returns: (transfer full): a new GL renderer
*
* Deprecated: 4.4: Use gsk_gl_renderer_new()
*/
GskRenderer *
gsk_ngl_renderer_new (void)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
return g_object_new (gsk_ngl_renderer_get_type (), NULL);
G_GNUC_END_IGNORE_DEPRECATIONS
}
+10 -4
View File
@@ -20,7 +20,13 @@
#pragma once
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#include <gsk/gsk.h>
#define GSK_INCLUDE_WARNING(x) GDK_DEPRECATED_IN_4_14_FOR("#include <gsk/gsk.h> instead of <gsk/gl/gskglrenderer.h> to avoid this warning")
#else
#include <gsk/gsktypes.h>
#define GSK_INCLUDE_WARNING(x) x
#endif
G_BEGIN_DECLS
@@ -35,14 +41,14 @@ G_BEGIN_DECLS
typedef struct _GskGLRenderer GskGLRenderer;
typedef struct _GskGLRendererClass GskGLRendererClass;
GDK_AVAILABLE_IN_4_2
GSK_INCLUDE_WARNING(GDK_AVAILABLE_IN_4_2)
GType gsk_gl_renderer_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_2
GSK_INCLUDE_WARNING(GDK_AVAILABLE_IN_4_2)
GskRenderer *gsk_gl_renderer_new (void);
GDK_DEPRECATED_IN_4_4_FOR (gsk_gl_renderer_get_type)
GSK_INCLUDE_WARNING(GDK_AVAILABLE_IN_ALL)
GType gsk_ngl_renderer_get_type (void) G_GNUC_CONST;
GDK_DEPRECATED_IN_4_4_FOR (gsk_gl_renderer_new)
GSK_INCLUDE_WARNING(GDK_AVAILABLE_IN_ALL)
GskRenderer *gsk_ngl_renderer_new (void);
G_END_DECLS
+2
View File
@@ -22,6 +22,8 @@
#include "gskglrenderer.h"
#include "gskglshader.h"
G_BEGIN_DECLS
gboolean gsk_gl_renderer_try_compile_gl_shader (GskGLRenderer *renderer,
+42 -38
View File
@@ -830,8 +830,8 @@ rounded_rect_scale_corners (const GskRoundedRect *rect,
{
for (guint i = 0; i < G_N_ELEMENTS (out_rect->corner); i++)
{
out_rect->corner[i].width = rect->corner[i].width * fabs (scale_x);
out_rect->corner[i].height = rect->corner[i].height * fabs (scale_y);
out_rect->corner[i].width = rect->corner[i].width * fabsf (scale_x);
out_rect->corner[i].height = rect->corner[i].height * fabsf (scale_y);
}
if (scale_x < 0)
@@ -1173,8 +1173,8 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job,
{
float scale_x = job->scale_x;
float scale_y = job->scale_y;
int surface_width = ceilf (node->bounds.size.width * fabs (scale_x));
int surface_height = ceilf (node->bounds.size.height * fabs (scale_y));
int surface_width = ceilf (node->bounds.size.width * fabsf (scale_x));
int surface_height = ceilf (node->bounds.size.height * fabsf (scale_y));
GdkTexture *texture;
cairo_surface_t *surface;
cairo_surface_t *rendered_surface;
@@ -1190,7 +1190,7 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job,
key.scale_x = scale_x;
key.scale_y = scale_y;
texture_id = gsk_gl_driver_lookup_texture (job->driver, &key);
texture_id = gsk_gl_driver_lookup_texture (job->driver, &key, NULL);
if (texture_id != 0)
goto done;
@@ -1203,11 +1203,11 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job,
surface_width,
surface_height);
cairo_surface_set_device_scale (rendered_surface, fabs (scale_x), fabs (scale_y));
cairo_surface_set_device_scale (rendered_surface, fabsf (scale_x), fabsf (scale_y));
cr = cairo_create (rendered_surface);
cairo_save (cr);
cairo_translate (cr, - floorf (node->bounds.origin.x), - floorf (node->bounds.origin.y));
cairo_translate (cr, - node->bounds.origin.x, - node->bounds.origin.y);
/* Render nodes don't modify state, so casting away the const is fine here */
gsk_render_node_draw_fallback ((GskRenderNode *)node, cr);
cairo_restore (cr);
@@ -1217,16 +1217,16 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job,
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
surface_width,
surface_height);
cairo_surface_set_device_scale (surface, fabs (scale_x), fabs (scale_y));
cairo_surface_set_device_scale (surface, fabsf (scale_x), fabsf (scale_y));
cr = cairo_create (surface);
/* We draw upside down here, so it matches what GL does. */
cairo_save (cr);
cairo_scale (cr, scale_x < 0 ? -1 : 1, scale_y < 0 ? 1 : -1);
cairo_translate (cr, scale_x < 0 ? - surface_width / fabs (scale_x) : 0,
scale_y < 0 ? 0 : - surface_height / fabs (scale_y));
cairo_translate (cr, scale_x < 0 ? - surface_width / fabsf (scale_x) : 0,
scale_y < 0 ? 0 : - surface_height / fabsf (scale_y));
cairo_set_source_surface (cr, rendered_surface, 0, 0);
cairo_rectangle (cr, 0, 0, surface_width / fabs (scale_x), surface_height / fabs (scale_y));
cairo_rectangle (cr, 0, 0, surface_width / fabsf (scale_x), surface_height / fabsf (scale_y));
cairo_fill (cr);
cairo_restore (cr);
cairo_destroy (cr);
@@ -1432,10 +1432,10 @@ blur_node (GskGLRenderJob *job,
offscreen->texture_id = blur_offscreen (job,
offscreen,
texture_width * fabs (scale_x),
texture_height * fabs (scale_y),
blur_radius * fabs (scale_x),
blur_radius * fabs (scale_y));
texture_width * fabsf (scale_x),
texture_height * fabsf (scale_y),
blur_radius * fabsf (scale_x),
blur_radius * fabsf (scale_y));
init_full_texture_region (offscreen);
}
@@ -2019,9 +2019,9 @@ result_is_axis_aligned (GskTransform *transform,
for (guint i = 0; i < 4; i++)
{
p = graphene_quad_get_point (&q, i);
if (fabs (p->x - b1.x) > FLT_EPSILON && fabs (p->x - b2.x) > FLT_EPSILON)
if (fabsf (p->x - b1.x) > FLT_EPSILON && fabsf (p->x - b2.x) > FLT_EPSILON)
return FALSE;
if (fabs (p->y - b1.y) > FLT_EPSILON && fabs (p->y - b2.y) > FLT_EPSILON)
if (fabsf (p->y - b1.y) > FLT_EPSILON && fabsf (p->y - b2.y) > FLT_EPSILON)
return FALSE;
}
@@ -2216,7 +2216,7 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job,
key.scale_x = scale_x;
key.scale_y = scale_y;
blurred_texture_id = gsk_gl_driver_lookup_texture (job->driver, &key);
blurred_texture_id = gsk_gl_driver_lookup_texture (job->driver, &key, NULL);
if (blurred_texture_id == 0)
{
@@ -2304,8 +2304,8 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job,
&offscreen,
texture_width,
texture_height,
blur_radius * fabs (scale_x),
blur_radius * fabs (scale_y));
blur_radius * fabsf (scale_x),
blur_radius * fabsf (scale_y));
gsk_gl_driver_release_render_target (job->driver, render_target, TRUE);
@@ -2501,8 +2501,8 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job,
do_slicing = TRUE;
}
texture_width = (int)ceil ((scaled_outline.bounds.size.width + blur_extra) * scale_x);
texture_height = (int)ceil ((scaled_outline.bounds.size.height + blur_extra) * scale_y);
texture_width = (int)ceilf ((scaled_outline.bounds.size.width + blur_extra) * scale_x);
texture_height = (int)ceilf ((scaled_outline.bounds.size.height + blur_extra) * scale_y);
scaled_outline.bounds.origin.x = extra_blur_pixels_x;
scaled_outline.bounds.origin.y = extra_blur_pixels_y;
@@ -2577,8 +2577,8 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job,
&offscreen,
texture_width,
texture_height,
blur_radius * fabs (scale_x),
blur_radius * fabs (scale_y));
blur_radius * fabsf (scale_x),
blur_radius * fabsf (scale_y));
gsk_gl_shadow_library_insert (job->driver->shadows_library,
&scaled_outline,
@@ -2834,7 +2834,7 @@ gsk_gl_render_job_visit_cross_fade_node (GskGLRenderJob *job,
offscreen_end.reset_clip = TRUE;
offscreen_end.bounds = &node->bounds;
gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabs (job->scale_x), fabs (job->scale_y)));
gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabsf (job->scale_x), fabsf (job->scale_y)));
if (!gsk_gl_render_job_visit_node_with_offscreen (job, start_node, &offscreen_start))
{
@@ -2964,7 +2964,7 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
const PangoFont *font = gsk_text_node_get_font (node);
const PangoGlyphInfo *glyphs = gsk_text_node_get_glyphs (node, NULL);
const graphene_point_t *offset = gsk_text_node_get_offset (node);
float text_scale = MAX (fabs (job->scale_x), fabs (job->scale_y)); /* TODO: Fix for uneven scales? */
float text_scale = MAX (fabsf (job->scale_x), fabsf (job->scale_y)); /* TODO: Fix for uneven scales? */
guint num_glyphs = gsk_text_node_get_num_glyphs (node);
float x = offset->x + job->offset_x;
float y = offset->y + job->offset_y;
@@ -3216,7 +3216,7 @@ gsk_gl_render_job_visit_blur_node (GskGLRenderJob *job,
key.scale_x = job->scale_x;
key.scale_y = job->scale_y;
offscreen.texture_id = gsk_gl_driver_lookup_texture (job->driver, &key);
offscreen.texture_id = gsk_gl_driver_lookup_texture (job->driver, &key, NULL);
cache_texture = offscreen.texture_id == 0;
blur_node (job,
@@ -3263,7 +3263,7 @@ gsk_gl_render_job_visit_blend_node (GskGLRenderJob *job,
bottom_offscreen.force_offscreen = TRUE;
bottom_offscreen.reset_clip = TRUE;
gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabs (job->scale_x), fabs (job->scale_y)));
gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabsf (job->scale_x), fabsf (job->scale_y)));
/* TODO: We create 2 textures here as big as the blend node, but both the
* start and the end node might be a lot smaller than that. */
@@ -3344,8 +3344,8 @@ gsk_gl_render_job_texture_mask_for_color (GskGLRenderJob *job,
gboolean use_mipmap;
guint16 cc[4];
use_mipmap = (scale_x * fabs (job->scale_x)) < 0.5 ||
(scale_y * fabs (job->scale_y)) < 0.5;
use_mipmap = (scale_x * fabsf (job->scale_x)) < 0.5 ||
(scale_y * fabsf (job->scale_y)) < 0.5;
rgba_to_half (rgba, cc);
gsk_gl_render_job_upload_texture (job, texture, use_mipmap, &offscreen);
@@ -3396,7 +3396,7 @@ gsk_gl_render_job_visit_mask_node (GskGLRenderJob *job,
mask_offscreen.reset_clip = TRUE;
mask_offscreen.do_not_cache = TRUE;
gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabs (job->scale_x), fabs (job->scale_y)));
gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabsf (job->scale_x), fabsf (job->scale_y)));
/* TODO: We create 2 textures here as big as the mask node, but both
* nodes might be a lot smaller than that.
@@ -3664,8 +3664,8 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
float scale_y = bounds->size.height / texture->height;
gboolean use_mipmap;
use_mipmap = (scale_x * fabs (job->scale_x)) < 0.5 ||
(scale_y * fabs (job->scale_y)) < 0.5;
use_mipmap = (scale_x * fabsf (job->scale_x)) < 0.5 ||
(scale_y * fabsf (job->scale_y)) < 0.5;
if G_LIKELY (texture->width <= max_texture_size &&
texture->height <= max_texture_size)
@@ -3771,6 +3771,8 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
float u0, u1, v0, v1;
GskTextureKey key;
guint texture_id;
gboolean need_mipmap;
gboolean has_mipmap;
gsk_gl_render_job_untransform_bounds (job, &job->current_clip->rect.bounds, &clip_rect);
@@ -3783,9 +3785,11 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
key.scale_x = 1.;
key.scale_y = 1.;
texture_id = gsk_gl_driver_lookup_texture (job->driver, &key);
need_mipmap = (filter == GSK_SCALING_FILTER_TRILINEAR);
if (texture_id != 0)
texture_id = gsk_gl_driver_lookup_texture (job->driver, &key, &has_mipmap);
if (texture_id != 0 && (!need_mipmap || has_mipmap))
goto render_texture;
viewport = GRAPHENE_RECT_INIT (0, 0,
@@ -3816,7 +3820,7 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
{
gpointer sync;
texture_id = gsk_gl_driver_load_texture (job->driver, texture, filter == GSK_SCALING_FILTER_TRILINEAR);
texture_id = gsk_gl_driver_load_texture (job->driver, texture, need_mipmap);
if (GDK_IS_GL_TEXTURE (texture) && texture_id == gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture)))
sync = gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture));
@@ -3853,7 +3857,7 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
GskGLTextureSlice *slices = NULL;
guint n_slices = 0;
gsk_gl_driver_slice_texture (job->driver, texture, filter == GSK_SCALING_FILTER_TRILINEAR, &slices, &n_slices);
gsk_gl_driver_slice_texture (job->driver, texture, need_mipmap, &slices, &n_slices);
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)))
{
@@ -4352,7 +4356,7 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
}
/* Check if we've already cached the drawn texture. */
cached_id = gsk_gl_driver_lookup_texture (job->driver, &key);
cached_id = gsk_gl_driver_lookup_texture (job->driver, &key, NULL);
if (cached_id != 0)
{
+2 -4
View File
@@ -117,9 +117,8 @@ gsk_gl_texture_library_real_compact (GskGLTextureLibrary *self,
g_hash_table_iter_remove (&iter);
dropped++;
}
if (periodic_scan)
entry->accessed = FALSE;
else if (periodic_scan)
entry->accessed = FALSE;
}
}
@@ -440,7 +439,6 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
entry->texture = texture;
entry->is_atlased = FALSE;
entry->accessed = TRUE;
entry->area.x = padding / (float) (padding + width + padding);
entry->area.y = padding / (float) (padding + height + padding);
entry->area.x2 = (padding + width) / (float) (padding + width + padding);
+2
View File
@@ -73,6 +73,8 @@ struct _GskGLTexture
/* Set when used by an atlas so we don't drop the texture */
guint permanent : 1;
/* we are allowed to call glGenerateMipmap() for this texture */
guint can_mipmap : 1;
/* we called glGenerateMipmap() for this texture */
guint has_mipmap : 1;
};
+2 -2
View File
@@ -10,8 +10,8 @@ void main() {
vUv = vec2(aUv.x, aUv.y);
// We use this shader for both plain glyphs (used as mask)
// and color glpyhs (used as source). The renderer sets
// aColor to vec4(-1) for color glyhs.
// and color glyphs (used as source). The renderer sets
// aColor to vec4(-1) for color glyphs.
if (distance(aColor,vec4(-1)) < 0.1)
use_color = 0.0;
else
+97
View File
@@ -0,0 +1,97 @@
#include "config.h"
#include "gskglbufferprivate.h"
struct _GskGLBuffer
{
GskGpuBuffer parent_instance;
GLenum target;
GLuint buffer_id;
GLenum access;
guchar *data;
};
G_DEFINE_TYPE (GskGLBuffer, gsk_gl_buffer, GSK_TYPE_GPU_BUFFER)
static void
gsk_gl_buffer_finalize (GObject *object)
{
GskGLBuffer *self = GSK_GL_BUFFER (object);
g_free (self->data);
glDeleteBuffers (1, &self->buffer_id);
G_OBJECT_CLASS (gsk_gl_buffer_parent_class)->finalize (object);
}
static guchar *
gsk_gl_buffer_map (GskGpuBuffer *buffer)
{
GskGLBuffer *self = GSK_GL_BUFFER (buffer);
return self->data;
}
static void
gsk_gl_buffer_unmap (GskGpuBuffer *buffer)
{
GskGLBuffer *self = GSK_GL_BUFFER (buffer);
gsk_gl_buffer_bind (self);
glBufferSubData (self->target, 0, gsk_gpu_buffer_get_size (buffer), self->data);
}
static void
gsk_gl_buffer_class_init (GskGLBufferClass *klass)
{
GskGpuBufferClass *buffer_class = GSK_GPU_BUFFER_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
buffer_class->map = gsk_gl_buffer_map;
buffer_class->unmap = gsk_gl_buffer_unmap;
gobject_class->finalize = gsk_gl_buffer_finalize;
}
static void
gsk_gl_buffer_init (GskGLBuffer *self)
{
}
GskGpuBuffer *
gsk_gl_buffer_new (GLenum target,
gsize size,
GLenum access)
{
GskGLBuffer *self;
self = g_object_new (GSK_TYPE_GL_BUFFER, NULL);
gsk_gpu_buffer_setup (GSK_GPU_BUFFER (self), size);
self->target = target;
self->access = access;
glGenBuffers (1, &self->buffer_id);
glBindBuffer (target, self->buffer_id);
glBufferData (target, size, NULL, GL_STATIC_DRAW);
self->data = malloc (size);
return GSK_GPU_BUFFER (self);
}
void
gsk_gl_buffer_bind (GskGLBuffer *self)
{
glBindBuffer (self->target, self->buffer_id);
}
void
gsk_gl_buffer_bind_base (GskGLBuffer *self,
GLuint index)
{
glBindBufferBase (self->target, index, self->buffer_id);
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include "gskgpubufferprivate.h"
#include "gskgldeviceprivate.h"
G_BEGIN_DECLS
#define GSK_TYPE_GL_BUFFER (gsk_gl_buffer_get_type ())
G_DECLARE_FINAL_TYPE (GskGLBuffer, gsk_gl_buffer, GSK, GL_BUFFER, GskGpuBuffer)
GskGpuBuffer * gsk_gl_buffer_new (GLenum target,
gsize size,
GLenum access);
void gsk_gl_buffer_bind (GskGLBuffer *self);
void gsk_gl_buffer_bind_base (GskGLBuffer *self,
GLuint index);
G_END_DECLS
+144
View File
@@ -0,0 +1,144 @@
#include "config.h"
#include "gskgldescriptorsprivate.h"
#include "gskglbufferprivate.h"
#include "gskglimageprivate.h"
struct _GskGLDescriptors
{
GskGpuDescriptors parent_instance;
GskGLDevice *device;
guint n_external;
};
G_DEFINE_TYPE (GskGLDescriptors, gsk_gl_descriptors, GSK_TYPE_GPU_DESCRIPTORS)
static void
gsk_gl_descriptors_finalize (GObject *object)
{
GskGLDescriptors *self = GSK_GL_DESCRIPTORS (object);
g_object_unref (self->device);
G_OBJECT_CLASS (gsk_gl_descriptors_parent_class)->finalize (object);
}
static gboolean
gsk_gl_descriptors_add_image (GskGpuDescriptors *desc,
GskGpuImage *image,
GskGpuSampler sampler,
guint32 *out_descriptor)
{
GskGLDescriptors *self = GSK_GL_DESCRIPTORS (desc);
gsize used_texture_units;
used_texture_units = gsk_gpu_descriptors_get_n_images (desc) + 2 * self->n_external;
if (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_EXTERNAL)
{
if (16 - used_texture_units < 3)
return FALSE;
*out_descriptor = (self->n_external << 1) | 1;
self->n_external++;
return TRUE;
}
else
{
if (used_texture_units >= 16)
return FALSE;
*out_descriptor = (gsk_gpu_descriptors_get_n_images (desc) - self->n_external) << 1;
return TRUE;
}
}
static gboolean
gsk_gl_descriptors_add_buffer (GskGpuDescriptors *desc,
GskGpuBuffer *buffer,
guint32 *out_descriptor)
{
gsize used_buffers;
used_buffers = gsk_gpu_descriptors_get_n_buffers (desc);
if (used_buffers >= 11)
return FALSE;
*out_descriptor = used_buffers;
return TRUE;
}
static void
gsk_gl_descriptors_class_init (GskGLDescriptorsClass *klass)
{
GskGpuDescriptorsClass *descriptors_class = GSK_GPU_DESCRIPTORS_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gsk_gl_descriptors_finalize;
descriptors_class->add_image = gsk_gl_descriptors_add_image;
descriptors_class->add_buffer = gsk_gl_descriptors_add_buffer;
}
static void
gsk_gl_descriptors_init (GskGLDescriptors *self)
{
}
GskGpuDescriptors *
gsk_gl_descriptors_new (GskGLDevice *device)
{
GskGLDescriptors *self;
self = g_object_new (GSK_TYPE_GL_DESCRIPTORS, NULL);
self->device = g_object_ref (device);
return GSK_GPU_DESCRIPTORS (self);
}
guint
gsk_gl_descriptors_get_n_external (GskGLDescriptors *self)
{
return self->n_external;
}
void
gsk_gl_descriptors_use (GskGLDescriptors *self)
{
GskGpuDescriptors *desc = GSK_GPU_DESCRIPTORS (self);
gsize i, ext, n_textures;
n_textures = 16 - 3 * self->n_external;
ext = 0;
for (i = 0; i < gsk_gpu_descriptors_get_n_images (desc); i++)
{
GskGLImage *image = GSK_GL_IMAGE (gsk_gpu_descriptors_get_image (desc, i));
if (gsk_gpu_image_get_flags (GSK_GPU_IMAGE (image)) & GSK_GPU_IMAGE_EXTERNAL)
{
glActiveTexture (GL_TEXTURE0 + n_textures + 3 * ext);
gsk_gl_image_bind_texture (image);
ext++;
}
else
{
glActiveTexture (GL_TEXTURE0 + i - ext);
gsk_gl_image_bind_texture (image);
glBindSampler (i - ext, gsk_gl_device_get_sampler_id (self->device, gsk_gpu_descriptors_get_sampler (desc, i)));
}
}
for (i = 0; i < gsk_gpu_descriptors_get_n_buffers (desc); i++)
{
GskGLBuffer *buffer = GSK_GL_BUFFER (gsk_gpu_descriptors_get_buffer (desc, i));
/* index 0 are the globals, we start at 1 */
gsk_gl_buffer_bind_base (buffer, i + 1);
}
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "gskgpudescriptorsprivate.h"
#include "gskgldeviceprivate.h"
G_BEGIN_DECLS
#define GSK_TYPE_GL_DESCRIPTORS (gsk_gl_descriptors_get_type ())
G_DECLARE_FINAL_TYPE (GskGLDescriptors, gsk_gl_descriptors, GSK, GL_DESCRIPTORS, GskGpuDescriptors)
GskGpuDescriptors * gsk_gl_descriptors_new (GskGLDevice *device);
guint gsk_gl_descriptors_get_n_external (GskGLDescriptors *self);
void gsk_gl_descriptors_use (GskGLDescriptors *self);
G_END_DECLS
+687
View File
@@ -0,0 +1,687 @@
#include "config.h"
#include "gskgldeviceprivate.h"
#include "gskdebugprivate.h"
#include "gskgpushaderopprivate.h"
#include "gskglbufferprivate.h"
#include "gskglimageprivate.h"
#include "gdk/gdkdisplayprivate.h"
#include "gdk/gdkglcontextprivate.h"
#include <glib/gi18n-lib.h>
struct _GskGLDevice
{
GskGpuDevice parent_instance;
GHashTable *gl_programs;
const char *version_string;
GdkGLAPI api;
guint sampler_ids[GSK_GPU_SAMPLER_N_SAMPLERS];
};
struct _GskGLDeviceClass
{
GskGpuDeviceClass parent_class;
};
typedef struct _GLProgramKey GLProgramKey;
struct _GLProgramKey
{
const GskGpuShaderOpClass *op_class;
guint32 variation;
GskGpuShaderClip clip;
guint n_external_textures;
};
G_DEFINE_TYPE (GskGLDevice, gsk_gl_device, GSK_TYPE_GPU_DEVICE)
static guint
gl_program_key_hash (gconstpointer data)
{
const GLProgramKey *key = data;
return GPOINTER_TO_UINT (key->op_class) ^
key->clip ^
(key->variation << 2) ^
(key->n_external_textures << 24);
}
static gboolean
gl_program_key_equal (gconstpointer a,
gconstpointer b)
{
const GLProgramKey *keya = a;
const GLProgramKey *keyb = b;
return keya->op_class == keyb->op_class &&
keya->variation == keyb->variation &&
keya->clip == keyb->clip &&
keya->n_external_textures == keyb->n_external_textures;
}
static GskGpuImage *
gsk_gl_device_create_offscreen_image (GskGpuDevice *device,
gboolean with_mipmap,
GdkMemoryDepth depth,
gsize width,
gsize height)
{
GskGLDevice *self = GSK_GL_DEVICE (device);
return gsk_gl_image_new (self,
gdk_memory_depth_get_format (depth),
GSK_GPU_IMAGE_RENDERABLE | GSK_GPU_IMAGE_FILTERABLE,
width,
height);
}
static GskGpuImage *
gsk_gl_device_create_upload_image (GskGpuDevice *device,
gboolean with_mipmap,
GdkMemoryFormat format,
gsize width,
gsize height)
{
GskGLDevice *self = GSK_GL_DEVICE (device);
return gsk_gl_image_new (self,
format,
0,
width,
height);
}
static GskGpuImage *
gsk_gl_device_create_download_image (GskGpuDevice *device,
GdkMemoryDepth depth,
gsize width,
gsize height)
{
GskGLDevice *self = GSK_GL_DEVICE (device);
return gsk_gl_image_new (self,
gdk_memory_depth_get_format (depth),
GSK_GPU_IMAGE_RENDERABLE,
width,
height);
}
static GskGpuImage *
gsk_gl_device_create_atlas_image (GskGpuDevice *device,
gsize width,
gsize height)
{
GskGLDevice *self = GSK_GL_DEVICE (device);
return gsk_gl_image_new (self,
GDK_MEMORY_DEFAULT,
GSK_GPU_IMAGE_RENDERABLE,
width,
height);
}
static void
gsk_gl_device_finalize (GObject *object)
{
GskGLDevice *self = GSK_GL_DEVICE (object);
GskGpuDevice *device = GSK_GPU_DEVICE (self);
g_object_steal_data (G_OBJECT (gsk_gpu_device_get_display (device)), "-gsk-gl-device");
gdk_gl_context_make_current (gdk_display_get_gl_context (gsk_gpu_device_get_display (device)));
g_hash_table_unref (self->gl_programs);
glDeleteSamplers (G_N_ELEMENTS (self->sampler_ids), self->sampler_ids);
G_OBJECT_CLASS (gsk_gl_device_parent_class)->finalize (object);
}
static void
gsk_gl_device_class_init (GskGLDeviceClass *klass)
{
GskGpuDeviceClass *gpu_device_class = GSK_GPU_DEVICE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
gpu_device_class->create_offscreen_image = gsk_gl_device_create_offscreen_image;
gpu_device_class->create_atlas_image = gsk_gl_device_create_atlas_image;
gpu_device_class->create_upload_image = gsk_gl_device_create_upload_image;
gpu_device_class->create_download_image = gsk_gl_device_create_download_image;
object_class->finalize = gsk_gl_device_finalize;
}
static void
free_gl_program (gpointer program)
{
glDeleteProgram (GPOINTER_TO_UINT (program));
}
static void
gsk_gl_device_init (GskGLDevice *self)
{
self->gl_programs = g_hash_table_new_full (gl_program_key_hash, gl_program_key_equal, g_free, free_gl_program);
}
static void
gsk_gl_device_setup_samplers (GskGLDevice *self)
{
struct {
GLuint min_filter;
GLuint mag_filter;
GLuint wrap;
} sampler_flags[GSK_GPU_SAMPLER_N_SAMPLERS] = {
[GSK_GPU_SAMPLER_DEFAULT] = {
.min_filter = GL_LINEAR,
.mag_filter = GL_LINEAR,
.wrap = GL_CLAMP_TO_EDGE,
},
[GSK_GPU_SAMPLER_TRANSPARENT] = {
.min_filter = GL_LINEAR,
.mag_filter = GL_LINEAR,
.wrap = GL_CLAMP_TO_BORDER,
},
[GSK_GPU_SAMPLER_REPEAT] = {
.min_filter = GL_LINEAR,
.mag_filter = GL_LINEAR,
.wrap = GL_REPEAT,
},
[GSK_GPU_SAMPLER_NEAREST] = {
.min_filter = GL_NEAREST,
.mag_filter = GL_NEAREST,
.wrap = GL_CLAMP_TO_EDGE,
},
[GSK_GPU_SAMPLER_MIPMAP_DEFAULT] = {
.min_filter = GL_LINEAR_MIPMAP_LINEAR,
.mag_filter = GL_LINEAR,
.wrap = GL_CLAMP_TO_EDGE,
}
};
guint i;
glGenSamplers (G_N_ELEMENTS (self->sampler_ids), self->sampler_ids);
for (i = 0; i < G_N_ELEMENTS (self->sampler_ids); i++)
{
glSamplerParameteri (self->sampler_ids[i], GL_TEXTURE_MIN_FILTER, sampler_flags[i].min_filter);
glSamplerParameteri (self->sampler_ids[i], GL_TEXTURE_MAG_FILTER, sampler_flags[i].mag_filter);
glSamplerParameteri (self->sampler_ids[i], GL_TEXTURE_WRAP_S, sampler_flags[i].wrap);
glSamplerParameteri (self->sampler_ids[i], GL_TEXTURE_WRAP_T, sampler_flags[i].wrap);
}
}
GskGpuDevice *
gsk_gl_device_get_for_display (GdkDisplay *display,
GError **error)
{
GskGLDevice *self;
GdkGLContext *context;
GLint max_texture_size;
self = g_object_get_data (G_OBJECT (display), "-gsk-gl-device");
if (self)
return GSK_GPU_DEVICE (g_object_ref (self));
if (!gdk_display_prepare_gl (display, error))
return NULL;
context = gdk_display_get_gl_context (display);
/* GLES 2 is not supported */
if (!gdk_gl_context_check_version (context, "3.0", "3.0"))
{
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
_("OpenGL ES 2.0 is not supported by this renderer."));
return NULL;
}
self = g_object_new (GSK_TYPE_GL_DEVICE, NULL);
gdk_gl_context_make_current (context);
glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_texture_size);
gsk_gpu_device_setup (GSK_GPU_DEVICE (self), display, max_texture_size);
self->version_string = gdk_gl_context_get_glsl_version_string (context);
self->api = gdk_gl_context_get_api (context);
gsk_gl_device_setup_samplers (self);
g_object_set_data (G_OBJECT (display), "-gsk-gl-device", self);
return GSK_GPU_DEVICE (self);
}
static char *
prepend_line_numbers (char *code)
{
GString *s;
char *p;
int line;
s = g_string_new ("");
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;
}
g_free (code);
return g_string_free (s, FALSE);
}
static gboolean
gsk_gl_device_check_shader_error (int shader_id,
GError **error)
{
GLint status;
GLint log_len;
GLint code_len;
char *log;
char *code;
glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
if G_LIKELY (status == GL_TRUE)
return TRUE;
glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len);
log = g_malloc0 (log_len + 1);
glGetShaderInfoLog (shader_id, log_len, NULL, log);
glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
code = g_malloc0 (code_len + 1);
glGetShaderSource (shader_id, code_len, NULL, code);
code = prepend_line_numbers (code);
g_set_error (error,
GDK_GL_ERROR,
GDK_GL_ERROR_COMPILATION_FAILED,
"Compilation failure in shader.\n"
"Source Code:\n"
"%s\n"
"\n"
"Error Message:\n"
"%s\n"
"\n",
code,
log);
g_free (code);
g_free (log);
return FALSE;
}
static void
print_shader_info (const char *prefix,
GLuint shader_id,
const char *name)
{
if (GSK_DEBUG_CHECK (SHADERS))
{
int code_len;
glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len);
if (code_len > 0)
{
char *code;
code = g_malloc0 (code_len + 1);
glGetShaderSource (shader_id, code_len, NULL, code);
code = prepend_line_numbers (code);
g_message ("%s %d, %s:\n%s",
prefix, shader_id,
name ? name : "unnamed",
code);
g_free (code);
}
}
}
static GLuint
gsk_gl_device_load_shader (GskGLDevice *self,
const char *program_name,
GLenum shader_type,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures,
GError **error)
{
GString *preamble;
char *resource_name;
GBytes *bytes;
GLuint shader_id;
preamble = g_string_new (NULL);
g_string_append (preamble, self->version_string);
g_string_append (preamble, "\n");
if (self->api == GDK_GL_API_GLES)
{
if (n_external_textures > 0)
{
g_string_append (preamble, "#extension GL_OES_EGL_image_external_essl3 : require\n");
g_string_append (preamble, "#extension GL_OES_EGL_image_external : require\n");
}
g_string_append (preamble, "#define GSK_GLES 1\n");
g_assert (3 * n_external_textures <= 16);
}
else
{
g_assert (n_external_textures == 0);
}
g_string_append_printf (preamble, "#define N_TEXTURES %u\n", 16 - 3 * n_external_textures);
g_string_append_printf (preamble, "#define N_EXTERNAL_TEXTURES %u\n", n_external_textures);
switch (shader_type)
{
case GL_VERTEX_SHADER:
g_string_append (preamble, "#define GSK_VERTEX_SHADER 1\n");
break;
case GL_FRAGMENT_SHADER:
g_string_append (preamble, "#define GSK_FRAGMENT_SHADER 1\n");
break;
default:
g_assert_not_reached ();
return 0;
}
g_string_append_printf (preamble, "#define GSK_VARIATION %uu\n", variation);
switch (clip)
{
case GSK_GPU_SHADER_CLIP_NONE:
g_string_append (preamble, "#define GSK_SHADER_CLIP GSK_GPU_SHADER_CLIP_NONE\n");
break;
case GSK_GPU_SHADER_CLIP_RECT:
g_string_append (preamble, "#define GSK_SHADER_CLIP GSK_GPU_SHADER_CLIP_RECT\n");
break;
case GSK_GPU_SHADER_CLIP_ROUNDED:
g_string_append (preamble, "#define GSK_SHADER_CLIP GSK_GPU_SHADER_CLIP_ROUNDED\n");
break;
default:
g_assert_not_reached ();
break;
}
resource_name = g_strconcat ("/org/gtk/libgsk/shaders/gl/", program_name, ".glsl", NULL);
bytes = g_resources_lookup_data (resource_name, 0, error);
g_free (resource_name);
if (bytes == NULL)
return 0;
shader_id = glCreateShader (shader_type);
glShaderSource (shader_id,
2,
(const char *[]) {
preamble->str,
g_bytes_get_data (bytes, NULL),
},
NULL);
g_bytes_unref (bytes);
g_string_free (preamble, TRUE);
glCompileShader (shader_id);
print_shader_info (shader_type == GL_FRAGMENT_SHADER ? "fragment" : "vertex", shader_id, program_name);
if (!gsk_gl_device_check_shader_error (shader_id, error))
{
glDeleteShader (shader_id);
return 0;
}
return shader_id;
}
static GLuint
gsk_gl_device_load_program (GskGLDevice *self,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures,
GError **error)
{
GLuint vertex_shader_id, fragment_shader_id, program_id;
GLint link_status;
vertex_shader_id = gsk_gl_device_load_shader (self, op_class->shader_name, GL_VERTEX_SHADER, variation, clip, n_external_textures, error);
if (vertex_shader_id == 0)
return 0;
fragment_shader_id = gsk_gl_device_load_shader (self, op_class->shader_name, GL_FRAGMENT_SHADER, variation, clip, n_external_textures, error);
if (fragment_shader_id == 0)
return 0;
program_id = glCreateProgram ();
glAttachShader (program_id, vertex_shader_id);
glAttachShader (program_id, fragment_shader_id);
op_class->setup_attrib_locations (program_id);
glLinkProgram (program_id);
glGetProgramiv (program_id, GL_LINK_STATUS, &link_status);
glDetachShader (program_id, vertex_shader_id);
glDeleteShader (vertex_shader_id);
glDetachShader (program_id, fragment_shader_id);
glDeleteShader (fragment_shader_id);
if (link_status == GL_FALSE)
{
char *buffer = NULL;
int log_len = 0;
glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len);
if (log_len > 0)
{
/* log_len includes NULL */
buffer = g_malloc0 (log_len);
glGetProgramInfoLog (program_id, log_len, NULL, buffer);
}
g_set_error (error,
GDK_GL_ERROR,
GDK_GL_ERROR_LINK_FAILED,
"Linking failure in shader: %s",
buffer ? buffer : "");
g_free (buffer);
glDeleteProgram (program_id);
return 0;
}
return program_id;
}
void
gsk_gl_device_use_program (GskGLDevice *self,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures)
{
GError *error = NULL;
GLuint program_id;
GLProgramKey key = {
.op_class = op_class,
.variation = variation,
.clip = clip,
.n_external_textures = n_external_textures
};
guint i, n_textures;
program_id = GPOINTER_TO_UINT (g_hash_table_lookup (self->gl_programs, &key));
if (program_id)
{
glUseProgram (program_id);
return;
}
program_id = gsk_gl_device_load_program (self, op_class, variation, clip, n_external_textures, &error);
if (program_id == 0)
{
g_critical ("Failed to load shader program: %s", error->message);
g_clear_error (&error);
return;
}
g_hash_table_insert (self->gl_programs, g_memdup (&key, sizeof (GLProgramKey)), GUINT_TO_POINTER (program_id));
glUseProgram (program_id);
n_textures = 16 - 3 * n_external_textures;
for (i = 0; i < n_external_textures; i++)
{
char *name = g_strdup_printf ("external_textures[%u]", i);
glUniform1i (glGetUniformLocation (program_id, name), n_textures + 3 * i);
g_free (name);
}
for (i = 0; i < n_textures; i++)
{
char *name = g_strdup_printf ("textures[%u]", i);
glUniform1i (glGetUniformLocation (program_id, name), i);
g_free (name);
}
}
GLuint
gsk_gl_device_get_sampler_id (GskGLDevice *self,
GskGpuSampler sampler)
{
g_return_val_if_fail (sampler < G_N_ELEMENTS (self->sampler_ids), 0);
return self->sampler_ids[sampler];
}
static gboolean
gsk_gl_device_get_format_flags (GskGLDevice *self,
GdkGLContext *context,
GdkMemoryFormat format,
GskGpuImageFlags *out_flags)
{
GdkGLMemoryFlags gl_flags;
*out_flags = 0;
gl_flags = gdk_gl_context_get_format_flags (context, format);
if (!(gl_flags & GDK_GL_FORMAT_USABLE))
return FALSE;
if (gl_flags & GDK_GL_FORMAT_RENDERABLE)
*out_flags |= GSK_GPU_IMAGE_RENDERABLE;
else if (gdk_gl_context_get_use_es (context))
*out_flags |= GSK_GPU_IMAGE_NO_BLIT;
if (gl_flags & GDK_GL_FORMAT_FILTERABLE)
*out_flags |= GSK_GPU_IMAGE_FILTERABLE;
if ((gl_flags & (GDK_GL_FORMAT_RENDERABLE | GDK_GL_FORMAT_FILTERABLE)) == (GDK_GL_FORMAT_RENDERABLE | GDK_GL_FORMAT_FILTERABLE))
*out_flags |= GSK_GPU_IMAGE_CAN_MIPMAP;
if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT)
*out_flags |= GSK_GPU_IMAGE_STRAIGHT_ALPHA;
return TRUE;
}
void
gsk_gl_device_find_gl_format (GskGLDevice *self,
GdkMemoryFormat format,
GskGpuImageFlags required_flags,
GdkMemoryFormat *out_format,
GskGpuImageFlags *out_flags,
GLint *out_gl_internal_format,
GLenum *out_gl_format,
GLenum *out_gl_type,
GLint out_swizzle[4])
{
GdkGLContext *context = gdk_gl_context_get_current ();
GskGpuImageFlags flags;
GdkMemoryFormat alt_format;
const GdkMemoryFormat *fallbacks;
gsize i;
/* First, try the actual format */
if (gsk_gl_device_get_format_flags (self, context, format, &flags) &&
((flags & required_flags) == required_flags))
{
*out_format = format;
*out_flags = flags;
gdk_memory_format_gl_format (format,
gdk_gl_context_get_use_es (context),
out_gl_internal_format,
out_gl_format,
out_gl_type,
out_swizzle);
return;
}
/* Second, try the potential RGBA format */
if (gdk_memory_format_gl_rgba_format (format,
gdk_gl_context_get_use_es (context),
&alt_format,
out_gl_internal_format,
out_gl_format,
out_gl_type,
out_swizzle) &&
gsk_gl_device_get_format_flags (self, context, alt_format, &flags) &&
((flags & required_flags) == required_flags))
{
*out_format = format;
*out_flags = flags;
return;
}
/* Next, try the fallbacks */
fallbacks = gdk_memory_format_get_fallbacks (format);
for (i = 0; fallbacks[i] != -1; i++)
{
if (gsk_gl_device_get_format_flags (self, context, fallbacks[i], &flags) &&
((flags & required_flags) == required_flags))
{
*out_format = fallbacks[i];
*out_flags = flags;
gdk_memory_format_gl_format (fallbacks[i],
gdk_gl_context_get_use_es (context),
out_gl_internal_format,
out_gl_format,
out_gl_type,
out_swizzle);
return;
}
}
/* fallbacks will always fallback to a supported format */
g_assert_not_reached ();
}
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include "gskgpudeviceprivate.h"
G_BEGIN_DECLS
#define GSK_TYPE_GL_DEVICE (gsk_gl_device_get_type ())
G_DECLARE_FINAL_TYPE (GskGLDevice, gsk_gl_device, GSK, GL_DEVICE, GskGpuDevice)
GskGpuDevice * gsk_gl_device_get_for_display (GdkDisplay *display,
GError **error);
void gsk_gl_device_use_program (GskGLDevice *self,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures);
GLuint gsk_gl_device_get_sampler_id (GskGLDevice *self,
GskGpuSampler sampler);
void gsk_gl_device_find_gl_format (GskGLDevice *self,
GdkMemoryFormat format,
GskGpuImageFlags required_flags,
GdkMemoryFormat *out_format,
GskGpuImageFlags *out_flags,
GLint *out_gl_internal_format,
GLenum *out_gl_format,
GLenum *out_gl_type,
GLint out_swizzle[4]);
G_END_DECLS
+240
View File
@@ -0,0 +1,240 @@
#include "config.h"
#include "gskglframeprivate.h"
#include "gskgpuglobalsopprivate.h"
#include "gskgpuopprivate.h"
#include "gskgpushaderopprivate.h"
#include "gskglbufferprivate.h"
#include "gskgldescriptorsprivate.h"
#include "gskgldeviceprivate.h"
#include "gskglimageprivate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkglcontextprivate.h"
#include "gdkgltextureprivate.h"
struct _GskGLFrame
{
GskGpuFrame parent_instance;
GLuint globals_buffer_id;
guint next_texture_slot;
GHashTable *vaos;
};
struct _GskGLFrameClass
{
GskGpuFrameClass parent_class;
};
G_DEFINE_TYPE (GskGLFrame, gsk_gl_frame, GSK_TYPE_GPU_FRAME)
static gboolean
gsk_gl_frame_is_busy (GskGpuFrame *frame)
{
return FALSE;
}
static void
gsk_gl_frame_setup (GskGpuFrame *frame)
{
GskGLFrame *self = GSK_GL_FRAME (frame);
glGenBuffers (1, &self->globals_buffer_id);
}
static void
gsk_gl_frame_cleanup (GskGpuFrame *frame)
{
GskGLFrame *self = GSK_GL_FRAME (frame);
self->next_texture_slot = 0;
GSK_GPU_FRAME_CLASS (gsk_gl_frame_parent_class)->cleanup (frame);
}
static GskGpuImage *
gsk_gl_frame_upload_texture (GskGpuFrame *frame,
gboolean with_mipmap,
GdkTexture *texture)
{
if (GDK_IS_GL_TEXTURE (texture))
{
GdkGLTexture *gl_texture = GDK_GL_TEXTURE (texture);
if (gdk_gl_context_is_shared (GDK_GL_CONTEXT (gsk_gpu_frame_get_context (frame)),
gdk_gl_texture_get_context (gl_texture)))
{
GskGpuImage *image;
GLsync sync;
image = gsk_gl_image_new_for_texture (GSK_GL_DEVICE (gsk_gpu_frame_get_device (frame)),
texture,
gdk_gl_texture_get_id (gl_texture),
FALSE,
gdk_gl_texture_has_mipmap (gl_texture) ? (GSK_GPU_IMAGE_CAN_MIPMAP | GSK_GPU_IMAGE_MIPMAP) : 0);
/* This is a hack, but it works */
sync = gdk_gl_texture_get_sync (gl_texture);
if (sync)
glWaitSync (sync, 0, GL_TIMEOUT_IGNORED);
return image;
}
}
else if (GDK_IS_DMABUF_TEXTURE (texture))
{
gboolean external;
GLuint tex_id;
tex_id = gdk_gl_context_import_dmabuf (GDK_GL_CONTEXT (gsk_gpu_frame_get_context (frame)),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture)),
&external);
if (tex_id)
{
return gsk_gl_image_new_for_texture (GSK_GL_DEVICE (gsk_gpu_frame_get_device (frame)),
texture,
tex_id,
TRUE,
(external ? GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT : 0));
}
}
return GSK_GPU_FRAME_CLASS (gsk_gl_frame_parent_class)->upload_texture (frame, with_mipmap, texture);
}
static GskGpuDescriptors *
gsk_gl_frame_create_descriptors (GskGpuFrame *frame)
{
return GSK_GPU_DESCRIPTORS (gsk_gl_descriptors_new (GSK_GL_DEVICE (gsk_gpu_frame_get_device (frame))));
}
static GskGpuBuffer *
gsk_gl_frame_create_vertex_buffer (GskGpuFrame *frame,
gsize size)
{
GskGLFrame *self = GSK_GL_FRAME (frame);
/* We could also reassign them all to the new buffer here?
* Is that faster?
*/
g_hash_table_remove_all (self->vaos);
return gsk_gl_buffer_new (GL_ARRAY_BUFFER, size, GL_WRITE_ONLY);
}
static GskGpuBuffer *
gsk_gl_frame_create_storage_buffer (GskGpuFrame *frame,
gsize size)
{
return gsk_gl_buffer_new (GL_UNIFORM_BUFFER, size, GL_WRITE_ONLY);
}
static void
gsk_gl_frame_submit (GskGpuFrame *frame,
GskGpuBuffer *vertex_buffer,
GskGpuOp *op)
{
GskGLFrame *self = GSK_GL_FRAME (frame);
GskGLCommandState state = { 0, };
glEnable (GL_SCISSOR_TEST);
glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LEQUAL);
glEnable (GL_BLEND);
if (vertex_buffer)
gsk_gl_buffer_bind (GSK_GL_BUFFER (vertex_buffer));
gsk_gl_frame_bind_globals (self);
glBufferData (GL_UNIFORM_BUFFER,
sizeof (GskGpuGlobalsInstance),
NULL,
GL_STREAM_DRAW);
while (op)
{
op = gsk_gpu_op_gl_command (op, frame, &state);
}
}
static void
gsk_gl_frame_finalize (GObject *object)
{
GskGLFrame *self = GSK_GL_FRAME (object);
g_hash_table_unref (self->vaos);
glDeleteBuffers (1, &self->globals_buffer_id);
G_OBJECT_CLASS (gsk_gl_frame_parent_class)->finalize (object);
}
static void
gsk_gl_frame_class_init (GskGLFrameClass *klass)
{
GskGpuFrameClass *gpu_frame_class = GSK_GPU_FRAME_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
gpu_frame_class->is_busy = gsk_gl_frame_is_busy;
gpu_frame_class->setup = gsk_gl_frame_setup;
gpu_frame_class->cleanup = gsk_gl_frame_cleanup;
gpu_frame_class->upload_texture = gsk_gl_frame_upload_texture;
gpu_frame_class->create_descriptors = gsk_gl_frame_create_descriptors;
gpu_frame_class->create_vertex_buffer = gsk_gl_frame_create_vertex_buffer;
gpu_frame_class->create_storage_buffer = gsk_gl_frame_create_storage_buffer;
gpu_frame_class->submit = gsk_gl_frame_submit;
object_class->finalize = gsk_gl_frame_finalize;
}
static void
free_vao (gpointer vao)
{
glDeleteVertexArrays (1, (GLuint[1]) { GPOINTER_TO_UINT (vao) });
}
static void
gsk_gl_frame_init (GskGLFrame *self)
{
self->vaos = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, free_vao);
}
void
gsk_gl_frame_use_program (GskGLFrame *self,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures)
{
GLuint vao;
gsk_gl_device_use_program (GSK_GL_DEVICE (gsk_gpu_frame_get_device (GSK_GPU_FRAME (self))),
op_class,
variation,
clip,
n_external_textures);
vao = GPOINTER_TO_UINT (g_hash_table_lookup (self->vaos, op_class));
if (vao)
{
glBindVertexArray (vao);
return;
}
glGenVertexArrays (1, &vao);
glBindVertexArray (vao);
op_class->setup_vao (0);
g_hash_table_insert (self->vaos, (gpointer) op_class, GUINT_TO_POINTER (vao));
}
void
gsk_gl_frame_bind_globals (GskGLFrame *self)
{
glBindBufferBase (GL_UNIFORM_BUFFER, 0, self->globals_buffer_id);
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "gskgpuframeprivate.h"
G_BEGIN_DECLS
#define GSK_TYPE_GL_FRAME (gsk_gl_frame_get_type ())
G_DECLARE_FINAL_TYPE (GskGLFrame, gsk_gl_frame, GSK, GL_FRAME, GskGpuFrame)
void gsk_gl_frame_use_program (GskGLFrame *self,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures);
void gsk_gl_frame_bind_globals (GskGLFrame *self);
G_END_DECLS
+308
View File
@@ -0,0 +1,308 @@
#include "config.h"
#include "gskglimageprivate.h"
#include "gdk/gdkdisplayprivate.h"
#include "gdk/gdkglcontextprivate.h"
struct _GskGLImage
{
GskGpuImage parent_instance;
guint texture_id;
guint framebuffer_id;
GLint gl_internal_format;
GLenum gl_format;
GLenum gl_type;
guint owns_texture : 1;
};
struct _GskGLImageClass
{
GskGpuImageClass parent_class;
};
G_DEFINE_TYPE (GskGLImage, gsk_gl_image, GSK_TYPE_GPU_IMAGE)
static void
gsk_gl_image_get_projection_matrix (GskGpuImage *image,
graphene_matrix_t *out_projection)
{
GskGLImage *self = GSK_GL_IMAGE (image);
GSK_GPU_IMAGE_CLASS (gsk_gl_image_parent_class)->get_projection_matrix (image, out_projection);
if (self->texture_id == 0)
graphene_matrix_scale (out_projection, 1.f, -1.f, 1.f);
}
static void
gsk_gl_image_finalize (GObject *object)
{
GskGLImage *self = GSK_GL_IMAGE (object);
if (self->framebuffer_id)
glDeleteFramebuffers (1, &self->framebuffer_id);
if (self->owns_texture)
glDeleteTextures (1, &self->texture_id);
G_OBJECT_CLASS (gsk_gl_image_parent_class)->finalize (object);
}
static void
gsk_gl_image_class_init (GskGLImageClass *klass)
{
GskGpuImageClass *image_class = GSK_GPU_IMAGE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
image_class->get_projection_matrix = gsk_gl_image_get_projection_matrix;
object_class->finalize = gsk_gl_image_finalize;
}
static void
gsk_gl_image_init (GskGLImage *self)
{
}
GskGpuImage *
gsk_gl_image_new_backbuffer (GskGLDevice *device,
GdkMemoryFormat format,
gsize width,
gsize height)
{
GskGLImage *self;
GskGpuImageFlags flags;
GLint swizzle[4];
self = g_object_new (GSK_TYPE_GL_IMAGE, NULL);
/* We only do this so these variables get initialized */
gsk_gl_device_find_gl_format (device,
format,
0,
&format,
&flags,
&self->gl_internal_format,
&self->gl_format,
&self->gl_type,
swizzle);
gsk_gpu_image_setup (GSK_GPU_IMAGE (self), flags, format, width, height);
/* texture_id == 0 means backbuffer */
return GSK_GPU_IMAGE (self);
}
GskGpuImage *
gsk_gl_image_new (GskGLDevice *device,
GdkMemoryFormat format,
GskGpuImageFlags required_flags,
gsize width,
gsize height)
{
GskGLImage *self;
GLint swizzle[4];
GskGpuImageFlags flags;
gsize max_size;
max_size = gsk_gpu_device_get_max_image_size (GSK_GPU_DEVICE (device));
if (width > max_size || height > max_size)
return NULL;
self = g_object_new (GSK_TYPE_GL_IMAGE, NULL);
gsk_gl_device_find_gl_format (device,
format,
required_flags,
&format,
&flags,
&self->gl_internal_format,
&self->gl_format,
&self->gl_type,
swizzle);
gsk_gpu_image_setup (GSK_GPU_IMAGE (self),
flags,
format,
width, height);
glGenTextures (1, &self->texture_id);
self->owns_texture = TRUE;
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, self->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);
glTexImage2D (GL_TEXTURE_2D, 0, self->gl_internal_format, width, height, 0, self->gl_format, self->gl_type, NULL);
/* Only apply swizzle if really needed, might not even be
* supported if default values are set
*/
if (swizzle[0] != GL_RED || swizzle[1] != GL_GREEN || swizzle[2] != GL_BLUE || swizzle[3] != GL_ALPHA)
{
/* Set each channel independently since GLES 3.0 doesn't support the iv method */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, swizzle[0]);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, swizzle[1]);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, swizzle[2]);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, swizzle[3]);
}
return GSK_GPU_IMAGE (self);
}
GskGpuImage *
gsk_gl_image_new_for_texture (GskGLDevice *device,
GdkTexture *owner,
GLuint tex_id,
gboolean take_ownership,
GskGpuImageFlags extra_flags)
{
GdkMemoryFormat format, real_format;
GskGpuImageFlags flags;
GskGLImage *self;
GLint swizzle[4];
format = gdk_texture_get_format (owner);
self = g_object_new (GSK_TYPE_GL_IMAGE, NULL);
gsk_gl_device_find_gl_format (device,
format,
0,
&real_format,
&flags,
&self->gl_internal_format,
&self->gl_format,
&self->gl_type,
swizzle);
if (format != real_format)
flags = GSK_GPU_IMAGE_NO_BLIT |
(gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT ? GSK_GPU_IMAGE_STRAIGHT_ALPHA : 0);
gsk_gpu_image_setup (GSK_GPU_IMAGE (self),
flags | extra_flags,
format,
gdk_texture_get_width (owner),
gdk_texture_get_height (owner));
gsk_gpu_image_toggle_ref_texture (GSK_GPU_IMAGE (self), owner);
self->texture_id = tex_id;
self->owns_texture = take_ownership;
return GSK_GPU_IMAGE (self);
}
void
gsk_gl_image_bind_texture (GskGLImage *self)
{
if (gsk_gpu_image_get_flags (GSK_GPU_IMAGE (self)) & GSK_GPU_IMAGE_EXTERNAL)
glBindTexture (GL_TEXTURE_EXTERNAL_OES, self->texture_id);
else
glBindTexture (GL_TEXTURE_2D, self->texture_id);
}
void
gsk_gl_image_bind_framebuffer_target (GskGLImage *self,
GLenum target)
{
GLenum status;
if (self->framebuffer_id)
{
glBindFramebuffer (target, self->framebuffer_id);
return;
}
/* We're the renderbuffer */
if (self->texture_id == 0)
{
glBindFramebuffer (target, 0);
return;
}
glGenFramebuffers (1, &self->framebuffer_id);
glBindFramebuffer (target, self->framebuffer_id);
glFramebufferTexture2D (target, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->texture_id, 0);
status = glCheckFramebufferStatus (target);
switch (status)
{
case GL_FRAMEBUFFER_COMPLETE:
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
g_critical ("glCheckFramebufferStatus() returned GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT. Expect broken rendering.");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
g_critical ("glCheckFramebufferStatus() returned GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS. Expect broken rendering.");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
g_critical ("glCheckFramebufferStatus() returned GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT. Expect broken rendering.");
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
g_critical ("glCheckFramebufferStatus() returned GL_FRAMEBUFFER_UNSUPPORTED. Expect broken rendering.");
break;
default:
g_critical ("glCheckFramebufferStatus() returned %u (0x%x). Expect broken rendering.", status, status);
break;
}
}
void
gsk_gl_image_bind_framebuffer (GskGLImage *self)
{
gsk_gl_image_bind_framebuffer_target (self, GL_FRAMEBUFFER);
}
gboolean
gsk_gl_image_is_flipped (GskGLImage *self)
{
return self->texture_id == 0;
}
GLint
gsk_gl_image_get_gl_internal_format (GskGLImage *self)
{
return self->gl_internal_format;
}
GLenum
gsk_gl_image_get_gl_format (GskGLImage *self)
{
return self->gl_format;
}
GLenum
gsk_gl_image_get_gl_type (GskGLImage *self)
{
return self->gl_type;
}
GLuint
gsk_gl_image_steal_texture (GskGLImage *self)
{
g_assert (self->owns_texture);
if (self->framebuffer_id)
{
glDeleteFramebuffers (1, &self->framebuffer_id);
self->framebuffer_id = 0;
}
self->owns_texture = FALSE;
return self->texture_id;
}
+41
View File
@@ -0,0 +1,41 @@
#pragma once
#include "gskgpuimageprivate.h"
#include "gskgldeviceprivate.h"
G_BEGIN_DECLS
#define GSK_TYPE_GL_IMAGE (gsk_gl_image_get_type ())
G_DECLARE_FINAL_TYPE (GskGLImage, gsk_gl_image, GSK, GL_IMAGE, GskGpuImage)
GskGpuImage * gsk_gl_image_new_backbuffer (GskGLDevice *device,
GdkMemoryFormat format,
gsize width,
gsize height);
GskGpuImage * gsk_gl_image_new (GskGLDevice *device,
GdkMemoryFormat format,
GskGpuImageFlags required_flags,
gsize width,
gsize height);
GskGpuImage * gsk_gl_image_new_for_texture (GskGLDevice *device,
GdkTexture *owner,
GLuint tex_id,
gboolean take_ownership,
GskGpuImageFlags extra_flags);
void gsk_gl_image_bind_texture (GskGLImage *self);
void gsk_gl_image_bind_framebuffer (GskGLImage *self);
void gsk_gl_image_bind_framebuffer_target (GskGLImage *self,
GLenum target);
gboolean gsk_gl_image_is_flipped (GskGLImage *self);
GLint gsk_gl_image_get_gl_internal_format (GskGLImage *self);
GLenum gsk_gl_image_get_gl_format (GskGLImage *self);
GLenum gsk_gl_image_get_gl_type (GskGLImage *self);
GLuint gsk_gl_image_steal_texture (GskGLImage *self);
G_END_DECLS

Some files were not shown because too many files have changed in this diff Show More