Commit Graph

2994 Commits

Author SHA1 Message Date
Benjamin Otte
b5b0002d24 rendernode: Return the right depth for colors
This makes sure we return U8_SRGB for GdkRGBA colors with linear
compositing.
2024-07-11 14:57:19 +02:00
Benjamin Otte
a7ceb8ce66 gdk: Add GDK_MEMORY_U8_SRGB depth
This is an experiment for now, but it seems that encoding srgb inside
the depth makes sense, as we not just use depth to decide on the
GL fbconfigs/Vulkan formats to pick, depth also encodes how the [0...1]
color values are quantized when stored.

Let's see where this goes.
2024-07-11 14:57:19 +02:00
Benjamin Otte
6dea23128a gpu: Add the GSK_GPU_IMAGE_SRGB flag
This commit just adds the flag, but I wanted to make it an individual
commit to explain the purpose:

The SRGB flag is meant to be used for images that have an SRGB format.
In Vulkan terms, that means VK_FORMAT_*_SRGB.
In GL, it means GL_SRGB or GL_SRGB_ALPHA.

As these formats have been madatory since GL 3.0, we can (ab)use them
uncoditionally. Images in these formats are renderable, too, so it's
not just usable for uploading.

What these images allow is treating the data as sRGB while shaders
access them as linear, thereby getting sRGB<=>linear conversions for
free.

It is also possible to switch off the linearization of these images and
treat them as sRGB, which allows all sorts of shenanigans, though one
has to be careful if that turning off applies to the relevant GL/Vulkan
code in question.
2024-07-11 14:57:19 +02:00
Benjamin Otte
2f4e19d514 gdk: Allow querying GL SRGB formats
Nobody is using this yet.
2024-07-11 14:57:19 +02:00
Benjamin Otte
1273413c7b vulkan: Import GL textures via dmabufs
If the GL texture is exportable to a dmabuf, we can just use our dmabuf
importing code to get that texture into Vulkan.
There is no need to go via host memory in that case.

And if it doesn't work, we just fall back, like before.
2024-07-11 14:14:35 +02:00
Benjamin Otte
ef3f48a2be vulkan: Refactor gsk_vulkan_image_new_for_dmabuf()
It now works with just a dmabuf and doesn't take a texture anymore.

Which means it can be used from other codepaths in the future.
2024-07-11 14:14:35 +02:00
Benjamin Otte
fff78b60e9 gpu: All nodes are implemented
Unimplemented nodes are a failure now.

We make this a soft failure with a g_warning() so that during
development when adding new nodes, the renderer doesn't instantly crash,
but instead prnts a warning.

But we do consider unimplemented nodes a bug now.

Because of that, add_fallback_node() is now renamed to add_cairo_node().
2024-07-11 13:34:37 +02:00
Benjamin Otte
9abc7fc80b gpu: Don't hand Cairo invalid nodes
When encountering an invalid node, exit asap. Don't draw it with Cairo,
Cairo won't know what to do with it either.
2024-07-11 13:34:37 +02:00
Benjamin Otte
d8059ebdd2 gpu: "Implement" GL shader nodes
Instead of falling back to Cairo, draw the pink error rectangle
directly.
2024-07-11 13:34:36 +02:00
Matthias Clasen
8c988a7b07 Take all transforms into account
When determining which way is up for the offloaded texture, we
must take all transforms into account - the ones outside the
subsurface node, and the ones inside.
2024-07-10 22:11:13 +02:00
Benjamin Otte
4f2b639a24 gpu: We can handle 90 degree rotations quite easily 2024-07-10 22:06:24 +02:00
Benjamin Otte
3e01924ca3 gpu: Handle dihedral transforms in occlusion culling 2024-07-10 22:06:24 +02:00
Matthias Clasen
4d2884bde7 offload: Support dihedral transforms
When looking for the texture transform, allow dihedral transforms,
and pass them along when attaching to the subsurface.
2024-07-10 21:34:12 +02:00
Benjamin Otte
6065165060 Add gdk_dihedral_swaps_xy
This function determines if a dihedral transform swaps x and y.
2024-07-10 21:34:12 +02:00
Benjamin Otte
9272bf96f6 gpu: Handle affine transforms without touching matrix
By moving negative affines to be treated like dihedrals, because they
also need support of the modelview, we can free up the affine branch for
doing work without it.

Not a big win I guess, but it makes scaling more efficient.
2024-07-10 21:34:12 +02:00
Benjamin Otte
ae3efb2d2f gpu: Implement transform support for dihedral transforms
This allows handling them without ever needing to offscreen for losing
the clip, because the clip can always be transformed.

Also, all the optimizations keep working, like occlusion culling,
clears, and so on.

The main benefit of this work is the ability for offloading to now
handle dihedral transforms of the video buffer.

The other big advantage is that we can now start our rendering with a
dihedral transform from the compositor.
2024-07-10 21:34:12 +02:00
Benjamin Otte
b9ecae84f5 gpu: Shuffle some transform flags around
No need to check for negative numbers now that we can just use the
category that doesn't give us any.
2024-07-10 21:34:12 +02:00
Benjamin Otte
cd3286c71a gpu: Switch to GskFineTransformCategory
This is purely replacing the enums, no functional changes.
2024-07-10 21:34:12 +02:00
Benjamin Otte
83c2766e3f rendernode: Handle rotation transforms in opacity calculations
Tests included.
2024-07-10 21:34:12 +02:00
Benjamin Otte
5f719c8ea3 transform: Implement transform_point() for dihedrals
No longer using the default path and risking rounding issues.
2024-07-10 21:34:12 +02:00
Benjamin Otte
555f7d5404 transform: Implement transform_bounds() for dihedrals
No longer using the default path and risking rounding issues.
2024-07-10 21:34:12 +02:00
Benjamin Otte
3bcfc5539c transform: Add gsk_transform_to_dihedral()
I hate everything about this.

Is is xy or yx now?
Do I need to combine(a, b) or combine(b, a)?
2024-07-10 14:38:48 +02:00
Benjamin Otte
3221a8bdab gdk: Rename GdkTextureTransform to GdkDihedral
... and put it into its own header.

We want to use it in more places and the name and location are awkward.
2024-07-10 12:36:07 +02:00
Benjamin Otte
930f059f5e transform: Introduce GskFineTransformCategory
This category does a finer-grained categorization than
GskTransformCategory, but it is deliberatedly made to allow
easy backwards compatibility.

The reason for the categories is that they fit our renderers more
fine.

In particular, it allows implementing wl_output_transform support more
efficiently, thereby allowing rendering buffers the right way for
rotated phone screens or monitors.
2024-07-10 12:36:07 +02:00
Benjamin Otte
9a6e61e510 rect: There's no coverage witout overlap
The rectangles need to touch/overlap in both directions, otherwise
there's no coverage that covers both rectangles.

Test included.

Fixes rendering glitches in various apps when redrawing.

Fixes: #6849
2024-07-10 00:28:33 +02:00
Matthias Clasen
ed4f51436c Merge branch 'matthiasc/for-main' into 'main'
Add a missing include

Closes #6842

See merge request GNOME/gtk!7433
2024-07-09 03:04:25 +00:00
Matthias Clasen
7837354c6c Add a missing include
When building without Vulkan, we don't get this include for free.
So add it explicitly.

Fixes: #6842
2024-07-08 22:18:11 -04:00
Benjamin Otte
5dc6f134c5 gpu: Make offscreening code use process()
... instead of init_draw(); add_node(); finish_node();

We hook into the infrastructure one step earlier and close to where the
default renderer_render() and renderer_render_texture() arrive in the
nodeprocessor.

Why is this relevant?
Because process() does occlusion culling.

TL;DR: offscreens do culling now
2024-07-08 23:22:55 +02:00
Benjamin Otte
6daeb7e504 gpu: Transition exported textures into GENERAL layout
We import them as general, so they should be exported like that.

This was a longstanding issue that I never got around to fixing and I'm
touching this code anyway atm.
See commit 3aa6c27c26 for more details.
2024-07-08 23:22:41 +02:00
Benjamin Otte
fcf59ad135 gpu: Allow NULL as clear color
NULL disables clearing. We only implement this for GL as in Vulkan we'd
need to create different renderpasses with different attachment
descriptions and that would require more plumbing.
2024-07-08 23:07:36 +02:00
Benjamin Otte
1dd905d976 gpu: Fix wrong rect check in occlusion fallback path
We need to check that the clip is inside the opaque region, not that the
opaque region is inside the clip.

Test included, using the only not that hits the fallback path with an
opaque region smaller than its bounds.
2024-07-08 23:07:36 +02:00
Benjamin Otte
155f7cdeec gpu: Chceck if a container node is opaque as fallback
Sometimes container nodes contain lots of overlapping opaque items. In
that case we can use the container node itself as the first node even
though none of the children cover the whole paint area.

The use case for this is a grid of cells like in a terminal where all
the cells are opaque and we want to avoid drawing the background behind
them.
2024-07-08 23:07:36 +02:00
Benjamin Otte
6d564075f3 gsk: texture-scale nodes with non-integer bounds aren't opaque
Due to the way the intermediate offscreen gets drawn, we might end up
with seams at the edges.

And I don't think it's worth spending more time on than saying "not
opaque".

Fixes the compare-render testsuite

New testcase included.
2024-07-08 15:28:14 +02:00
Benjamin Otte
4cdf7aa65a rendernode: Add containernode->opaque and fill it at startup
We want to operate with opacities, so it makes sense to have this radily
available.

And we're doing a walk over all children on creation anyway, so why not
just capture the rect there.
2024-07-08 15:28:14 +02:00
Benjamin Otte
329dc9e0cf gpu: Change get_opaque() implementation of containers
We want to be able to express opaque grids. This means that the app
provides either a row of columns of opaque nodes or a column of rows,
and then the containers will magically figure it out.

The main use case for this is terminals, which are uilt using cells. And
when there's a transparent background configured but the contents are
opaque, it'd be nice if we could figure that out.

Also remove the 80% requirement. It is rather arbitrary and while it
helps for some cases, the aforementioned grid would suffer.
2024-07-08 15:28:14 +02:00
Benjamin Otte
e02de45537 gpu: Add GSK_GPU_DISABLE=occlusion
This simply disables add_first_node() usage.

Useful to find bugs in its implementation or track performance
with/without it.
2024-07-08 15:28:14 +02:00
Benjamin Otte
29fbda49bb gpu: Implement add_first_node() for rounded clip nodes
This is a bit more expensive than clip nodes, because we have to check
the rounded edges are outside of the clip.
2024-07-08 15:28:14 +02:00
Benjamin Otte
1b155341bd gpu: Implement add_first_node() for clip nodes
Clip nodes often appear in the widget tree.

And the implementation can be trivial because of the sanity checks
already performed before calling the vfunc.
2024-07-08 15:28:14 +02:00
Benjamin Otte
96c02c1eb4 gpu: Implement add_first_node() for transform nodes
This is required because transform nodes appear everywhere.

We just exit for all transforms that can't transform the clip rect
losslessly. Both because they are rare and because we'd make the
coverage possibilities much lower.
2024-07-08 15:28:14 +02:00
Benjamin Otte
116d662e0f gpu: Add early exit to add_first_node()
A node must cover the full clip region to be eligible for being the
first opaque node.

Do an early exit for all nodes that aren't big enough for that.
2024-07-08 15:28:14 +02:00
Benjamin Otte
d81cd4751f gpu: Add add_first_node for colors
Color nodes can set the default background of the renderpass, instead of
doing a clear op or running a shader.
2024-07-08 15:28:14 +02:00
Benjamin Otte
dd33068943 gpu: Implement add_first_node for containers
Containers can walk the list of children back to front, trying to find
the topmost node that fully covers the viewport.

And then they can skip drawing all the nodes before that one.
2024-07-08 15:28:14 +02:00
Benjamin Otte
09c1e51b8a gpu: Add gsk_gpu_node_processor_add_first_node()
Asks a node to add itself if it is fully covering the clip rectangle.
In that case, it is the first node that needs to be added.

If the node is not fully covering the clip, it should not draw itself,
because there might be stuff needing to be drawn below.

If a node adds itself, it should call gsk_gpu_render_pass_begin_op().
2024-07-08 15:28:14 +02:00
Benjamin Otte
af9a9422c4 gpu: Allow passing a background color to renderpasses
It's not used yet, everybody is passing GDK_RGBA_TRANSPARENT.
2024-07-08 15:28:14 +02:00
Benjamin Otte
df3c85ea7f gpu: Move renderpass handling into the nodeprocessor
There's no need for the frame to do this.
2024-07-08 15:28:14 +02:00
Benjamin Otte
b14a115fc0 container: Implement get_opaque_rect()
We find the first child that covers >80% of the container and return
that.

This is a nice speedup for the common case of a GtkWindow being covered
by a large opaque background.
It will fall apart for fancy themes that play with transparency or for
small windows because the shadow region gets too large.

But then we just scan the whole node tree.

We could think about adapting the 80% number, because that wasn't chosen
with any real scientific data behind it.
2024-07-08 15:28:14 +02:00
Benjamin Otte
355a88d002 roundedclip: Implement get_opaque_rect
This takes both the vertical and horizontal rectangle that isn't
covering the rounded corners and intersects both with the child's opaque
rect.
And then it returns the larger of the two.

This means the small slices of a window near the left/right (or
top/bottom) will never be covered, but if we wanted that, we'd need to
use something else than a rectangle - either a region or actually a
rounded rect.

But that is a lot more expensive to implement.
2024-07-08 15:28:14 +02:00
Benjamin Otte
1014b3d972 rendernode: Implement a bunch of simple opque_rect getters
Not much to write home about here.
2024-07-08 15:28:14 +02:00
Benjamin Otte
1a2b1575d6 rendernode: Add fully-opaque flag
Allows rendernodes to advertise themselves as fully opaque.

This is used as a fast path for get_opaque_rect().
2024-07-08 15:28:14 +02:00
Benjamin Otte
9c032bec89 gsk: Add gsk_render_node_get_opaque_rect()
Gets a rectangle inside the rendernode that is opaque.

This function only adds the API. So far, no implementation exists.
2024-07-08 15:28:14 +02:00