Commit Graph

3354 Commits

Author SHA1 Message Date
Benjamin Otte
896ea5b753 memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).

This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:

1. it gets closer to the desired effect

2. it is a lot faster

Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.

Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-06 15:47:35 -04:00
Benjamin Otte
cea961f4f4 memoryformat: Take src_format and dest_format
Why do we need this? Because RGB images are provided in RGB format but
GPUs can't handle RGB, only RGBA, so we need to convert.

And we need to do that without allocating too much memory, because
allocating memory is slow. Which means in aprticular we need to do the
conversion after mipmapping, not before (like we were doing).
2024-09-06 15:47:34 -04:00
Benjamin Otte
848c6815d3 gpu: Allow uploading of mipmap levels when tiling
This allows uploading less memory but requires computing lod levels on
the CPU which is slow because it reads through all of the memory and so
far entirely not optimized.

However, it uses significantly less VRAM.

This is done by adding a gdk_memory_mipmap() function that does this
task.
The texture upload op now accepts a lod level and if that is >0 it uses
gdk_memory_mipmap() on the source texture.
2024-09-06 15:47:34 -04:00
Philip Withnall
e87b4dca71
gsk: Add autoptr cleanup function for GskStroke
It appeared to be missing, while other GSK types already have cleanup
functions defined.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-03 16:50:10 +01:00
Benjamin Otte
563cce5530 gsk: Use gsk_rect_init_offset() everywhere
... and make it use a graphene_point_t as argument, because that's what
the callers want.
2024-09-02 00:22:37 +02:00
Benjamin Otte
b0e4be7fda rendernode: Colors should not influence depth decisions
Depth of a rendernode should be determined by the textures used and the
compositing colorstate requirements.
Colors influence the colorstate choice, so they indirectly influence the
depth, but they should not influence the depth directly.

Otherwise a single color in a border being rec2100-pq would make us
switch to 16bit float.

Also remove gdk_color_get_depth(), because it was only used here and
because again: Colors should not influence depth decisions.
2024-09-02 00:22:37 +02:00
Benjamin Otte
e29701a203 gl: Handle GDK_MEMORY_NONE depth
In rare circumstances a rendernode can be MEMORY_NONE and we don't want
to render it as a float texture then.
2024-09-02 00:22:37 +02:00
Benjamin Otte
6a1cd87480 gpu: Use builder for memory texture 2024-09-01 22:49:34 +02:00
Benjamin Otte
49ee69f316 gpu: Use right GL context when exporting texture
We want to use the display's context on the resulting texture,
but we do not want to use it for the stufff we need to do while
exporting - most importantly the GLsync.

Fixes #6976
2024-09-01 22:49:34 +02:00
Benjamin Otte
0defdc4af5 gpu: Plug fd leak in fallback path
If we can't construct a dmabuf texture, we need to clear the dmabuf fd.
2024-08-26 20:31:08 +02:00
Benjamin Otte
ea9b47f1b6 gpu: Use common cleanup function
Just simple cleanup, both functions do the same thing.
2024-08-26 20:31:08 +02:00
Benjamin Otte
65c8320a32 gpu: Fix fd leak in GL dmabuf export
The texture ID is not deleted on dmabuf export; a copy is made, the
GskGpuImage retains ownership.

However when doing GL export, the texture *does* take ownership, so we
need the stealing semantics for that case.
2024-08-26 20:31:08 +02:00
Benjamin Otte
4be1d754b7 vulkan: Don't spam stderr on failed Vulkan import
We write a debug message and then handle things using fallback.

Fixes error messages when trying to import incompatible dmabufs.
(in my case: llvmpipe dmabufs into radv)
2024-08-23 22:53:13 +02:00
Benjamin Otte
73c94cf1d6 gpu: Use the shared GL context when creating GL textures
The non-shared context's surface must survive the lifetime of the
GL texture, and when the renderer gets unrealized the surface goes away,
but we cannot guarantee that all GL textures have been destroyed by
then.

So better use a context we know will survive becuase it isn't bound to a
surface.

This is the same fix for NGL as f3ac0535f8
was for GL.
2024-08-23 20:04:46 +02:00
Benjamin Otte
6a986f03b6 gpu: Simplify the blur op a bit
I was looking through it and thought this looks better.

It's also 21 lineas of code less.
2024-08-23 19:01:05 +02:00
Benjamin Otte
54758bee1f gpu: Only run a single renderpass
Instead of running one renderpass per clip region, run one renderpass for
the whole clip extents, and just set the scissor to the individual clip
rects.

This means that we need to use LOAD_OP_LOAD in cases where we don't
redraw the full extents, but nonetheless, the eprformance wins of
avoiding renderpasses are worth it, in particualr on tilers like the
Raspberry Pi or other mobile chips and the Apple M1/2.
2024-08-21 21:13:34 +02:00
Benjamin Otte
cfe0da1eed gpu: Add GskGpuLoadOp
We want to differentiate between CLEAR, DONT_CARE and LOAD in the
future, and the current boolean doesn't allow that.

Also implement support for the the different ops in the Vulkan
renderpass code.
2024-08-21 21:13:34 +02:00
Benjamin Otte
1198dc76a4 gpu: Add gsk_gpu_first_node_begin_rendering()
This starts the renderpass at the given scissor rect.

It just splits out the gsk_gpu_render_pass_begin_op() call into a
simpler function, so it's harder to mess up.
2024-08-21 21:13:34 +02:00
Benjamin Otte
bed3e9918b gpu: Add GskGpuFirstNodeInfo
Just encapsulate all the data for the add_first_node() call into a
single struct.
2024-08-21 21:13:34 +02:00
Benjamin Otte
d76bb2991a gpu: Refactoring: Pull out nodeprocessor
Add gsk_gpu_node_processor_set_scissor() that allows resetting the
nodeprocessor's scissor and clip rectangle.
That in turn allows using the same nodeprocessor instance for all the
rects we draw for the clip region.
2024-08-21 21:13:34 +02:00
Benjamin Otte
e962e86fcd gpu: Split out a function
converting an image to any colorstate (not just ccs-capable default
colorstates) can go in its own function.
2024-08-21 21:13:34 +02:00
Benjamin Otte
dd59c90842 rendernode: repeeat nodes with empty child bounds are transparent
So they must not copy the fully_opaque flag from the child.

Adapted the testcase that accidentally caught it do now always catch it
by setting a proper background.
2024-08-21 21:13:26 +02:00
Benjamin Otte
c7fabe2897 gpu: Be more aggressive about GC'ing dead textures
When we encounter many dead textures, we want to GC. Textures can take
up fds (potentially even more than 1) and when we are not collecting
them quickly enough, we may run out of fds.

So GC when more then 50 dead textures exist.

An example for this happening is recent Mesa with llvmpipe udmabuf
support, which takes 2 fds per texture and the test in
testsuite/gdk/memorytexture that creates 800 textures of ~1 pixel each,
which it diligently releases but doesn't GC.

Related: #6917
2024-08-21 09:45:05 +02:00
Matthias Clasen
740965016f Merge branch 'matthiasc/for-main' into 'main'
Add a GDK_DISABLE env var

See merge request GNOME/gtk!7632
2024-08-20 01:58:54 +00:00
Matthias Clasen
26a2966a7b gdk: Beef up gdk_parse_debug_var
Add a docstring for the variable itself, and print it as part
of the help message. Update all callers to provide a docstring.
2024-08-19 20:40:32 -04:00
Matthias Clasen
2d230f79a6 Change the offload-disable flag
Move this from GSK_DEBUG=offload-disable to GDK_DISABLE=offload.
2024-08-19 20:40:32 -04:00
Benjamin Otte
2fb3dc8c90 Merge branch 'wip/otte/for-main' into 'main'
wayland: Create EGL window in make_current() if necessary

Closes #6930

See merge request GNOME/gtk!7633
2024-08-19 23:34:35 +00:00
Benjamin Otte
f6a8ba0ccb gpu: The colorstate op doesn't need a colorstates arg
It's using the same colorstate all the time: any premultiplied.

So just hardcode it.
2024-08-20 01:05:20 +02:00
Benjamin Otte
f3ac0535f8 gl: Use the shared GL context when creating GL textures
the non-shared context's surface must survive the lifetime of the
GL texture, and when the renderer gets unrealized the surface goes away,
but we cannot guarantee that all GL textures have been destroyed by
then.

So better use a context we know will survive becuase it isn't bound to a
surface.
2024-08-20 01:05:20 +02:00
Matthias Clasen
d4e730db0c node parser: Move parse_color even earlier
It will be used by parse_stops in the future, so move it above.

No functional change.
2024-08-17 16:24:20 -04:00
Benjamin Otte
96139a902d gsk: Don't print any sRGB color as rgb() or rgba()
If the color value is not inside the proper range for rgb() or rgba()
values being integers, use color() instead.

Tests added/adapted.
2024-08-17 21:09:25 +02:00
Benjamin Otte
a6233ac852 rendernodeparser: Check color values aren't out of range
Use the clamp() API from the previous commit to:

1. Clamp values into range
2. Emit an error if values were out of range

Unlike CSS, which just clamps and doesn't emit an error, we do want to
emit one because we care about colors being correct in our node files.
2024-08-17 18:12:23 +02:00
Benjamin Otte
585f31fa2e rendernodeparser: Rename function
There's no need to name a function parse_color2() when parse_color()
doesn't exist.
2024-08-17 16:03:46 +02:00
Benjamin Otte
69e7838461 rendernodeparser: Don't have unnecessary forward declarations
Reorders functions to not have them.

No functional changes.
2024-08-17 16:03:46 +02:00
Matthias Clasen
436989d745 gsk: Apply the same transfer fixes
These are copied from gdkcolordefs.h.
2024-08-14 13:21:28 -04:00
Benjamin Otte
824ccfc562 gpu: Add an assertion
If the wrong color states get passed, we need to figure that out, before
we run shaders with junk values doing god knows what.
2024-08-14 08:30:55 +02:00
Benjamin Otte
79c2df8392 color: Handle negative values in all transfer functions
Make sure that for all eotfs/oetfs, eotf(x) == -eotf(-x)

In particular, don't pass negative values to pow() and cause undefined
behavior.
2024-08-13 20:47:40 +02:00
Matthias Clasen
13d415f2f6 Add a comment 2024-08-11 16:31:18 -04:00
Matthias Clasen
0436801a9c Merge branch 'matthiasc/for-main' into 'main'
docs: Mark the docs check as failing

See merge request GNOME/gtk!7598
2024-08-11 19:43:16 +00:00
Matthias Clasen
5dbce5ce9b docs: Add a missing bit 2024-08-11 14:47:59 -04:00
Benjamin Otte
68d73dcce5 nodeparser: Handle disallowed values for radial gradients
Make sure the radii are strictly positive.

Also handle the case where start >= end.
We can't really underline that error, because we don't track the
locations of the start/end properties until we know that there's an
error.
So just underline the whole radial gradient declaration.

Test included
2024-08-11 19:07:40 +02:00
Benjamin Otte
9643a21827 gl: Interpolate gradient colors as premultiplied
Tests included
2024-08-11 19:07:40 +02:00
Matthias Clasen
23922eebf1 gl: Handle text colors with color states
Since we don't have proper color management here, just convert
any color we meet to sRGB and hope for the best.
2024-08-10 07:48:18 -04:00
Matthias Clasen
92bd85ba30 nodeparser: Support color states in text nodes
Test included.
2024-08-10 07:37:01 -04:00
Matthias Clasen
ca7aa30bc5 gsk: Use private text node api 2024-08-10 07:37:01 -04:00
Matthias Clasen
d17972427a gsk: Add private text node api
Add a constructor that takes a GdkColor and a corresponding getter.
2024-08-10 07:37:01 -04:00
Matthias Clasen
25f0c81530 Fix a copy-paste error
This was introduced in ea28dc8cff.
2024-08-10 07:11:56 -04:00
Matthias Clasen
310196cc59 gl: Handle box shadow colors with color states
Since we don't have proper color management here, just convert
any color we meet to sRGB and hope for the best.
2024-08-09 22:27:57 -04:00
Benjamin Otte
04ee41d7b0 Merge branch 'wip/otte/for-main' into 'main'
lots of small things

See merge request GNOME/gtk!7585
2024-08-10 01:10:12 +00:00
Benjamin Otte
23af1cd8ad gpu: When transforming to simpler transform, we might be all clipped
When transforming back from a complex transform to a simpler transform,
the resulting clip might turn out to clip everything, because clips can
grow while transforming, but the scissor rect won't. So when this
process happens, we can end up with an empty clip by transforming:

1. Set a clip that also sets the scissor
2. transform in a way that grows the clip, say rotate(45)
3. modify the clip to shrink it
4. transform in a way that simplifies the transform, say another
   rotate(45)
5. Figure out that this clip and the scissor rect do no longer overlap

Catch this case and avoid drawing anything.
2024-08-10 02:38:13 +02:00
Matthias Clasen
0f7c0f616c nodeparser: Handle shadows with color state
Test included.
2024-08-09 20:09:31 -04:00
Matthias Clasen
5551f30400 gsk: Use private shadow node api 2024-08-09 20:09:31 -04:00
Matthias Clasen
2c10d72fe5 gsk: Add private shadow node api
Add a new GskShadow2 struct that has a GdkColor instead of
a GdkRGBA, and a new constructor and getter to go along with
it.

With this commit, my_color_get_depth is no longer used and
has been dropped.
2024-08-09 20:09:31 -04:00
Matthias Clasen
44fe51247c gsk: Change the blur op api
Pass the ccs, opacity and GdkColor to the op to let it make
decisions about color conversion.

Update the callers.
2024-08-09 20:09:31 -04:00
Matthias Clasen
3a99f1e9f1 gsk: Change the colorize op api
Pass the ccs, opacity and GdkColors to the op to let it make
decisions about color conversion.

Update the callers.
2024-08-09 20:09:30 -04:00
Matthias Clasen
d233f0ca3e node parser: Move parse_color2 up
We will use this function more so move it where it belongs.
2024-08-09 20:09:30 -04:00
Matthias Clasen
c548bdc3fe css: Add gtk_css_parser_consume_number_or_percentage
This comes in handy in the render node parser.
2024-08-09 20:09:30 -04:00
Benjamin Otte
16c7003acb gdk: Pass the opaque rect to begin_frame() actually
We know it at begin_frame() time, so if we pass it there instead of
end_frame(), we can use it then to make decisions about opacity.

For example, we could notice that the whole surface is opaque and choose
an RGBx format.
We don't do that yet, but now we could.
2024-08-10 01:40:46 +02:00
Benjamin Otte
75748f4ae9 gl: Remove update_area() trick
This is poking into the surface directly, so not a good idea.
And I want to hide that struct in the priv member.

Technically, this code should look at the opaque region, but I am lazy
and the GL renderer is on its way out, so I think it's not worth doing.
2024-08-10 01:40:46 +02:00
Benjamin Otte
a35f8d52d6 gsk: Clear current context after unrealize()
Make sure both GL renderers don't leave their contexts alive via the
current context, but ensure they dispose of them properly.

Fixes issues when the corresponding GL resources in the surfaces they
were attached to go away.
2024-08-10 01:40:45 +02:00
Benjamin Otte
b08ccc0bec ngl: Stop crashing with zink and llvmpipe
We were not calling make_current() early enough anymore after the
Vulkan validation-layer fixes in !7468

Change that by calling it earlier.
2024-08-10 01:40:45 +02:00
Benjamin Otte
523cd0dff7 glcontext: Add a surface_attached flag
GLContexts marked as surface_attached are always attached to the surface
in make_current().
Other contexts continue to only get attached to their surface between
begin_frame() and end_frame().

All our renderer use surface-attached contexts now.
Public API only gives out non-surface-attached contexts.

The benefit here is that we can now choose whenever we want to
call make_current() because it will not cause a re-make_current() if we
call it outside vs inside the begin/end_frame() region.

Or in other words: I want to call make_current() before begin_frame()
without a performance penalty, and now I can.
2024-08-10 01:40:45 +02:00
Benjamin Otte
8ac1806015 gdk: Use begin_frame_full() everywhere
begin_frame() is going to go away, so we should use the "real" function.
2024-08-10 01:40:45 +02:00
Benjamin Otte
0b2275774f gdk: Add gdk_draw_context_end_frame_full()
... and pass the opaque region of the node.

We don't do anything with it yet, this is just the plumbing.

The original function still exists, it passes NULL which is the value
for no opaque region at all.
2024-08-10 01:40:45 +02:00
Benjamin Otte
4fbfe9b041 gsk: Warn about unused result in gsk_render_node_get_opaque_rect()
It's a function to easily forget to check the return value.

In fact I just did that.
2024-08-10 01:40:45 +02:00
Benjamin Otte
904b1815b5 nodeprocessor: Consult scissor after rounded clip
If we apply a rounded clip, we might change the clip in a way that makes
it intersectable with the scissor again, if both had diverged before.

So try and intersect with the clip.
2024-08-10 01:40:45 +02:00
Benjamin Otte
d6322c6389 gsk: Switch box shadow nodes to use offsets
Instead of
  float dx;
  float dy;
have a
  graphene_point_t offset;
in the object and in all APIs relating to them.
2024-08-10 01:40:45 +02:00
Benjamin Otte
2ee16e5dd9 gl: Set correct context when disposing GLDriver 2024-08-10 01:40:45 +02:00
Matthias Clasen
ea28dc8cff nodeparser: Support color states for box shadows
Just switch from parse_color to parse_color2, and apply the
corresponding changes to serialization too.

Test included.
2024-08-08 15:49:55 -04:00
Matthias Clasen
d3b9eb7fc8 gsk: Use private box shadow api 2024-08-08 15:43:49 -04:00
Matthias Clasen
cdb61923af gsk: Add private box shadow node api
Add a constructor that takes a GdkColor, and a getter for it.
2024-08-08 15:43:49 -04:00
Matthias Clasen
070ddcd14b Change box shadow op api
Pass the ccs, opacity and GdkColor and let the op decide about
color conversions. Update all callers.
2024-08-08 15:43:49 -04:00
Matthias Clasen
355890b421 gsk: Port the cairo blur to GdkColor
Update all callers.
2024-08-08 15:43:49 -04:00
Matthias Clasen
33f8fa331d fp16: Mark ifuncs as unused to pacify clang
clang in F40 seems to have forgotten what fp16 is, and doesn't
use the resolver functions for anything, and then complains that
they are unused...
2024-08-08 14:40:19 -04:00
Benjamin Otte
99d291eb69 Merge branch 'wip/otte/occlusion' into 'main'
Implement advanced occlusion culling

See merge request GNOME/gtk!7570
2024-08-08 14:22:22 +00:00
Benjamin Otte
3313fd4e2b vulkan: Turn debug messages into warnings
Vulkan errors are quire critical, so we want to see them.

Our code is good enough to handle all non-critical errors.
2024-08-08 04:41:16 +02:00
Matthias Clasen
56c02dd7d1 Merge branch 'css-color-hookup-2' into 'main'
Make non-srgb css colors work for borders

See merge request GNOME/gtk!7550
2024-08-07 23:14:35 +00:00
Benjamin Otte
4e4ed1e2d5 gpu: Implement occlusion for subsurface nodes
In the case of no offloading, we want to pass through to the child
(which is likely a big texture doing occlusion).

In the case of punching a hole, we want to punch the hole and not draw
anything behind it, so we start an occlusion pass with transparency.

And in the final case with offloading active, we don't draw anything,
so we don't draw anything.

This should fix concerns about drawing the background behind the video
as mentioned for example in
https://github.com/Rafostar/clapper/issues/343#issuecomment-1445425004
2024-08-07 23:26:03 +02:00
Benjamin Otte
82aa2cb5c2 gpu: Implement add_first_node for debug nodes
As always, we want to have no influence on any results
from these nodes.
2024-08-07 23:26:03 +02:00
Benjamin Otte
e9944148d5 gpu: Add GSK_DEBUG=occlusion
Draws a semi-transparent white overlay over all regions that have
been chosen for occlusion.
2024-08-07 23:26:03 +02:00
Benjamin Otte
afa4eb7d35 gpu: Make containers check opaque size for early exit
Container nodes save their opaque region, so it's quick to access. Use
that to check if the largest opaque region even qualifies for culling -
and if not, just exit.

Speeds up walking node trees by a lot.
2024-08-07 23:26:03 +02:00
Benjamin Otte
55597d88a4 gpu: Run full check for every clip rect
Now that we can specify the min size for an occlusion pass, we can
specify that we want the full clip rect to be occluded for occlusion to
trigger.

The benefit of this is that for partial redraws we almost
always get the background color to cover the redrawn rectangle, so
occlusion will kick in.
2024-08-07 23:26:03 +02:00
Benjamin Otte
ac37b589b6 gpu: Require an occlusion path to be 10% of image
That way we are guaranteed to run <=10 occlusion passes.
2024-08-07 23:26:03 +02:00
Benjamin Otte
b9d868b8eb gpu: Pass min occlusion size as argument
That allows as to vary the number. We don't do that yet, but we could
now.
2024-08-07 23:26:03 +02:00
Benjamin Otte
30e5bfcbf0 gpu: Refactor culling function
Split the loop into 2: One for the culling and one for later, once we've
decided to not try culling anymore.
2024-08-07 23:26:03 +02:00
Benjamin Otte
57e21683a6 gpu: Try largest clip rect first
When trying to cull, try culling from the largest rectangle of the
remaining draw region first. That region has the biggest chance of
containing a large area to skip.

As a side effect, we can stop trying to cull once the largest rectangle
isn't big enough anymore to contain anything worth culling.
2024-08-07 23:26:03 +02:00
Benjamin Otte
852ecf7c20 gpu: Consult scissor for clip bounds
When querying clip bounds, also check the scissor rect, because
sometimes that one is tighter than the clip bounds, because the clip
bounds need to track some larger rounded corners.

Makes a few tests harder to break.
2024-08-07 23:26:03 +02:00
Benjamin Otte
5976debfcd gpu: Change how occlusion passes work
Instead of requiring an occlusion pass to cover the whole given scissor
rect, allow using a smaller rect to start the pass.

When starting such a pass, we adjust the scissor rect to the size of
that pass and do not grow it again until the pass is done.
The rectangle subtraction at the end will then take care of subtraction
that rectangle from the remaining pixels.

To not end up with lots of tiny occlusion passes, add a limit for how
small such a pass may be.
For now that limit is arbitrarily chosen at 100k pixels.
2024-08-07 23:26:03 +02:00
Benjamin Otte
08fcba63d0 gpu: Split out a function
gsk_gpu_node_processor_rect_to_device() is a useful function to have,
even if it has to return FALSE sometimes when there is no simple 1:1
mapping - ie when the modelview contains a rotation.
2024-08-07 23:26:03 +02:00
Benjamin Otte
1abe9760ab gpu: Change the way clip rectangles are processed
Instead of just iterating over all the rectangles of the region,
always draw the first rectangle of the region and subtract it when done.

This sounds more complicated, but it will allow us to modify the
rectangle in future commits.
2024-08-07 23:26:03 +02:00
Benjamin Otte
9a4d8453ed gpu: Remove unused argument
the clip is already available via node->scissor so no need to track
that.
2024-08-07 23:26:03 +02:00
Benjamin Otte
b637c3e201 gpu: Pass the clip region even further down
We are now handling the region inside the nodeprocessor.
2024-08-07 23:26:03 +02:00
Benjamin Otte
292f54dd60 gpu: Split out render function
Makes the code easier to understand
2024-08-07 23:26:03 +02:00
Benjamin Otte
1328c1409a gpu: Make the region argument transfer full
I want to modify the region while using it, and everybody destroys it
right after, so now there's no need to do a copy.
2024-08-07 23:26:03 +02:00
Benjamin Otte
dbeddd4417 gpu: Always pass a clip region to render()
This way, we can remove the code that checks for its existence in that
function, making the code simpler.
2024-08-07 23:26:03 +02:00
Benjamin Otte
add5dec4a9 rect: Add another utility function
Add gsk_rect_to_cairo_shrink() to match gsk_rect_to_cairo_grow()
2024-08-07 23:26:03 +02:00
Matthias Clasen
ee18156675 gsk: Add gsk_render_node_is_hdr
Add a function that tracks whether a render node's content is
in a wide gamut color state (in practice, that means non-sRGB).

This will be used in render_texture to determine the color
state to use when creating a texture.
2024-08-07 11:14:21 -04:00
Matthias Clasen
ffdc8c8f60 gsk: Drop some unused code
Nobody is using gsk_gpu_download_png_op, and we are going to
refactor the download op code.
2024-08-07 08:39:53 -04:00
Jonas Ådahl
8089222fc3 gsk/gpu/downloadop: Include glib-unix.h
It's needed by g_close().
2024-08-06 23:41:46 +02:00
Benjamin Otte
6c54d0a7e2 gpu: Consult target colorstate for depth
When creating images for use with different colorstates, ensure that
they have the depth of that colorstate. Otherwise we might lose accuracy
due to quantization.

Fixes mipmaps in rec2100 being rendered as RGBA8.
2024-08-06 22:15:17 +02:00
Benjamin Otte
e58f9ea1b4 rendrenodeparser: Use simpler function
We don't need to peek tokens.
2024-08-06 17:50:43 +02:00
Matthias Clasen
a3691d311b nodeparser: Support color states in border nodes
Test included.
2024-08-06 07:35:00 -04:00
Matthias Clasen
e220e6dae7 gsk: Use private border node api
Use the GdkColors returned by this function instead of assuming
the colors of a border node are always sRGB.
2024-08-06 07:35:00 -04:00
Matthias Clasen
bd3d1f7715 gsk: Add private border node api
Add a constructor that takes GdkColors, and a getter for those.

To support the existing api, we convert the colors to GdkRGBA
as needed.
2024-08-06 07:35:00 -04:00
Matthias Clasen
f3ffa99f6a gsk: Change the border op api
Pass the ccs, opacity and GdkColors to the op to let it make
decisions about color conversion. Also, reorder the offset to
follow the same order as the color ops.

Update the callers.
2024-08-06 07:35:00 -04:00
Matthias Clasen
d9e15ff6e9 Colors are always unpremultiplied
We can't use gsk_gpu_node_processor_color_states_self() for ops which
apply alt to colors that don't come from textures, since those are
always unpremultiplied.

This fixes the + and - in disabled spin buttons appearing completely
white.
2024-08-06 00:59:23 -04:00
Matthias Clasen
71d6392572 nodeparser: Rewrite the color parsing
Use gtk_css_parser_consume_function, for better error handling.
We are now getting the expected error for

  color(srgb 1 2 3 4 5 6)

Test included.
2024-08-06 00:23:07 -04:00
Matthias Clasen
dbd16cd9da Rename GDK_COLOR_INIT_SRGB
Rename the macro to GDK_COLOR_SRGB, and make it usable as
a compound literal as well.

Update all users.
2024-08-06 00:06:41 -04:00
Matthias Clasen
f9c9a03404 gsk: Improve handling of fill and stroke nodes
Use GdkColor here. We still convert to sRGB as the last step, though.
2024-08-05 15:59:28 -04:00
Matthias Clasen
7dab23e38a gl: Handle color nodes with color states
Since we don't have proper color management here, just convert
any color we meet to sRGB and hope for the best.
2024-08-05 11:11:15 -04:00
Matthias Clasen
16431da3f2 nodeparser: Add support for cicp color states
Allow defining cicp color states with an @-rule:

    @cicp "jpeg" {
      primaries: 1;
      transfer: 13;
      matrix: 6;
      range: full;
    }

And allow using them in color() like this:

    color("jpeg" 50% 0.5 1 / 75%)

Note that custom color states use a string, unlike default color
states which use an ident.

Test included.
2024-08-05 11:11:15 -04:00
Matthias Clasen
842949fcf3 nodeparser: Support color states
And allow using color states for colors with a syntax similar
to modern css color syntax.

color(srgb 50% 0.5 1 / 75%)

Both floating point numbers and percentages can be used.

Currently, this is only supported for color nodes.

Test included.
2024-08-05 11:11:15 -04:00
Matthias Clasen
3d3e935c91 offload: Use gsk_color_node_get_color2
We want the blackest black.
2024-08-05 11:11:15 -04:00
Matthias Clasen
87e9c940a4 gsk: Use the private color node api
Use the color state returned by this function instead of assuming
the color of a color node is always sRGB.

Node colors are converted to the css on the cpu. That is necessary
since we don't know if they are in one of the default color states,
and our shaders can't deal with non-default color states.
2024-08-05 11:11:14 -04:00
Matthias Clasen
6a02fa4be8 gsk: Add private color node api
Add a constructor that takes a color state, a getter for it, and
also a getter for the color coordinates that avoids GdkRGBA.
2024-08-05 11:11:14 -04:00
Matthias Clasen
9f548efd32 gsk: Change color op apis
Make color-related ops take the ccs and a GdkColor, and make
decisions about color conversion on the cpu vs the gpu.

This makes the node processor code simpler, and lets use convert
the color directly into the op instance without extra copying.

We also pass opacity to the op, so it can be applied when we
write the color into the instance.

Lastly, rorder the offset to come right after the opacity argument.

Treat the color and rounded color ops the same way.

Update all callers.

With this, the prepare_color apis in gskgpunodeprocessor.c are
no longer used and have been dropped.
2024-08-05 11:11:14 -04:00
Matthias Clasen
9eebe8e547 gsk: Change the clear op api
A clear op is just a fancy memcpy. Make it the callers responsibility
to convert the color to the right color state before passing it
to the clear op.
2024-08-05 11:11:14 -04:00
Benjamin Otte
126d689086 gpu: Rename function
We want to reuse gsk_gpu_color_to_float() for use with GdkColor and this
function will be replaced. But until that's fully done, we need 2
different names.

So rename this one to something else
2024-08-03 20:59:40 -04:00
Matthias Clasen
2be48a8f86 Pass ccs to the cairo blur code
This is needed to set the color properly.
2024-08-02 09:13:41 -04:00
Matthias Clasen
9e0f41bd05 Fix a copy-paste error
We were using the wrong api to get the color of an outset shadow
node. This just worked by luck.
2024-08-02 09:00:51 -04:00
Matthias Clasen
86b59ba643 Cosmetics: Remove a leftover line
This looks just like a copy-paste leftover. Suprisingly, it compiled
just fine and worked too.
2024-08-01 17:19:50 -04:00
Matthias Clasen
67080dab21 vulkan: Don't try srgb for the atlas
This makes the Emoji rendering come out wrong.

Fixes: #6887
2024-08-01 14:43:49 -04:00
Benjamin Otte
809b98c96e vulkan: Don't leak fds
It makes sense to close the fds before doing an early return.
D'oh.
2024-08-01 12:51:46 +02:00
Benjamin Otte
059af1365a vulkan: Add error checking in a place
Doesn't hurt to have, but I just added it while debugging something
unrelated.
2024-08-01 12:51:46 +02:00
Benjamin Otte
9f71528a05 gpu: Fix shadows even more
Math is hard.

But this time, it comes with a test!
2024-07-30 18:01:45 +02:00
Benjamin Otte
defc4d335e gpu: Fix shadows some more
It turns out the "step" variable could up as 0 when p.y ~= 3.0 ||
p.y ~= r.y - 3.0
That was not enough to trigger it though because if "start" and "end"
were the same value, the "y <= end" check in the loop would immediately
terminate it.

However, if start + epsilon == end so that end != start but (end - start)
/ 7 == 0, then step would end up as 0 and the loop would never
terminate.

And if that happened, it would bring down GPUs.
So recode this whole machinery to make it impossible to infloop.

Fixes #6896
2024-07-30 16:09:38 +02:00
Benjamin Otte
bdcfcfa5b9 Merge branch 'wip/otte/for-main' into 'main'
gpu: Draw proper shadows again

Closes #6888

See merge request GNOME/gtk!7518
2024-07-30 00:19:37 +00:00
Benjamin Otte
4a94c91772 gpu: Don't blur tiny blur radii
We get those wrong, and there's not really a visual effect.

And since we do a check anyway, just disallow them and treat them as
unblurred.
2024-07-30 01:50:56 +02:00
Benjamin Otte
cc3ed89e34 gpu: Draw proper shadows again
The fix in commit 5e7f227d broke shadows while trying to make them
faster.
So use a better way to make them faster.

With the normalized blur radius, we can now conclude that all the values
too far from p.y will cause the gauss() call to return close to 0, so we
can skip any y value that is too far from p.y.

And that allows us to put an upper limit on the loop iterations.

Tests included

Fixes #6888
2024-07-30 01:50:56 +02:00
Benjamin Otte
5059ae1d7b gpu: Simplify box-shadow shader
Instead of doing complicated math, normalize the values to a sigma
of 1.0, and then use that.
This should also be beneficial for shader performance, because 1.0 is a
constant and constant-elimination can kick in on the inlined functions.
2024-07-29 19:14:10 +02:00
Benjamin Otte
50bb42f0f3 gl: Don't crash on box shadows with negative scales
Some places didn't fabs() the scale values properly, leading to
assertions when offscreens with negative sizes were created.
2024-07-29 19:14:10 +02:00
Matthias Clasen
bfb779ac2f gsk: Add missing cicp transfer functions
This was overlooked in 50ea9450ea.
2024-07-29 10:35:32 -04:00
Simon McVittie
214f5a6f98 gskpathop: Introduce a type to represent an aligned graphene_point_t
When we allocate a graphene_point_t on the stack, there's no guarantee
that it will be aligned at an 8-byte boundary, which is an assumption
made by gsk_pathop_encode() (which wants to use the lowest 3 bits to
encode the operation). In the places where it matters, force the
points on the stack and embedded in structs to be nicely aligned.

By using a distinct type for this (a union with a suitable size and
alignment), we ensure that the compiler will warn or error whenever we
can't prove that a particular point is, in fact, suitably aligned.
We can go from a `GskAlignedPoint *` to a `graphene_point_t *`
(which is always valid, because the `GskAlignedPoint` is aligned)
via &aligned_points[0].pt, but we cannot go back the other way
(which is not always valid, because the `graphene_point_t` is not
necessarily aligned nicely) without a cast.

In practice, it seems that a graphene_point_t on x86_64 *is* usually
placed at an 8-byte boundary, but this is not the case on 32-bit
architectures or on s390x.

In many cases we can avoid needing an explicit reference to the more
complicated type by making use of a transparent union. There's already
at least one transparent union in GSK's public API, so it's presumably
portable enough to match GTK's requirements.

Increasing the alignment of GskAlignedPoint also requires adjusting how
a GskStandardContour is allocated and initialized. This data structure
allocates extra memory to hold an array of GskAlignedPoint outside the
bounds of the struct itself, and that array now needs to be aligned
suitably. Previously the array started with at next byte after the
flexible array of gskpathop, but the alignment of a gskpathop is only
4 bytes on 32-bit architectures, so depending on the number of gskpathop
in the trailing flexible array, that pointer might be an unsuitable
location to allocate a GskAlignedPoint.

Resolves: https://gitlab.gnome.org/GNOME/gtk/-/issues/6395
Signed-off-by: Simon McVittie <smcv@debian.org>
2024-07-28 17:31:41 +01:00
Simon McVittie
660c6c8d6f gsk, testsuite: Avoid undefined behaviour in half_to_float_one()
Similar to the previous commit, to avoid undefined behaviour we need
to avoid evaluating out-of-bounds shifts, even if their result is going
to ignored by being multiplied by 0 later.

Detected by running a subset of the test suite with
-Dsanitize=address,undefined on x86_64.

Signed-off-by: Simon McVittie <smcv@debian.org>
2024-07-27 20:22:09 +01:00
Simon McVittie
ad679187d3 gsk, testsuite: Avoid undefined behaviour in float_to_half_one()
If, for example, e == 0, it is undefined behaviour to compute an
expression involving an out-of-range shift by (125 - e), even if the
result is in fact irrelevant because it's going to be multiplied by 0.

This was already fixed for the memorytexture test in
commit 5d1b839 "testsuite: Fix another ubsan warning", so use the
implementation from that test everywhere. It's in the header as an
inline function to keep the linking of the relevant tests simple:
its only caller in production code is fp16.c, so there will be no
duplication outside the test suite.

Detected by running a subset of the test suite with
-Dsanitize=address,undefined on x86_64.

Signed-off-by: Simon McVittie <smcv@debian.org>
2024-07-27 20:22:09 +01:00
Matthias Clasen
e2d337740f gpu: Don't mess up color states
When uploading textures, we were unintentionally converting to
srgb. Avoid that, so that yuv data survives unmolested.
2024-07-26 17:34:48 -04:00
Matthias Clasen
150f57f706 gpu: Fix the cicp conversion
The fragment shader was mixing up pixel and color variables.
And the compilers don't have 'uninitialized variable' warnings :(
2024-07-26 07:24:48 -04:00
Matthias Clasen
33131ad24d gpu: Fix the cicp conversion shader for ngl
The compiler was unhappy with using signed labels with an unsigned
variable in a switch. Talk about being picky.
2024-07-26 07:23:18 -04:00
Matthias Clasen
d53b3f9941 gpu: More debug spew
Print out the direction of the cicp conversion.
2024-07-26 07:22:45 -04:00
Benjamin Otte
6f9a70bd4e gpu: Add a version of a function
With the changes in !7473 we now use sampler2D arguments in functions.
However, when there's a function we call with a samplerExternalOES -
which means we need to overload it with that shader variant.
2024-07-25 18:53:55 +02:00
Benjamin Otte
de1dfb99bc gpu: Add shader name to error message
When a shader cant be compiled, we produce a long error dump, but
nowhere did we mention the actual shader.

Fix that.
2024-07-25 18:53:55 +02:00
Benjamin Otte
1f3c88b995 build: Skip vulkan parts in generated GLSL
Make the #include parsing script able to skip a predefined list of terms
with #ifdef

Put "VULKAN" in that list to skip the vulkan parts.
2024-07-25 17:32:19 +02:00
Benjamin Otte
5e7f227d92 gpu: Don't run long loops in shaders
If the border radius is too big, take bigger steps when computing the
shadow.

I randomly chose 8 because that looked good and was fast enough.
2024-07-25 17:32:19 +02:00
Matthias Clasen
d8775d0194 gsk: Make shader matrices match
We were using slightly different numbers here, which isn't good.

The matrices in gdkcolordefs.h are tested in the colorstate-internal
tests, so they are at least properly inverse, and the products match.

It would be better to generate the glsl definitions, somehow.
2024-07-24 16:45:21 -06:00
Matthias Clasen
e415ec9ca5 gsk: Use the cicp convert shader
When we the image color state is not a default one, use the cicp
convert op to convert it to the ccs. And when the target color
state is a non-default one, use the shader in the reverse direction.
2024-07-24 08:16:08 -06:00
Matthias Clasen
226652edb0 gsk: Add a cicp convert shader
This shader receives cicp parameters via uniforms, and converts
the texture data from or to the output colorstate. It computes
the matrix in the vertex shader, and then picks the eotf/oetf
according to the cicp parameters in the fragment shader.
2024-07-24 08:16:08 -06:00
Benjamin Otte
293d2fd19f gpu: Use correct shader clip mode for glyph nodes
We were passing the wrong rect to the clip mode computation, resulting
in a rounded rect every time, even though it should pretty much always
be unclipped.

The visual results are unaffected, because the clip sent to the shader
was still correct.
2024-07-23 10:03:11 +02:00
Benjamin Otte
40e25218e2 gpu: Compile with AMD's compiler, too
Apparently AMD's GLSL compiler doesn't like our #if statements. Turn
them into simple #ifdefs and compute them in the preamble instead.
2024-07-22 19:40:24 +02:00
Benjamin Otte
9e27acb0a6 gpu: Allocate Vulkan descriptor pools dynamically
Instead of allocating one large descriptor pool and hoping we never run
out of descriptors, allocate small ones dynamically, so we know we never
run out.

Test incldued, though the test doesn't fail in CI, because llvmpipe
doesn't care about pool size limits. It does fail on my AMD though.

A fun side note about that test is that the GL renderer handles it best
in normal operationbecause it caches offscreens per node and we draw the
same node repeatedly.
But, the replay test expands them to duplicated unique nodes, and then
the GL renderer runs out of command queue length, so I had to disable
the test on it.
2024-07-22 19:40:24 +02:00
Benjamin Otte
67b9fb43d0 gpu: Completely revamp YCbCr handling
There is now a GskGpuYcbcr struct that maintains all the Vulkan
machinery related to YCbCrConversions.
It's a GskGpuCached, so it will make itself go away when it is no longer
used, ie a video stopped playing.
2024-07-22 19:40:24 +02:00