Compare commits

..

122 Commits

Author SHA1 Message Date
Matthias Clasen d4e536ebc6 image-tool: build with AVIF_DEBUG for now
This makes it easier to find out whats going on while the avif
loader is still frequently touched.
2024-08-10 10:09:56 -04:00
Matthias Clasen 00aec81d79 image tool: Load and save avif using the loader
We don't want to use the gdk-pixbuf loader, since it doesn not
produce dmabufs, and has no idea about color states and >8bit
formats.

With this commit, the image tool will support avif in both
the relabel and the convert commands (provided we are building
with avif support).
2024-08-10 10:09:56 -04:00
Matthias Clasen d536d4ab78 image tool: Better color state support
Show custom color states with their cicp tuple, and recognize
the name "jpeg".
2024-08-10 10:09:56 -04:00
Matthias Clasen 6d5664c4e3 Add yuv roundtrip tests
These load avif images in various formats to produce dmabuf or memory
textures, then download the data to compare it with the original png.

For now, the images are single-color, to avoid extra noise due to
reconstruction from subsampled formats.
2024-08-10 10:09:56 -04:00
Matthias Clasen 8343ba9ce3 Support avif in the render node parser
When saving, use avif if it is available and the texture is yuv.

When loading, look at the mimetype to decide whether to use the
avif loader.
2024-08-10 09:16:57 -04:00
Matthias Clasen c68a189005 Add an avif loder
Add a loader for avif images. It uses libavif and produces dmabufs
when /dev/udmabuf is available. Otherwise it produces YUVA memory
textures.

For saving, currently only YUV444 is supported. It would be nice
to just save dmabufs as-is, but that requires more work.

This is meant to facilitate testing of our yuv support, and
therefore, it is not exposed via the public texture loading and
saving apis. It is disabled by default and should *not* be enabled
in distro builds.

avif: Make it build outside of libgtk

We want to use this code in the image tool, and we don't want to
link it statically.

avif loader fixes
2024-08-10 09:16:57 -04:00
Matthias Clasen 567de6317d gpu: When importing dmabufs, adjust colorstate
We need to account for the yuv->rgb conversion that may happen
during import. Use the new color state adjustment helper for this.
2024-08-10 09:16:57 -04:00
Matthias Clasen 502a7f201b gpu: Add a helper to adjust color states
Add a function that takes an image and a colorstate, and adjusts
the colorstate according to the image flags. This is meant to handle
cases where the upload changes the effective color state of the data,
such as GL_SRGB or importing yuv as external texture.

Note: this function returns a reference.
2024-08-10 09:16:57 -04:00
Matthias Clasen 0d33aafe9a gsk: Add image flags for yuv
We want to separate the yuv->rgb conversion from the texture
upload, and if we do so we need to keep a record of whether it
happened or not.

Also add a mask that collects all the yuv-related flags for
convenient checking.
2024-08-10 09:16:57 -04:00
Matthias Clasen 50e7f02fc4 egl: Use correct yuv details for importing
Make the dmabuf import api take color space and range hints as
ints, and update all callers to pass them.

The callers use the new dmabuf egl yuv hints helper api to get
this information from the dmabuf + colorstate. Note that the old
gl renderer is not handling color states carefully and may not
get dmabuf import right wrt to color states.
2024-08-10 09:16:57 -04:00
Matthias Clasen 83ba577fa8 Add a helper for egl yuv hints 2024-08-10 09:16:57 -04:00
Matthias Clasen c53f791cb3 gst: Set matrix coefficients
This is needed to use our color conversion machinery successfully.

We need some heuristics to determine what coefficients and range
to use when gstreamer gives us an 'unspecified' value. For that,
we look at the fourcc.
2024-08-10 09:16:57 -04:00
Matthias Clasen 3445d2c12a jpeg: Save YCrCb data without conversion
If the texture we are saving is in the right colorstate, just use
the data without converting it to srgb first, only for libjpeg to
convert it back.
2024-08-10 09:16:57 -04:00
Matthias Clasen 22c119094c jpeg: Load YCbCr data without conversion
We can represent this data with a colorstate now, and feed it into
our color conversion machinery, instead of relying on libjpeg to
do the yuv->rgb conversion.
2024-08-10 09:16:57 -04:00
Matthias Clasen 839095d968 dmabuf: Fix P010 download
P010 has zeros in the 6 low bits. So what we want to do here is
to shift the top bits down and add them. This is necessary to
make the 'white' value in P010 (which is 1111111111000000) match
the highest value of 0xffff.
2024-08-10 09:16:52 -04:00
Matthias Clasen 1455933d61 dmabuf: Drop handrolled yuv conversions
Make the download function just unpack the dmabuf format, and
leave the color state conversion to the conversion call that
we do afterwards. This relies on dmabuf textures having the
correct color state set.
2024-08-10 09:11:06 -04:00
Matthias Clasen 406f563559 dmabuf: Set a proper color state for yuv
When we have to guess the color state because none was explicitly
set, take yuv-ness of the dmabuf fourcc into account.
2024-08-10 09:11:06 -04:00
Matthias Clasen 1a188e1171 colorstate: Add yuv support
Add support for some of the yuv-related cicp tuples.

Concretely, this adds bt601, bt709 and bt2020, both in their
narrow and full-range variants.
2024-08-10 09:11:05 -04:00
Matthias Clasen c7780d7528 gsk: Make gsk_gpu_cache_lookup_tile return a ref
Make this function return a reference to the cached color state.
This will integrate better in the caller where we may have to
create a new color state, and thus need a reference. And since
the function returns a reference to the image as well, it seems
more consistent to return a reference to the color state too.
2024-08-10 08:57:41 -04:00
Matthias Clasen 05e7b00453 gsk: Change refcounting of color states
gsk_gpu_lookup_texture may need to return a newly constructed
color state in the future, so make it return a reference, and
update all callers.
2024-08-10 08:57:41 -04:00
Matthias Clasen bec71a15b4 Merge branch 'matthiasc/for-main' into 'main'
Fix a copy-paste error

See merge request GNOME/gtk!7589
2024-08-10 12:55:32 +00:00
Matthias Clasen 25f0c81530 Fix a copy-paste error
This was introduced in ea28dc8cff.
2024-08-10 07:11:56 -04:00
Matthias Clasen 4f95d126ba Merge branch 'matthiasc/for-main' into 'main'
gl: Handle box shadow colors with color states

See merge request GNOME/gtk!7588
2024-08-10 03:05:26 +00: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
Matthias Clasen 8052bcc69c Updates 2024-08-09 22:11:35 -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
Benjamin Otte 4426194ee6 Merge branch 'css-color-hookup-4' into 'main'
Make non-srgb css colors work for shadows

See merge request GNOME/gtk!7557
2024-08-10 00:36:28 +00:00
Matthias Clasen 92c119e12c testsuite: Replay shadow nodes properly
Use the new apis for this.
2024-08-09 20:17:04 -04:00
Matthias Clasen ff02665407 inspector: Show more shadow node details
Show the color state, and create textures with the full color
information.

With this commit, add_color_row and get_color_texture are no longer
used and have been dropped.
2024-08-09 20:17:04 -04:00
Matthias Clasen d471ed5912 gtk: Use new shadow snapshot apis
Preserve color states from css as much as possible.
2024-08-09 20:17:04 -04:00
Matthias Clasen b92ca5da02 gtk: Add gtk_snapshot_push_shadow2
This is a private snapshot function that uses the new constructor
to create a shadow node with the given color states.
2024-08-09 20:17:04 -04: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 839d797292 build: Don't set G_SLICE=always-malloc
That environment variable has been gone since GSlice went away in glib
2.76. Which is our minimum requirement.
2024-08-10 01:53:46 +02:00
Benjamin Otte f8a30ddfc1 gdk: Deprecate gdk_surface_set_opaque_region() 2024-08-10 01:40:46 +02:00
Benjamin Otte bb0eb3af45 gtk: Stop calling gdk_window_set_opaque_region()
Now that GDK can figure it out from the rendernode, doing all this work
trying to figure it out is no longer necessary.

Plus, it was sometimes wrong and lead to obscure artifacts.
2024-08-10 01:40:46 +02:00
Benjamin Otte 999d9bc73b gdk: Introduce gdk_surface_is_opaque()
... and use it in the mac backend instead of a hand-rolled version.
2024-08-10 01:40:46 +02: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 f64045c229 gdk: Pass the opaque rect on to the opaque region
The opaque rect from the rendernodes are now used to set the opaque
region in the backend.

This means applications can now set a transparent window background and
make indivual parts of their window opaque.
But because this is a best effort method, it is not guaranteed to
succeed in finding all opaque regions, in particular if the rendernodes
used to build it are not straightforward to analyze.
2024-08-10 01:40:46 +02:00
Benjamin Otte 58aebc4447 surface: Put opaque_region in the priv structure
This is in preparation for future patches.
2024-08-10 01:40:46 +02:00
Benjamin Otte 3b3b6036f8 mac: Remove clear optimization
1. We want to get rid of exposing the opaque region

2. Cairo optimizes clearing the whole surface
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 f90fb68aec gdk: Deprecate public begin/end_frame() APIs
We are using so many internal extra features that it is no longer a good
idea to use these functions.
And they aren't really used anyway.

These extra features are also constantly in flux and rely on internal
APIs, so exposing them would just cause extra pain.
2024-08-10 01:40:45 +02:00
Benjamin Otte 4fa3943e51 gdk: "inline" gdk_draw_context_get_frame_region()
By using the inlining macro trick, we can work around deprecation
warnings from removing this function as a public API, which will happen
in the next commits.
2024-08-10 01:40:45 +02:00
Benjamin Otte 0a92f741b3 vulkan: Remove 2 unneeded return_if_fail() checks
I want to deprecate that function, so getting rid of calls to it sounds
like a good idea.
2024-08-10 01:40:45 +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 b6c848d711 x11: Remove special casing from get_damage() call
This function is only ever called while inside a frame, so the check is
not necessary.
2024-08-10 01:40:45 +02:00
Benjamin Otte a467cfd060 inspector: Use a higher priority than USER
We want to override user settings, so make sure we do that.
2024-08-10 01:40:45 +02:00
Benjamin Otte f24be8476e wayland: Clean up after ourselves in the xx-color code
If an image description query is running while the surface gets
destroyed, we were not properly cleaning up, causing the callbacks to be
emitted on freed variables.
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 f846315a6a Merge branch 'matthiasc/for-main' into 'main'
docs: More details for the node format

See merge request GNOME/gtk!7586
2024-08-09 16:46:30 +00:00
Matthias Clasen 5329b7d211 docs: More details for the node format
Add some more details.
2024-08-09 12:16:06 -04:00
Matthias Clasen ac18a665d5 node-format.md: formatting tweaks 2024-08-09 11:54:12 -04:00
Matthias Clasen c492e71aed Merge branch 'css-color-hookup-3' into 'main'
Make non-srgb css colors work for box shadows

See merge request GNOME/gtk!7552
2024-08-08 22:52:12 +00:00
Matthias Clasen 4ea1319c6b Replay inset and outset shadow nodes properly 2024-08-08 16:01:06 -04:00
Matthias Clasen 2aac3c2cc9 inspector: Show more details for box shadow nodes
Show the color state, and create textures with the full color
information.
2024-08-08 16:01:06 -04:00
Matthias Clasen 55d18bdc06 gtk: Use new box shadow snapshot apis
Preserve color states from css as much as possible.
2024-08-08 16:01:06 -04:00
Matthias Clasen abefa0ab00 gtk: Add gtk_snapshot_append_{in,out}set_shadow2
These are private snapshot functions that use the new constructors
to create a box shadow nodes with a given color state.
2024-08-08 16:01:06 -04: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 d86407f263 Merge branch 'wip/otte/optional-dependencies' into 'main'
gstreamer: Always build dmabuf support

See merge request GNOME/gtk!7201
2024-08-08 19:29:13 +00:00
Benjamin Otte a24a7db72b build: bump GStreamer dep to 1.24.0
Depend on a release version, not a prerelease.
2024-08-08 19:03:31 +00:00
Benjamin Otte 2096a29b06 build: Remove an old workaround
The workaround only triggered in GStreamer < 1.19.1 but we require 1.23
now.
2024-08-08 19:03:31 +00:00
Benjamin Otte ce352b5538 build: Move GStreamer dependency checks
Put them where all the other checks go so that it's easy for people
reading build files to see what GTK depends on.

Also reindent properly.
2024-08-08 19:03:31 +00:00
Benjamin Otte 4bcd2c75cc gstreamer: Require the same version for all GStreamer deps
We don't want people to have different GStramer library versions.

GStreamer now is developed in a monorepo, so the versions are in sync.
2024-08-08 19:03:31 +00:00
Benjamin Otte 3c3bf0192d gstreamer: Always build dmabuf support
I just spent an hour trying to figure out why things don't work. And it
was an optional dependency hidden 3 layers deep in some meson file.

This really has to stop.

And because just like in GTK, GStreamer's dmabuf APIs are always
available (they will just fail on Windows etc), there's no need to have
any conditions.

The only difference is that the GStreamer media backend now requires
GStreamer 1.24.
2024-08-08 19:03:31 +00:00
Benjamin Otte cf84d999d8 dmabuf: Add DRM_FORMAT_MOD_INVALID to our formats
That's gonna be necessary for the next commits.
2024-08-08 19:03:31 +00:00
Matthias Clasen 668628941e Merge branch 'ci-update-f40' into 'main'
ci: Update to Fedora 40

See merge request GNOME/gtk!7583
2024-08-08 19:02:22 +00: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
Matthias Clasen 7814d1fd75 ci: Fix a Vulkan problem in the F40 image
Drop the powervr Vulkan driver, which otherwise interferes with
proper functioning of our ci.
2024-08-08 14:19:25 -04:00
Matthias Clasen b57c3008a3 ci: Update to Fedora 40
Crucially, this gives us gstreamer 1.24.
2024-08-08 12:57:33 -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 8e35398371 Merge branch 'wip/otte/for-main' into 'main'
vulkan: Turn debug messages into warnings

See merge request GNOME/gtk!7579
2024-08-08 04:25:35 +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
Benjamin Otte 97b51dc070 inspector: Print opaque rect of nodes
Also change the way rectangles are printed by including the bottom right
coordinate, too.

I'm still not sure what the best way is, but at least I no longer get
confused and it has the infos I want.
2024-08-07 23:26:03 +02:00
Benjamin Otte 88c9a30f77 testsuite: Half the runtime of offscreens test
It times out too much in CI.
2024-08-07 23:26:03 +02:00
Benjamin Otte 5c071cb02e dmabuf: Fix a check
We were comparing with destination stride, not with source stride, and
in rare cases when those were different, this would trigger aborts in
the testsuite.
2024-08-07 19:06:02 +02:00
Matthias Clasen 2960bb7cb2 Add a compare test for colorstates in borders 2024-08-06 07:35:00 -04:00
Matthias Clasen 161c0f0963 inspector: Show more detail for border nodes
Show the color state, and create textures with the full color
information.
2024-08-06 07:35:00 -04:00
Matthias Clasen 3002591d08 gtk: Use new border snapshot api
Preserve color states from css as much as possible.
2024-08-06 07:35:00 -04:00
Matthias Clasen 1b2b9726f8 gtk: Add gtk_snapshot_append_border2
This is a private snapshot function that uses the new constructor
to create a border node with the given GdkColors.
2024-08-06 07:35:00 -04:00
Matthias Clasen a3691d311b nodeparser: Support color states in border nodes
Test included.
2024-08-06 07:35:00 -04:00
Matthias Clasen 89d449352f testsuite: Replay border nodes properly
Use the new apis for this.
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
166 changed files with 4539 additions and 2094 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ variables:
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled -Dbuild-testsuite=true -Dintrospection=enabled"
MESON_TEST_TIMEOUT_MULTIPLIER: 3
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v49"
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v52"
workflow:
rules:
+4 -1
View File
@@ -1,4 +1,4 @@
FROM fedora:39
FROM fedora:40
RUN dnf -y install \
adwaita-icon-theme \
@@ -99,8 +99,11 @@ RUN dnf -y install \
which \
wireplumber \
xorg-x11-server-Xvfb \
&& dnf -y update \
&& dnf clean all
RUN rm /usr/share/vulkan/icd.d/powervr_mesa_icd.x86_64.json
# Enable sudo for wheel users
RUN sed -i -e 's/# %wheel/%wheel/' -e '0,/%wheel/{s/%wheel/# %wheel/}' /etc/sudoers
-1
View File
@@ -11,7 +11,6 @@ multiplier=${MESON_TEST_TIMEOUT_MULTIPLIER:-1}
# Ignore memory leaks lower in dependencies
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:detect_leaks=0:allocator_may_return_null=1
export G_SLICE=always-malloc
case "${setup}" in
x11*)
+31
View File
@@ -1,6 +1,37 @@
Overview of Changes in 4.15.5, xx-xx-xxxx
=========================================
* GtkTextView:
- ADd GtkTextBufferCommitNotify
* CSS:
- Propagate color state information to GSK for many features:
colors, borders, shadows
* Gdk:
- Fix an fd leak in the Vulkan code
- Fix a leak of EGLSurfaces and DMA buffers
- Set the opaque region of surfaces automatically based on their content
* Gsk:
- Fix Emoji rendering in Vulkan
- Rework color handling to take color states into account
- Implement more powerful occlusion culling
* Macos:
- Fix window transparency
* Debugging:
- The inspector shows details about color states now
* Deprecations:
- gdk_draw_context_begin/end_frame
- gdk_surface_set_opaque_region
* Build:
- Require gstreamer 1.24
Overview of Changes in 4.15.4, 30-07-2024
=========================================
+7
View File
@@ -265,6 +265,13 @@ support in the file chooser.
This option controls whether GTK should use colord for color
calibration support in the cups print backend.
## `avif`
This option controls whether GTK will use libavif for loading
textures from AVIF image files. Note that the purpose of this option
is to facilitate development of GTK. The support for this image format
is not guaranteed and may go away at any time.
### `documentation`, `man-pages` and `screenshots`
The *gi-docgen* package is used to generate the reference documentation
+61 -15
View File
@@ -6,7 +6,7 @@ The format is a text format that follows the [CSS syntax rules](https://drafts.c
The grammar of a node text representation using [the CSS value definition syntax](https://drafts.csswg.org/css-values-3/#value-defs) looks like this:
document: <@-rule>*<node>*
document: <@-rule>*<node>
@-rule: @cicp "name" { <property>* }
node: container [ "name" ] { <document> } | <node-type> [ "name" ] { <property>* } | "name"
property: <property-name>: <node> | <value> ;
@@ -49,12 +49,16 @@ The following properties can be set for custom color states:
| primaries | `<integer>` | 2 | always |
| transfer | `<integer>` | 2 | always |
| matrix | `<integer>` | 2 | always |
| range | `narrow | full` | full | non-default |
| range | `<range>` | full | non-default |
Note that the primaries, transfer and matrix properties always need
to be specified, since GTK does not allow creating color state objects
with these being set to 2 (== unspecified).
Range can have the following values:
range: narrow | full
# Colors
Colors can be specified with a variation of the modern CSS color syntax:
@@ -66,6 +70,16 @@ The traditional syntax for sRGB colors still works as well:
rgba(<number>, <number>, <number>, <number)
rgb(<number, <number>, <number>)
# Rectangles
Rectangles can be specified just as four integers for x, y, width and height:
rect: <number> <number> <number> <number>
Rounded rectangles use a CSS-like syntax:
rounded-rect: <rect> [ "/" <number>{1,4} [ "/" <number>{1,4} ] ]
# Nodes
### container
@@ -82,6 +96,13 @@ The **container** node is a special node that allows specifying a list of child
Creates a node like `gsk_blend_node_new()` with the given properties.
Possible values for the mode property are:
blend-mode: normal | multiply | screen | overlay | darken |
lighten | color-dodge | color-burn | hard-light |
soft-light | difference | exclusion | color |
hue | saturation | luminosity
### blur
| property | syntax | default | printed |
@@ -201,6 +222,10 @@ Creates a node like `gsk_fill_node_new()` with the given properties.
The default child node is the default color node, but created with the
bounds of the path.
Possible values for the fill-rule property are:
fill-rule: winding | even-odd
### glshader
| property | syntax | default | printed |
@@ -252,6 +277,10 @@ Creates a node like `gsk_linear_gradient_node_new()` with the given properties.
Creates a node like `gsk_mask_node_new()` with the given properties.
Possible values for the mode property are:
mask-mode: alpha | inverted-alpha | luminance | inverted-luminance
### opacity
| property | syntax | default | printed |
@@ -290,11 +319,11 @@ Creates a node like `gsk_radial_gradient_node_new()` with the given properties.
### repeat
| property | syntax | default | printed |
| ----------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | *bounds of child node* | non-default |
| child | `<node>` | color { } | always |
| child-bounds| `<rect>` | *bounds of child node* | non-default |
| property | syntax | default | printed |
| ------------ | ---------- | ---------------------- | ----------- |
| bounds | `<rect>` | *bounds of child node* | non-default |
| child | `<node>` | color { } | always |
| child-bounds | `<rect>` | *bounds of child node* | non-default |
Creates a node like `gsk_repeat_node_new()` with the given properties.
@@ -361,6 +390,14 @@ Creates a node like `gsk_stroke_node_new()` with the given properties.
The default child node is the default color node, but created with the
stroke bounds of the path.
Possible values for the line-cap property are:
line-cap: butt | round | square
Possible values for the line-join property are:
line-join: miter | round | bevel
### text
| property | syntax | default | printed |
@@ -369,9 +406,9 @@ stroke bounds of the path.
| font | `<string>` `<url>`? | "Cantarell 15px" | always |
| glyphs | `<glyphs>` | "Hello" | always |
| offset | `<point>` | 0 0 | non-default |
| hint-style | `<hint style>` | slight | non-default |
| hint-style | `<hint-style>` | slight | non-default |
| antialias | `<antialias>` | gray | non-default |
| hint-metrics | `<hint metrics>` | off | non-default |
| hint-metrics | `<hint-metrics>` | off | non-default |
Creates a node like `gsk_text_node_new()` with the given properties.
@@ -386,9 +423,17 @@ 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.
Possible values for hint-style are none, slight or full.
Possible value for antialias are none or gray.
Possible value for hint-metrics are on or off.
Possible values for the hint-style property are:
hint-style: none | slight | full
Possible value for the antialias property are:
antialias: none | gray
Possible value for hint-metrics are:
hint-metrics: on | off
### texture
@@ -414,14 +459,15 @@ representation for this texture is `url("data:image/png;base64,iVBORw0KGgoAAAANS
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| texture | `<url>` | *see below* | always |
| filter | `filter` | *see below* | non-default |
| filter | `filter` | linear | non-default |
Creates a node like `gsk_texture_scale_node_new()` with the given properties.
The default texture is a 10x10 checkerboard, just like for texture.
The possible filter values are `linear`, `nearest` and `trilinear`, with
`linear` being the default.
Possible values for the filter property are:
filter: linear | nearest | trilinear
### transform
+2
View File
@@ -82,8 +82,10 @@ gdk_cairo_context_cairo_create (GdkCairoContext *self)
draw_context = GDK_DRAW_CONTEXT (self);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
if (!gdk_draw_context_is_in_frame (draw_context))
return NULL;
G_GNUC_END_IGNORE_DEPRECATIONS
cr = GDK_CAIRO_CONTEXT_GET_CLASS (self)->cairo_create (self);
+3
View File
@@ -208,7 +208,10 @@ gdk_cicp_params_class_init (GdkCicpParamsClass *klass)
* Supported values:
*
* - 0: RGB
* - 1: BT.709
* - 2: unspecified
* - 5,6: BT.601
* - 9: BT.2020
*
* Since: 4.16
*/
+36
View File
@@ -222,3 +222,39 @@ static const float srgb_to_rec2020[9] = {
0.069108, 0.919519, 0.011360,
0.016394, 0.088011, 0.895380,
};
static const float rgb_to_bt601[9] = {
0.299000, 0.587000, 0.114000,
-0.168736, -0.331264, 0.500000,
0.500000, -0.418688, -0.081312,
};
static const float bt601_to_rgb[9] = {
1.000000, 0.000000, 1.402000,
1.000000, -0.344136, -0.714136,
1.000000, 1.772000, 0.000000,
};
static const float rgb_to_bt709[9] = {
0.212600, 0.715200, 0.072200,
-0.114572, -0.385428, 0.500000,
0.500000, -0.454153, -0.045847,
};
static const float bt709_to_rgb[9] = {
1.000000, 0.000000, 1.574800,
1.000000, -0.187324, -0.468124,
1.000000, 1.855600, -0.000000,
};
static const float rgb_to_bt2020[9] = {
0.262700, 0.678000, 0.059300,
-0.139630, -0.360370, 0.500000,
0.500000, -0.459786, -0.040214,
};
static const float bt2020_to_rgb[9] = {
1.000000, -0.000000, 1.474600,
1.000000, -0.164553, -0.571353,
1.000000, 1.881400, -0.000000,
};
+198 -22
View File
@@ -18,6 +18,7 @@
#include "config.h"
#define GDK_COLOR_STATE_IMPL
#include "gdkcolorstateprivate.h"
#include <math.h>
@@ -411,7 +412,7 @@ GdkDefaultColorState gdk_default_color_states[] = {
},
};
/* }}} */
/* }}} */
/* {{{ Cicp implementation */
typedef struct _GdkCicpColorState GdkCicpColorState;
@@ -431,25 +432,128 @@ struct _GdkCicpColorState
float *from_srgb;
float *from_rec2020;
const float *from_yuv;
const float *to_yuv;
GdkCicp cicp;
};
/* {{{ Conversion functions */
#define cicp ((GdkCicpColorState *)self)
#define TRANSFORM_FROM_CICP(name, matrix, oetf) \
static void \
name (GdkColorState *color_state, \
float (*values)[4], \
gsize n_values) \
{ \
GdkCicpColorState *self = (GdkCicpColorState *) color_state; \
\
for (gsize i = 0; i < n_values; i++) \
{ \
if (self->cicp.range == GDK_CICP_RANGE_NARROW) \
{ \
values[i][0] = CLAMP ((values[i][0] - 16.0/255.0) * 255.0 / 219.0, -10, 10); \
values[i][1] = CLAMP ((values[i][1] - 16.0/255.0) * 255.0 / 224.0, -10, 10); \
values[i][2] = CLAMP ((values[i][2] - 16.0/255.0) * 255.0 / 224.0, -10, 10); \
} \
if (self->from_yuv) \
{ \
float res[3]; \
values[i][1] -= 0.5; \
values[i][2] -= 0.5; \
res[0] = self->from_yuv[0] * values[i][0] + self->from_yuv[1] * values[i][1] + self->from_yuv[2] * values[i][2]; \
res[1] = self->from_yuv[3] * values[i][0] + self->from_yuv[4] * values[i][1] + self->from_yuv[5] * values[i][2]; \
res[2] = self->from_yuv[6] * values[i][0] + self->from_yuv[7] * values[i][1] + self->from_yuv[8] * values[i][2]; \
values[i][0] = res[0]; \
values[i][1] = res[1]; \
values[i][2] = res[2]; \
} \
if (self->eotf != NONE) \
{ \
values[i][0] = self->eotf (values[i][0]); \
values[i][1] = self->eotf (values[i][1]); \
values[i][2] = self->eotf (values[i][2]); \
} \
if (self->matrix != IDENTITY) \
{ \
float res[3]; \
res[0] = self->matrix[0] * values[i][0] + self->matrix[1] * values[i][1] + self->matrix[2] * values[i][2]; \
res[1] = self->matrix[3] * values[i][0] + self->matrix[4] * values[i][1] + self->matrix[5] * values[i][2]; \
res[2] = self->matrix[6] * values[i][0] + self->matrix[7] * values[i][1] + self->matrix[8] * values[i][2]; \
values[i][0] = res[0]; \
values[i][1] = res[1]; \
values[i][2] = res[2]; \
} \
if (oetf != NONE) \
{ \
values[i][0] = oetf (values[i][0]); \
values[i][1] = oetf (values[i][1]); \
values[i][2] = oetf (values[i][2]); \
} \
} \
}
TRANSFORM(gdk_cicp_to_srgb, cicp->eotf, cicp->to_srgb, srgb_oetf)
TRANSFORM(gdk_cicp_to_srgb_linear, cicp->eotf, cicp->to_srgb, NONE)
TRANSFORM(gdk_cicp_to_rec2100_pq, cicp->eotf, cicp->to_rec2020, pq_oetf)
TRANSFORM(gdk_cicp_to_rec2100_linear, cicp->eotf, cicp->to_rec2020, NONE)
TRANSFORM(gdk_cicp_from_srgb, srgb_eotf, cicp->from_srgb, cicp->oetf)
TRANSFORM(gdk_cicp_from_srgb_linear, NONE, cicp->from_srgb, cicp->oetf)
TRANSFORM(gdk_cicp_from_rec2100_pq, pq_eotf, cicp->from_rec2020, cicp->oetf)
TRANSFORM(gdk_cicp_from_rec2100_linear, NONE, cicp->from_rec2020, cicp->oetf)
#define TRANSFORM_TO_CICP(name, eotf, matrix) \
static void \
name (GdkColorState *color_state, \
float (*values)[4], \
gsize n_values) \
{ \
GdkCicpColorState *self = (GdkCicpColorState *) color_state; \
\
for (gsize i = 0; i < n_values; i++) \
{ \
if (eotf != NONE) \
{ \
values[i][0] = eotf (values[i][0]); \
values[i][1] = eotf (values[i][1]); \
values[i][2] = eotf (values[i][2]); \
} \
if (self->matrix != IDENTITY) \
{ \
float res[3]; \
res[0] = self->matrix[0] * values[i][0] + self->matrix[1] * values[i][1] + self->matrix[2] * values[i][2]; \
res[1] = self->matrix[3] * values[i][0] + self->matrix[4] * values[i][1] + self->matrix[5] * values[i][2]; \
res[2] = self->matrix[6] * values[i][0] + self->matrix[7] * values[i][1] + self->matrix[8] * values[i][2]; \
values[i][0] = res[0]; \
values[i][1] = res[1]; \
values[i][2] = res[2]; \
} \
if (self->oetf != NONE) \
{ \
values[i][0] = self->oetf (values[i][0]); \
values[i][1] = self->oetf (values[i][1]); \
values[i][2] = self->oetf (values[i][2]); \
} \
if (self->to_yuv) \
{ \
float res[3]; \
res[0] = self->to_yuv[0] * values[i][0] + self->to_yuv[1] * values[i][1] + self->to_yuv[2] * values[i][2]; \
res[1] = self->to_yuv[3] * values[i][0] + self->to_yuv[4] * values[i][1] + self->to_yuv[5] * values[i][2]; \
res[2] = self->to_yuv[6] * values[i][0] + self->to_yuv[7] * values[i][1] + self->to_yuv[8] * values[i][2]; \
values[i][0] = res[0]; \
values[i][1] = res[1] + 0.5; \
values[i][2] = res[2] + 0.5; \
} \
if (self->cicp.range == GDK_CICP_RANGE_NARROW) \
{ \
values[i][0] = values[i][0] * 219.0 / 255.0 + 16.0 / 255.0; \
values[i][1] = values[i][1] * 224.0 / 255.0 + 16.0 / 255.0; \
values[i][2] = values[i][2] * 224.0 / 255.0 + 16.0 / 255.0; \
} \
} \
}
#undef cicp
TRANSFORM_FROM_CICP(gdk_cicp_to_srgb, to_srgb, srgb_oetf)
TRANSFORM_FROM_CICP(gdk_cicp_to_srgb_linear, to_srgb, NONE)
TRANSFORM_FROM_CICP(gdk_cicp_to_rec2100_pq, to_rec2020, pq_oetf)
TRANSFORM_FROM_CICP(gdk_cicp_to_rec2100_linear, to_rec2020, NONE)
TRANSFORM_TO_CICP(gdk_cicp_from_srgb, srgb_eotf, from_srgb)
TRANSFORM_TO_CICP(gdk_cicp_from_srgb_linear, NONE, from_srgb)
TRANSFORM_TO_CICP(gdk_cicp_from_rec2100_pq, pq_eotf, from_rec2020)
TRANSFORM_TO_CICP(gdk_cicp_from_rec2100_linear, NONE, from_rec2020)
/* }}} */
/* }}} */
/* {{{ Vfuncs */
@@ -555,7 +659,7 @@ gdk_cicp_color_state_get_cicp (GdkColorState *color_state)
return &self->cicp;
}
/* }}} */
/* }}} */
static const
GdkColorStateClass GDK_CICP_COLOR_STATE_CLASS = {
@@ -568,6 +672,46 @@ GdkColorStateClass GDK_CICP_COLOR_STATE_CLASS = {
.get_cicp = gdk_cicp_color_state_get_cicp,
};
GdkCicpColorState gdk_color_state_bt601_narrow = {
.parent = {
.klass = &GDK_CICP_COLOR_STATE_CLASS,
.ref_count = 1,
.depth = GDK_MEMORY_FLOAT16,
.rendering_color_state = GDK_COLOR_STATE_REC2100_LINEAR,
},
.name = "cicp-1/13/6/0",
.no_srgb = NULL,
.cicp = { 1, 13, 6, 0 },
.eotf = srgb_eotf,
.oetf = srgb_oetf,
.to_yuv = rgb_to_bt601,
.from_yuv = bt601_to_rgb,
.to_srgb = IDENTITY,
.to_rec2020 = (float *) srgb_to_rec2020,
.from_srgb = IDENTITY,
.from_rec2020 = (float *) rec2020_to_srgb,
};
GdkCicpColorState gdk_color_state_bt601_full = {
.parent = {
.klass = &GDK_CICP_COLOR_STATE_CLASS,
.ref_count = 1,
.depth = GDK_MEMORY_FLOAT16,
.rendering_color_state = GDK_COLOR_STATE_REC2100_LINEAR,
},
.name = "cicp-1/13/6/1",
.no_srgb = NULL,
.cicp = { 1, 13, 6, 1 },
.eotf = srgb_eotf,
.oetf = srgb_oetf,
.to_yuv = rgb_to_bt601,
.from_yuv = bt601_to_rgb,
.to_srgb = IDENTITY,
.to_rec2020 = (float *) srgb_to_rec2020,
.from_srgb = IDENTITY,
.from_rec2020 = (float *) rec2020_to_srgb,
};
static inline float *
multiply (float res[9],
const float m1[9],
@@ -592,14 +736,8 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
GdkTransferFunc oetf;
gconstpointer to_xyz;
gconstpointer from_xyz;
if (cicp->range == GDK_CICP_RANGE_NARROW || cicp->matrix_coefficients != 0)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
_("cicp: Narrow range or YUV not supported"));
return NULL;
}
gconstpointer to_yuv = NULL;
gconstpointer from_yuv = NULL;
if (cicp->color_primaries == 2 ||
cicp->transfer_function == 2 ||
@@ -613,10 +751,16 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
for (guint i = 0; i < GDK_COLOR_STATE_N_IDS; i++)
{
if (gdk_cicp_equivalent (cicp, &gdk_default_color_states[i].cicp))
if (gdk_cicp_equal (cicp, &gdk_default_color_states[i].cicp))
return (GdkColorState *) &gdk_default_color_states[i];
}
if (gdk_cicp_equal (cicp, &gdk_color_state_bt601_narrow.cicp))
return gdk_color_state_ref ((GdkColorState *) &gdk_color_state_bt601_narrow);
if (gdk_cicp_equal (cicp, &gdk_color_state_bt601_full.cicp))
return gdk_color_state_ref ((GdkColorState *) &gdk_color_state_bt601_full);
switch (cicp->transfer_function)
{
case 1:
@@ -669,6 +813,7 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
from_xyz = xyz_to_pal;
break;
case 6:
case 7:
to_xyz = ntsc_to_xyz;
from_xyz = xyz_to_ntsc;
break;
@@ -688,6 +833,34 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
return NULL;
}
switch (cicp->matrix_coefficients)
{
case 0:
to_yuv = IDENTITY;
from_yuv = IDENTITY;
break;
case 1:
to_yuv = rgb_to_bt709;
from_yuv = bt709_to_rgb;
break;
case 5:
case 6:
to_yuv = rgb_to_bt601;
from_yuv = bt601_to_rgb;
break;
case 9:
to_yuv = rgb_to_bt2020;
from_yuv = bt2020_to_rgb;
break;
default:
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
_("cicp: Matrix coefficients %u, %s not supported"),
cicp->matrix_coefficients,
cicp->range == GDK_CICP_RANGE_NARROW ? "narrow" : "full");
return NULL;
}
self = g_new0 (GdkCicpColorState, 1);
self->parent.klass = &GDK_CICP_COLOR_STATE_CLASS;
@@ -700,6 +873,9 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
memcpy (&self->cicp, cicp, sizeof (GdkCicp));
self->to_yuv = to_yuv;
self->from_yuv = from_yuv;
self->eotf = eotf;
self->oetf = oetf;
+8 -8
View File
@@ -78,15 +78,8 @@ GdkColorState * gdk_color_state_new_for_cicp (const GdkCicp
GError **error);
static inline GdkColorState *
gdk_color_state_get_rendering_color_state (GdkColorState *self,
gboolean srgb)
gdk_color_state_get_rendering_color_state (GdkColorState *self)
{
if (srgb)
{
self = gdk_color_state_get_no_srgb_tf (self);
g_assert (self);
}
if (GDK_DEBUG_CHECK (HDR))
self = GDK_COLOR_STATE_REC2100_PQ;
@@ -218,3 +211,10 @@ gdk_color_state_from_rgba (GdkColorState *self,
out_color);
}
#ifndef GDK_COLOR_STATE_IMPL
extern GdkColorState gdk_color_state_bt601_narrow;
extern GdkColorState gdk_color_state_bt601_full;
#endif
#define GDK_COLOR_STATE_YUV ((GdkColorState *) &gdk_color_state_bt601_narrow)
#define GDK_COLOR_STATE_JPEG ((GdkColorState *) &gdk_color_state_bt601_full)
+1 -1
View File
@@ -1477,7 +1477,7 @@ gdk_display_create_gl_context (GdkDisplay *self,
if (!gdk_display_prepare_gl (self, error))
return NULL;
return gdk_gl_context_new (self, NULL);
return gdk_gl_context_new (self, NULL, FALSE);
}
/*< private >
+57 -102
View File
@@ -24,6 +24,7 @@
#include "gdkdmabuffourccprivate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkcolorstate.h"
#ifdef HAVE_DMABUF
#include <sys/mman.h>
@@ -71,7 +72,7 @@ download_memcpy (guchar *dst_data,
bpp = gdk_memory_format_bytes_per_pixel (dst_format);
src_stride = dmabuf->planes[0].stride;
src_data = src_datas[0] + dmabuf->planes[0].offset;
g_return_if_fail (sizes[0] >= dmabuf->planes[0].offset + gdk_memory_format_min_buffer_size (dst_format, dst_stride, width, height));
g_return_if_fail (sizes[0] >= dmabuf->planes[0].offset + gdk_memory_format_min_buffer_size (dst_format, src_stride, width, height));
if (dst_stride == src_stride)
memcpy (dst_data, src_data, (height - 1) * dst_stride + width * bpp);
@@ -133,49 +134,6 @@ download_memcpy_3_1 (guchar *dst_data,
}
}
typedef struct _YUVCoefficients YUVCoefficients;
struct _YUVCoefficients
{
int v_to_r;
int u_to_g;
int v_to_g;
int u_to_b;
};
/* multiplied by 65536 */
static const YUVCoefficients itu601_narrow = { 104597, -25675, -53279, 132201 };
//static const YUVCoefficients itu601_wide = { 74711, -25864, -38050, 133176 };
static inline void
get_uv_values (const YUVCoefficients *coeffs,
guint8 u,
guint8 v,
int *out_r,
int *out_g,
int *out_b)
{
int u2 = (int) u - 127;
int v2 = (int) v - 127;
*out_r = coeffs->v_to_r * v2;
*out_g = coeffs->u_to_g * u2 + coeffs->v_to_g * v2;
*out_b = coeffs->u_to_b * u2;
}
static inline void
set_rgb_values (guint8 rgb[3],
guint8 y,
int r,
int g,
int b)
{
int y2 = y * 65536;
rgb[0] = CLAMP ((y2 + r) >> 16, 0, 255);
rgb[1] = CLAMP ((y2 + g) >> 16, 0, 255);
rgb[2] = CLAMP ((y2 + b) >> 16, 0, 255);
}
static void
download_nv12 (guchar *dst_data,
gsize dst_stride,
@@ -226,14 +184,21 @@ download_nv12 (guchar *dst_data,
{
for (x = 0; x < width; x += X_SUB)
{
int r, g, b;
int u_, v_;
gsize xs, ys;
get_uv_values (&itu601_narrow, uv_data[x / X_SUB * 2 + U], uv_data[x / X_SUB * 2 + V], &r, &g, &b);
u_ = uv_data[x / X_SUB * 2 + U];
v_ = uv_data[x / X_SUB * 2 + V];
for (ys = 0; ys < Y_SUB && y + ys < height; ys++)
for (xs = 0; xs < X_SUB && x + xs < width; xs++)
set_rgb_values (&dst_data[3 * (x + xs) + dst_stride * ys], y_data[x + xs + y_stride * ys], r, g, b);
{
guint8 *rgb = &dst_data[3 * (x + xs) + dst_stride * ys];
rgb[0] = y_data[x + xs + y_stride * ys];
rgb[1] = u_;
rgb[2] = v_;
}
}
dst_data += Y_SUB * dst_stride;
y_data += Y_SUB * y_stride;
@@ -241,35 +206,6 @@ download_nv12 (guchar *dst_data,
}
}
static inline void
get_uv_values16 (const YUVCoefficients *coeffs,
guint16 u,
guint16 v,
gint64 *out_r,
gint64 *out_g,
gint64 *out_b)
{
gint64 u2 = (gint64) u - 32767;
gint64 v2 = (gint64) v - 32767;
*out_r = coeffs->v_to_r * v2;
*out_g = coeffs->u_to_g * u2 + coeffs->v_to_g * v2;
*out_b = coeffs->u_to_b * u2;
}
static inline void
set_rgb_values16 (guint16 rgb[3],
guint16 y,
gint64 r,
gint64 g,
gint64 b)
{
gint64 y2 = (gint64) y * 65536;
rgb[0] = CLAMP ((y2 + r) >> 16, 0, 65535);
rgb[1] = CLAMP ((y2 + g) >> 16, 0, 65535);
rgb[2] = CLAMP ((y2 + b) >> 16, 0, 65535);
}
static void
download_p010 (guchar *dst,
gsize dst_stride,
@@ -284,7 +220,7 @@ download_p010 (guchar *dst,
guint16 *dst_data;
gsize x, y, y_stride, uv_stride;
gsize U, V, X_SUB, Y_SUB;
guint16 SIZE, MASK;
guint16 SIZE;
switch (dmabuf->fourcc)
{
@@ -304,7 +240,6 @@ download_p010 (guchar *dst,
g_assert_not_reached ();
return;
}
MASK = 0xFFFF << (16 - SIZE);
y_stride = dmabuf->planes[0].stride / 2;
y_data = (const guint16 *) (src_data[0] + dmabuf->planes[0].offset);
@@ -319,22 +254,24 @@ download_p010 (guchar *dst,
{
for (x = 0; x < width; x += X_SUB)
{
gint64 r, g, b;
gsize xs, ys;
guint16 u, v;
guint16 u_, v_;
u = uv_data[x / X_SUB * 2 + U];
u = (u & MASK) | (u >> SIZE);
v = uv_data[x / X_SUB * 2 + V];
v = (v & MASK) | (v >> SIZE);
get_uv_values16 (&itu601_narrow, u, v, &r, &g, &b);
u_ = uv_data[x / X_SUB * 2 + U];
u_ = u_ | (u_ >> SIZE);
v_ = uv_data[x / X_SUB * 2 + V];
v_ = v_ | (v_ >> SIZE);
for (ys = 0; ys < Y_SUB && y + ys < height; ys++)
for (xs = 0; xs < X_SUB && x + xs < width; xs++)
{
guint16 *rgb = &dst_data[3 * (x + xs) + dst_stride * ys];
guint16 y_ = y_data[x + xs + y_stride * ys];
y_ = (y_ & MASK) | (y_ >> SIZE);
set_rgb_values16 (&dst_data[3 * (x + xs) + dst_stride * ys], y_, r, g, b);
y_ = y_ | (y_ >> SIZE);
rgb[0] = y_;
rgb[1] = u_;
rgb[2] = v_;
}
}
dst_data += Y_SUB * dst_stride;
@@ -408,14 +345,21 @@ download_yuv_3 (guchar *dst_data,
{
for (x = 0; x < width; x += X_SUB)
{
int r, g, b;
int u_, v_;
gsize xs, ys;
get_uv_values (&itu601_narrow, u_data[x / X_SUB], v_data[x / X_SUB], &r, &g, &b);
u_ = u_data[x / X_SUB];
v_ = v_data[x / X_SUB];
for (ys = 0; ys < Y_SUB && y + ys < height; ys++)
for (xs = 0; xs < X_SUB && x + xs < width; xs++)
set_rgb_values (&dst_data[3 * (x + xs) + dst_stride * ys], y_data[x + xs + y_stride * ys], r, g, b);
{
guint8 *rgb = &dst_data[3 * (x + xs) + dst_stride * ys];
rgb[0] = y_data[x + xs + y_stride * ys];
rgb[1] = u_;
rgb[2] = v_;
}
}
dst_data += Y_SUB * dst_stride;
y_data += Y_SUB * y_stride;
@@ -465,12 +409,23 @@ download_yuyv (guchar *dst_data,
{
for (x = 0; x < width; x += 2)
{
int r, g, b;
guint8 *rgb;
int u_, v_;
get_uv_values (&itu601_narrow, src_data[2 * x + U], src_data[2 * x + V], &r, &g, &b);
set_rgb_values (&dst_data[3 * x], src_data[2 * x + Y1], r, g, b);
u_ = src_data[2 * x + U];
v_ = src_data[2 * x + V];
rgb = &dst_data[3 * x];
rgb[0] = src_data[2 * x + Y1];
rgb[1] = u_;
rgb[2] = v_;
if (x + 1 < width)
set_rgb_values (&dst_data[3 * (x + 1)], src_data[2 * x + Y2], r, g, b);
{
rgb = &dst_data[3 * (x + 1)];
rgb[0] = src_data[2 * x + Y2];
rgb[1] = u_;
rgb[2] = v_;
}
}
dst_data += dst_stride;
src_data += src_stride;
@@ -2139,14 +2094,14 @@ gdk_dmabuf_do_download_mmap (GdkTexture *texture,
needs_unmap[i] = TRUE;
}
info->download (data,
stride,
gdk_texture_get_format (texture),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
dmabuf,
src_data,
sizes);
info->download (data,
stride,
gdk_texture_get_format (texture),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
dmabuf,
src_data,
sizes);
out:
for (i = 0; i < dmabuf->n_planes; i++)
+76 -4
View File
@@ -209,12 +209,15 @@ gdk_dmabuf_egl_create_image (GdkDisplay *display,
int width,
int height,
const GdkDmabuf *dmabuf,
int color_space_hint,
int range_hint,
int target)
{
EGLDisplay egl_display = gdk_display_get_egl_display (display);
EGLint attribs[64];
int i;
EGLImage image;
gboolean is_yuv;
g_return_val_if_fail (width > 0, 0);
g_return_val_if_fail (height > 0, 0);
@@ -228,6 +231,25 @@ gdk_dmabuf_egl_create_image (GdkDisplay *display,
return EGL_NO_IMAGE;
}
if (gdk_dmabuf_fourcc_is_yuv (dmabuf->fourcc, &is_yuv) && is_yuv)
{
if (color_space_hint == 0 || range_hint == 0)
{
GDK_DISPLAY_DEBUG (display, DMABUF,
"Can't import yuv dmabuf into GL without color space hints");
return EGL_NO_IMAGE;
}
}
else
{
if (color_space_hint != 0 || range_hint != 0)
{
GDK_DISPLAY_DEBUG (display, DMABUF,
"Can't import non-yuv dmabuf into GL with color space hints");
return EGL_NO_IMAGE;
}
}
GDK_DISPLAY_DEBUG (display, DMABUF,
"Importing dmabuf (format: %.4s:%#" G_GINT64_MODIFIER "x, planes: %u) into GL",
(char *) &dmabuf->fourcc, dmabuf->modifier, dmabuf->n_planes);
@@ -241,10 +263,16 @@ gdk_dmabuf_egl_create_image (GdkDisplay *display,
attribs[i++] = height;
attribs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
attribs[i++] = dmabuf->fourcc;
attribs[i++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attribs[i++] = EGL_ITU_REC601_EXT;
attribs[i++] = EGL_SAMPLE_RANGE_HINT_EXT;
attribs[i++] = EGL_YUV_NARROW_RANGE_EXT;
if (color_space_hint != 0)
{
attribs[i++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attribs[i++] = color_space_hint;
}
if (range_hint != 0)
{
attribs[i++] = EGL_SAMPLE_RANGE_HINT_EXT;
attribs[i++] = range_hint;
}
#define ADD_PLANE(plane) \
{ \
@@ -289,4 +317,48 @@ gdk_dmabuf_egl_create_image (GdkDisplay *display,
return image;
}
void
gdk_dmabuf_get_egl_yuv_hints (const GdkDmabuf *dmabuf,
GdkColorState *color_state,
int *color_space_hint,
int *range_hint)
{
gboolean is_yuv;
const GdkCicp *cicp;
cicp = gdk_color_state_get_cicp (color_state);
if (cicp &&
gdk_dmabuf_fourcc_is_yuv (dmabuf->fourcc, &is_yuv) && is_yuv)
{
if (cicp->range == GDK_CICP_RANGE_NARROW)
*range_hint = EGL_YUV_NARROW_RANGE_EXT;
else
*range_hint = EGL_YUV_FULL_RANGE_EXT;
switch (cicp->matrix_coefficients)
{
case 1:
*color_space_hint = EGL_ITU_REC709_EXT;
break;
case 5:
case 6:
*color_space_hint = EGL_ITU_REC601_EXT;
break;
case 9:
*color_space_hint = EGL_ITU_REC2020_EXT;
break;
default:
*color_space_hint = 0;
*range_hint = 0;
break;
}
}
else
{
*color_space_hint = 0;
*range_hint = 0;
}
}
#endif /* HAVE_DMABUF && HAVE_EGL */
+7
View File
@@ -13,6 +13,13 @@ EGLImage gdk_dmabuf_egl_create_image (GdkDisplay
int width,
int height,
const GdkDmabuf *dmabuf,
int color_state_hint,
int range_hint,
int target);
void gdk_dmabuf_get_egl_yuv_hints (const GdkDmabuf *dmabuf,
GdkColorState *color_state,
int *color_space_hint,
int *range_hint);
#endif /* HAVE_DMABUF && HAVE_EGL */
+4
View File
@@ -5,6 +5,10 @@
#include <drm_fourcc.h>
#endif
#ifndef DRM_FORMAT_MOD_INVALID
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
#endif
#ifndef fourcc_code
#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \
((__u32)(c) << 16) | ((__u32)(d) << 24))
+2 -5
View File
@@ -208,12 +208,9 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
gboolean is_yuv;
if (gdk_dmabuf_fourcc_is_yuv (dmabuf.fourcc, &is_yuv) && is_yuv)
{
g_warning_once ("FIXME: Implement the proper colorstate for YUV dmabufs");
color_state = gdk_color_state_get_srgb ();
}
color_state = GDK_COLOR_STATE_YUV;
else
color_state = gdk_color_state_get_srgb ();
color_state = GDK_COLOR_STATE_SRGB;
}
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,
+44 -14
View File
@@ -223,6 +223,9 @@ gdk_draw_context_init (GdkDrawContext *self)
*
* Returns: %TRUE if the context is between [method@Gdk.DrawContext.begin_frame]
* and [method@Gdk.DrawContext.end_frame] calls.
*
* Deprecated: 4.16: Drawing directly to the surface is no longer recommended.
* Use `GskRenderNode` and `GskRenderer`.
*/
gboolean
gdk_draw_context_is_in_frame (GdkDrawContext *context)
@@ -313,6 +316,9 @@ gdk_draw_context_get_surface (GdkDrawContext *context)
* gdk_draw_context_begin_frame() and gdk_draw_context_end_frame() via the
* use of [GskRenderer](../gsk4/class.Renderer.html)s, so application code
* does not need to call these functions explicitly.
*
* Deprecated: 4.16: Drawing directly to the surface is no longer recommended.
* Use `GskRenderNode` and `GskRenderer`.
*/
void
gdk_draw_context_begin_frame (GdkDrawContext *context,
@@ -324,11 +330,12 @@ gdk_draw_context_begin_frame (GdkDrawContext *context,
g_return_if_fail (priv->surface != NULL);
g_return_if_fail (region != NULL);
gdk_draw_context_begin_frame_full (context, GDK_MEMORY_U8, region);
gdk_draw_context_begin_frame_full (context, GDK_MEMORY_U8, region, NULL);
}
/*
* @depth: best depth to render in
* @opaque: (nullable): opaque region of the rendering
*
* If the given depth is not `GDK_MEMORY_U8`, GDK will see about providing a
* rendering target that supports a higher bit depth than 8 bits per channel.
@@ -351,9 +358,10 @@ gdk_draw_context_begin_frame (GdkDrawContext *context,
* to choose.
*/
void
gdk_draw_context_begin_frame_full (GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region)
gdk_draw_context_begin_frame_full (GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region,
const graphene_rect_t *opaque)
{
GdkDrawContextPrivate *priv = gdk_draw_context_get_instance_private (context);
@@ -378,6 +386,8 @@ gdk_draw_context_begin_frame_full (GdkDrawContext *context,
return;
}
gdk_surface_set_opaque_rect (priv->surface, opaque);
if (gdk_display_get_debug_flags (priv->display) & GDK_DEBUG_HIGH_DEPTH)
depth = GDK_MEMORY_FLOAT32;
@@ -420,6 +430,21 @@ region_get_pixels (cairo_region_t *region)
}
#endif
void
gdk_draw_context_end_frame_full (GdkDrawContext *context)
{
GdkDrawContextPrivate *priv = gdk_draw_context_get_instance_private (context);
GDK_DRAW_CONTEXT_GET_CLASS (context)->end_frame (context, priv->frame_region);
gdk_profiler_set_int_counter (pixels_counter, region_get_pixels (priv->frame_region));
g_clear_pointer (&priv->color_state, gdk_color_state_unref);
g_clear_pointer (&priv->frame_region, cairo_region_destroy);
g_clear_object (&priv->surface->paint_context);
priv->depth = GDK_N_DEPTHS;
}
/**
* gdk_draw_context_end_frame:
* @context: a `GdkDrawContext`
@@ -432,6 +457,9 @@ region_get_pixels (cairo_region_t *region)
* When using a [class@Gdk.GLContext], this function may call `glFlush()`
* implicitly before returning; it is not recommended to call `glFlush()`
* explicitly before calling this function.
*
* Deprecated: 4.16: Drawing directly to the surface is no longer recommended.
* Use `GskRenderNode` and `GskRenderer`.
*/
void
gdk_draw_context_end_frame (GdkDrawContext *context)
@@ -459,14 +487,7 @@ gdk_draw_context_end_frame (GdkDrawContext *context)
return;
}
GDK_DRAW_CONTEXT_GET_CLASS (context)->end_frame (context, priv->frame_region);
gdk_profiler_set_int_counter (pixels_counter, region_get_pixels (priv->frame_region));
g_clear_pointer (&priv->color_state, gdk_color_state_unref);
g_clear_pointer (&priv->frame_region, cairo_region_destroy);
g_clear_object (&priv->surface->paint_context);
priv->depth = GDK_N_DEPTHS;
gdk_draw_context_end_frame_full (context);
}
/**
@@ -483,15 +504,24 @@ gdk_draw_context_end_frame (GdkDrawContext *context)
* and [method@Gdk.DrawContext.end_frame], %NULL will be returned.
*
* Returns: (transfer none) (nullable): a Cairo region
*
* Deprecated: 4.16: Drawing directly to the surface is no longer recommended.
* Use `GskRenderNode` and `GskRenderer`.
*/
const cairo_region_t *
gdk_draw_context_get_frame_region (GdkDrawContext *context)
_gdk_draw_context_get_frame_region (GdkDrawContext *context)
{
GdkDrawContextPrivate *priv = gdk_draw_context_get_instance_private (context);
return priv->frame_region;
}
const cairo_region_t *
(gdk_draw_context_get_frame_region) (GdkDrawContext *context)
{
g_return_val_if_fail (GDK_IS_DRAW_CONTEXT (context), NULL);
return priv->frame_region;
return _gdk_draw_context_get_frame_region (context);
}
/*<private>
+4 -4
View File
@@ -40,15 +40,15 @@ GdkDisplay * gdk_draw_context_get_display (GdkDrawContext
GDK_AVAILABLE_IN_ALL
GdkSurface * gdk_draw_context_get_surface (GdkDrawContext *context);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_16
void gdk_draw_context_begin_frame (GdkDrawContext *context,
const cairo_region_t *region);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_16
void gdk_draw_context_end_frame (GdkDrawContext *context);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_16
gboolean gdk_draw_context_is_in_frame (GdkDrawContext *context);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_16
const cairo_region_t * gdk_draw_context_get_frame_region (GdkDrawContext *context);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDrawContext, g_object_unref)
+7 -1
View File
@@ -25,6 +25,8 @@
#include "gdkcolorstateprivate.h"
#include "gdkmemoryformatprivate.h"
#include <graphene.h>
G_BEGIN_DECLS
#define GDK_DRAW_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DRAW_CONTEXT, GdkDrawContextClass))
@@ -57,10 +59,14 @@ void gdk_draw_context_surface_resized (GdkDrawContext
void gdk_draw_context_begin_frame_full (GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region);
const cairo_region_t *region,
const graphene_rect_t *opaque);
void gdk_draw_context_end_frame_full (GdkDrawContext *context);
void gdk_draw_context_empty_frame (GdkDrawContext *context);
#define gdk_draw_context_get_frame_region(...) _gdk_draw_context_get_frame_region(__VA_ARGS__)
const cairo_region_t * _gdk_draw_context_get_frame_region (GdkDrawContext *self);
GdkColorState * gdk_draw_context_get_color_state (GdkDrawContext *self);
GdkMemoryDepth gdk_draw_context_get_depth (GdkDrawContext *self);
+42 -8
View File
@@ -122,6 +122,7 @@ struct _GdkGLContextPrivate
GdkGLMemoryFlags memory_flags[GDK_MEMORY_N_FORMATS];
GdkGLFeatures features;
guint surface_attached : 1;
guint use_khr_debug : 1;
guint has_debug_output : 1;
guint extensions_checked : 1;
@@ -637,7 +638,10 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
else
*out_depth = GDK_MEMORY_U8;
*out_color_state = color_state;
if (*out_depth == GDK_MEMORY_U8_SRGB)
*out_color_state = gdk_color_state_get_no_srgb_tf (color_state);
else
*out_color_state = color_state;
#else
*out_color_state = gdk_color_state_get_srgb ();
*out_depth = GDK_MEMORY_U8;
@@ -826,20 +830,28 @@ gdk_gl_context_init (GdkGLContext *self)
/* Must have called gdk_display_prepare_gl() before */
GdkGLContext *
gdk_gl_context_new (GdkDisplay *display,
GdkSurface *surface)
GdkSurface *surface,
gboolean surface_attached)
{
GdkGLContext *shared;
GdkGLContextPrivate *priv;
GdkGLContext *shared, *result;
g_assert (surface == NULL || display == gdk_surface_get_display (surface));
g_assert (!surface_attached || surface != NULL);
/* assert gdk_display_prepare_gl() had been called */
shared = gdk_display_get_gl_context (display);
g_assert (shared);
return g_object_new (G_OBJECT_TYPE (shared),
"display", display,
"surface", surface,
NULL);
result = g_object_new (G_OBJECT_TYPE (shared),
"display", display,
"surface", surface,
NULL);
priv = gdk_gl_context_get_instance_private (result);
priv->surface_attached = surface_attached;
return result;
}
void
@@ -1822,12 +1834,22 @@ gdk_gl_context_check_is_current (GdkGLContext *context)
void
gdk_gl_context_make_current (GdkGLContext *context)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
MaskedContext *current, *masked_context;
gboolean surfaceless;
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
surfaceless = !gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context));
if (priv->surface_attached)
{
surfaceless = FALSE;
}
else
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
surfaceless = !gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context));
G_GNUC_END_IGNORE_DEPRECATIONS
}
masked_context = mask_context (context, surfaceless);
current = g_private_get (&thread_current_context);
@@ -2176,6 +2198,8 @@ gdk_gl_context_import_dmabuf_for_target (GdkGLContext *self,
int width,
int height,
const GdkDmabuf *dmabuf,
int color_space_hint,
int range_hint,
int target)
{
#if defined(HAVE_EGL) && defined(HAVE_DMABUF)
@@ -2187,6 +2211,8 @@ gdk_gl_context_import_dmabuf_for_target (GdkGLContext *self,
width,
height,
dmabuf,
color_space_hint,
range_hint,
target);
if (image == EGL_NO_IMAGE)
return 0;
@@ -2210,6 +2236,8 @@ gdk_gl_context_import_dmabuf (GdkGLContext *self,
int width,
int height,
const GdkDmabuf *dmabuf,
int color_space_hint,
int range_hint,
gboolean *external)
{
GdkDisplay *display = gdk_gl_context_get_display (self);
@@ -2226,6 +2254,8 @@ gdk_gl_context_import_dmabuf (GdkGLContext *self,
texture_id = gdk_gl_context_import_dmabuf_for_target (self,
width, height,
dmabuf,
color_space_hint,
range_hint,
GL_TEXTURE_2D);
if (texture_id == 0)
{
@@ -2255,6 +2285,8 @@ gdk_gl_context_import_dmabuf (GdkGLContext *self,
texture_id = gdk_gl_context_import_dmabuf_for_target (self,
width, height,
dmabuf,
color_space_hint,
range_hint,
GL_TEXTURE_EXTERNAL_OES);
if (texture_id == 0)
{
@@ -2287,6 +2319,8 @@ gdk_gl_context_import_dmabuf (GdkGLContext *self,
texture_id = gdk_gl_context_import_dmabuf_for_target (self,
width, height,
dmabuf,
color_space_hint,
range_hint,
target);
if (texture_id == 0)
+5 -2
View File
@@ -122,8 +122,9 @@ void gdk_gl_backend_use (GdkGLBackend
void gdk_gl_context_clear_current_if_surface (GdkSurface *surface);
GdkGLContext * gdk_gl_context_new (GdkDisplay *display,
GdkSurface *surface);
GdkGLContext * gdk_gl_context_new (GdkDisplay *display,
GdkSurface *surface,
gboolean surface_attached);
gboolean gdk_gl_context_is_api_allowed (GdkGLContext *self,
GdkGLAPI api,
@@ -184,6 +185,8 @@ guint gdk_gl_context_import_dmabuf (GdkGLContext
int width,
int height,
const GdkDmabuf *dmabuf,
int color_space_hint,
int range_hint,
gboolean *external);
gboolean gdk_gl_context_export_dmabuf (GdkGLContext *self,
-14
View File
@@ -1879,12 +1879,6 @@ gdk_memory_convert (guchar *dest_data,
g_assert (dest_data + gdk_memory_format_min_buffer_size (dest_format, dest_stride, width, height) <= src_data ||
src_data + gdk_memory_format_min_buffer_size (src_format, src_stride, width, height) <= dest_data);
g_print ("memory convert %s %s -> %s %s\n",
gdk_memory_format_get_name (src_format),
gdk_color_state_get_name (src_cs),
gdk_memory_format_get_name (dest_format),
gdk_color_state_get_name (dest_cs));
if (src_format == dest_format && gdk_color_state_equal (dest_cs, src_cs))
{
gsize bytes_per_row = src_desc->bytes_per_pixel * width;
@@ -1958,7 +1952,6 @@ gdk_memory_convert (guchar *dest_data,
if (func != NULL)
{
g_print ("convert format\n");
for (y = 0; y < height; y++)
{
func (dest_data, src_data, width);
@@ -1981,13 +1974,10 @@ gdk_memory_convert (guchar *dest_data,
needs_premultiply = src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT;
}
g_print ("convert color %lu %lu\n", width, height);
for (y = 0; y < height; y++)
{
src_desc->to_float (tmp, src_data, width);
g_print ("after to_float: %f %f %f %f\n", tmp[0][0], tmp[0][1], tmp[0][2], tmp[0][3]);
if (needs_unpremultiply)
unpremultiply (tmp, width);
@@ -2169,10 +2159,6 @@ gdk_memory_convert_color_state (guchar *data,
if (gdk_color_state_equal (src_cs, dest_cs))
return;
g_print ("memory convert color state %s -> %s\n",
gdk_color_state_get_name (src_cs),
gdk_color_state_get_name (dest_cs));
if (format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED &&
src_cs == GDK_COLOR_STATE_SRGB &&
dest_cs == GDK_COLOR_STATE_SRGB_LINEAR)
+10
View File
@@ -52,6 +52,16 @@ gdk_rectangle_transform_affine (const GdkRectangle *src,
dest->height = ceilf (MAX (y1, y2)) - dest->y;
}
static inline gboolean
gdk_rectangle_contains (const GdkRectangle *rect,
const GdkRectangle *contained)
{
return contained->x >= rect->x
&& contained->y >= rect->y
&& contained->x + contained->width <= rect->x + rect->width
&& contained->y + contained->height <= rect->y + rect->height;
}
G_END_DECLS
+102 -11
View File
@@ -40,11 +40,13 @@
#include <glib/gi18n-lib.h>
#include "gdkmarshalers.h"
#include "gdkpopupprivate.h"
#include "gdkrectangle.h"
#include "gdkrectangleprivate.h"
#include "gdktoplevelprivate.h"
#include "gdkvulkancontext.h"
#include "gdksubsurfaceprivate.h"
#include "gsk/gskrectprivate.h"
#include <math.h>
#ifdef HAVE_EGL
@@ -75,6 +77,9 @@ struct _GdkSurfacePrivate
GdkMemoryDepth egl_surface_depth;
#endif
cairo_region_t *opaque_region;
cairo_rectangle_int_t opaque_rect; /* This is different from the region */
gpointer widget;
GdkColorState *color_state;
@@ -510,6 +515,12 @@ gdk_surface_real_create_subsurface (GdkSurface *surface)
return NULL;
}
static void
gdk_surface_default_set_opaque_region (GdkSurface *surface,
cairo_region_t *region)
{
}
static void
gdk_surface_constructed (GObject *object)
{
@@ -533,6 +544,7 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
klass->beep = gdk_surface_real_beep;
klass->get_scale = gdk_surface_real_get_scale;
klass->create_subsurface = gdk_surface_real_create_subsurface;
klass->set_opaque_region = gdk_surface_default_set_opaque_region;
/**
* GdkSurface:cursor: (attributes org.gtk.Property.get=gdk_surface_get_cursor org.gtk.Property.set=gdk_surface_set_cursor)
@@ -771,7 +783,7 @@ gdk_surface_finalize (GObject *object)
g_clear_object (&surface->display);
g_clear_pointer (&surface->opaque_region, cairo_region_destroy);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
if (surface->parent)
surface->parent->children = g_list_remove (surface->parent->children, surface);
@@ -1134,11 +1146,12 @@ gdk_surface_set_egl_native_window (GdkSurface *self,
{
GdkDisplay *display = gdk_surface_get_display (self);
gdk_gl_context_clear_current_if_surface (self);
eglDestroySurface (gdk_display_get_egl_display (display), priv->egl_surface);
priv->egl_surface = NULL;
}
gdk_gl_context_clear_current_if_surface (self);
priv->egl_native_window = native_window;
}
@@ -1256,7 +1269,7 @@ gdk_surface_create_gl_context (GdkSurface *surface,
if (!gdk_display_prepare_gl (surface->display, error))
return NULL;
return gdk_gl_context_new (surface->display, surface);
return gdk_gl_context_new (surface->display, surface, FALSE);
}
/**
@@ -2633,6 +2646,35 @@ gdk_surface_get_scale (GdkSurface *surface)
return GDK_SURFACE_GET_CLASS (surface)->get_scale (surface);
}
static void
gdk_surface_update_opaque_region (GdkSurface *self)
{
GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
cairo_region_t *region;
if (priv->opaque_region == NULL)
{
if (priv->opaque_rect.width <= 0)
region = NULL;
else
region = cairo_region_create_rectangle (&priv->opaque_rect);
}
else
{
if (priv->opaque_rect.width <= 0)
region = cairo_region_reference (priv->opaque_region);
else
{
region = cairo_region_copy (priv->opaque_region);
cairo_region_union_rectangle (region, &priv->opaque_rect);
}
}
GDK_SURFACE_GET_CLASS (self)->set_opaque_region (self, region);
g_clear_pointer (&region, cairo_region_destroy);
}
/**
* gdk_surface_set_opaque_region:
* @surface: a top-level `GdkSurface`
@@ -2654,27 +2696,76 @@ gdk_surface_get_scale (GdkSurface *surface)
* is opaque, as we know where the opaque regions are. If your surface
* background is not opaque, please update this property in your
* [GtkWidgetClass.css_changed](../gtk4/vfunc.Widget.css_changed.html) handler.
*
* Deprecated: 4.16: GDK can figure out the opaque parts of a window itself
* by inspecting the contents that are drawn.
*/
void
gdk_surface_set_opaque_region (GdkSurface *surface,
cairo_region_t *region)
{
GdkSurfaceClass *class;
GdkSurfacePrivate *priv = gdk_surface_get_instance_private (surface);
g_return_if_fail (GDK_IS_SURFACE (surface));
g_return_if_fail (!GDK_SURFACE_DESTROYED (surface));
if (cairo_region_equal (surface->opaque_region, region))
if (cairo_region_equal (priv->opaque_region, region))
return;
g_clear_pointer (&surface->opaque_region, cairo_region_destroy);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
if (region != NULL)
surface->opaque_region = cairo_region_reference (region);
priv->opaque_region = cairo_region_reference (region);
class = GDK_SURFACE_GET_CLASS (surface);
if (class->set_opaque_region)
class->set_opaque_region (surface, region);
gdk_surface_update_opaque_region (surface);
}
/* Sets the opaque rect from the rendernode via end_frame() */
void
gdk_surface_set_opaque_rect (GdkSurface *self,
const graphene_rect_t *rect)
{
GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
cairo_rectangle_int_t opaque;
if (rect)
gsk_rect_to_cairo_shrink (rect, &opaque);
else
opaque = (cairo_rectangle_int_t) { 0, 0, 0, 0 };
if (gdk_rectangle_equal (&priv->opaque_rect, &opaque))
return;
priv->opaque_rect = opaque;
gdk_surface_update_opaque_region (self);
}
/*
* gdk_surface_is_opaque:
* @self: a surface
*
* Checks if the whole surface is known to be opaque.
* This allows using an RGBx buffer instead of RGBA.
*
* This function works for the currently rendered frame inside
* begin_frame() implementations.
*
* Returns: %TRUE if the whole surface is provably opaque
**/
gboolean
gdk_surface_is_opaque (GdkSurface *self)
{
GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
cairo_rectangle_int_t whole = { 0, 0, self->width, self->height };
if (gdk_rectangle_contains (&priv->opaque_rect, &whole))
return TRUE;
if (cairo_region_contains_rectangle (priv->opaque_region, &whole) == CAIRO_REGION_OVERLAP_IN)
return TRUE;
return FALSE;
}
void
+1 -1
View File
@@ -125,7 +125,7 @@ void gdk_surface_request_layout (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
GdkFrameClock* gdk_surface_get_frame_clock (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_16
void gdk_surface_set_opaque_region (GdkSurface *surface,
cairo_region_t *region);
+11 -10
View File
@@ -96,8 +96,6 @@ struct _GdkSurface
GSList *draw_contexts;
GdkDrawContext *paint_context;
cairo_region_t *opaque_region;
GdkSeat *current_shortcuts_inhibited_seat;
GPtrArray *subsurfaces;
@@ -253,14 +251,17 @@ gdk_gravity_flip_vertically (GdkGravity anchor)
g_assert_not_reached ();
}
void _gdk_surface_destroy (GdkSurface *surface,
gboolean foreign_destroy);
void gdk_surface_invalidate_rect (GdkSurface *surface,
const GdkRectangle *rect);
void gdk_surface_invalidate_region (GdkSurface *surface,
const cairo_region_t *region);
void _gdk_surface_clear_update_area (GdkSurface *surface);
void _gdk_surface_update_size (GdkSurface *surface);
void _gdk_surface_destroy (GdkSurface *surface,
gboolean foreign_destroy);
void gdk_surface_invalidate_rect (GdkSurface *surface,
const GdkRectangle *rect);
void gdk_surface_invalidate_region (GdkSurface *surface,
const cairo_region_t *region);
void _gdk_surface_clear_update_area (GdkSurface *surface);
void _gdk_surface_update_size (GdkSurface *surface);
void gdk_surface_set_opaque_rect (GdkSurface *self,
const graphene_rect_t *rect);
gboolean gdk_surface_is_opaque (GdkSurface *self);
GdkGLContext * gdk_surface_get_paint_gl_context (GdkSurface *surface,
GError **error);
+2
View File
@@ -983,6 +983,8 @@ gdk_texture_download_surface (GdkTexture *texture,
* %CAIRO_FORMAT_ARGB32, so every downloaded pixel requires
* 4 bytes of memory.
*
* The downloaded data is converted to the sRGB color state.
*
* Downloading a texture into a Cairo image surface:
* ```c
* surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+4 -3
View File
@@ -678,7 +678,10 @@ gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context,
cairo_region_union (region, priv->regions[priv->draw_index]);
*out_color_state = color_state;
if (priv->current_depth == GDK_MEMORY_U8_SRGB)
*out_color_state = gdk_color_state_get_no_srgb_tf (color_state);
else
*out_color_state = color_state;
*out_depth = priv->current_depth;
}
@@ -1345,7 +1348,6 @@ gdk_vulkan_context_get_draw_index (GdkVulkanContext *context)
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), 0);
g_return_val_if_fail (gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context)), 0);
return priv->draw_index;
}
@@ -1369,7 +1371,6 @@ gdk_vulkan_context_set_draw_semaphore (GdkVulkanContext *context,
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
g_return_if_fail (GDK_IS_VULKAN_CONTEXT (context));
g_return_if_fail (!gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context)));
g_return_if_fail (priv->draw_semaphore == VK_NULL_HANDLE);
priv->draw_semaphore = semaphore;
+1 -1
View File
@@ -65,7 +65,7 @@ gdk_vulkan_handle_result (VkResult res,
{
if (res != VK_SUCCESS)
{
GDK_DEBUG (VULKAN, "%s(): %s (%d)", called_function, gdk_vulkan_strerror (res), res);
g_warning ("%s(): %s (%d)", called_function, gdk_vulkan_strerror (res), res);
}
return res;
+865
View File
@@ -0,0 +1,865 @@
#include "config.h"
#include "gdkavifprivate.h"
#include "gdkmemorytexturebuilder.h"
#include "gdktexture.h"
#include "gdkdisplay.h"
#include "gdkcicpparamsprivate.h"
#include "gdkcolorstateprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkdmabuftexture.h"
#include "gdktexturedownloader.h"
#include <avif/avif.h>
#ifdef HAVE_DMABUF
#include "gdkdmabuftextureprivate.h"
#include "gdkdmabuftexturebuilder.h"
#include "gdkdmabuffourccprivate.h"
/* NOTE: We build this code outside of libgtk, in tests and the image tool, so this
* code has to be a bit careful to avoid depending on private api, which can also
* be dragged in indirectly, via inlines.
*/
#ifdef AVIF_DEBUG
#define DEBUG(fmt,...) g_log ("avif", G_LOG_LEVEL_DEBUG, fmt __VA_OPT__(,) __VA_ARGS__)
#else
#define DEBUG(fmt,...)
#endif
/* {{{ udmabuf support */
#include <inttypes.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/udmabuf.h>
#include <drm_fourcc.h>
#include <errno.h>
#include <gio/gio.h>
static int udmabuf_fd;
static gboolean
udmabuf_initialize (GError **error)
{
if (udmabuf_fd == 0)
{
udmabuf_fd = open ("/dev/udmabuf", O_RDWR);
if (udmabuf_fd == -1)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to open /dev/udmabuf: %s",
g_strerror (errno));
}
}
return udmabuf_fd != -1;
}
typedef struct
{
int mem_fd;
int dmabuf_fd;
size_t size;
gpointer data;
} UDmabuf;
static void
udmabuf_free (gpointer data)
{
UDmabuf *udmabuf = data;
munmap (udmabuf->data, udmabuf->size);
close (udmabuf->mem_fd);
close (udmabuf->dmabuf_fd);
g_free (udmabuf);
}
#define align(x,y) (((x) + (y) - 1) & ~((y) - 1))
static UDmabuf *
udmabuf_allocate (size_t size,
GError **error)
{
int mem_fd = -1;
int dmabuf_fd = -1;
uint64_t alignment;
int res;
gpointer data;
UDmabuf *udmabuf;
if (udmabuf_fd == -1)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"udmabuf not available");
goto fail;
}
alignment = sysconf (_SC_PAGE_SIZE);
size = align (size, alignment);
mem_fd = memfd_create ("gtk", MFD_ALLOW_SEALING);
if (mem_fd == -1)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to open /dev/udmabuf: %s",
g_strerror (errno));
goto fail;
}
res = ftruncate (mem_fd, size);
if (res == -1)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"ftruncate failed: %s",
g_strerror (errno));
goto fail;
}
if (fcntl (mem_fd, F_ADD_SEALS, F_SEAL_SHRINK) < 0)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"ftruncate failed: %s",
g_strerror (errno));
goto fail;
}
dmabuf_fd = ioctl (udmabuf_fd,
UDMABUF_CREATE,
&(struct udmabuf_create) {
.memfd = mem_fd,
.flags = UDMABUF_FLAGS_CLOEXEC,
.offset = 0,
.size = size
});
if (dmabuf_fd < 0)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"UDMABUF_CREATE ioctl failed: %s",
g_strerror (errno));
goto fail;
}
data = mmap (NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, mem_fd, 0);
if (!data)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"mmap failed: %s",
g_strerror (errno));
goto fail;
}
udmabuf = g_new0 (UDmabuf, 1);
udmabuf->mem_fd = mem_fd;
udmabuf->dmabuf_fd = dmabuf_fd;
udmabuf->size = size;
udmabuf->data = data;
return udmabuf;
fail:
if (mem_fd != -1)
close (mem_fd);
if (dmabuf_fd != -1)
close (dmabuf_fd);
return NULL;
}
/* }}} */
/* {{{ dmabuf texture support */
static GdkTexture *
gdk_avif_create_dmabuf_texture (avifDecoder *decoder,
GdkColorState *color_state,
GError **error)
{
guint fourcc = 0;
guint32 width, height, depth;
GdkDmabufTextureBuilder *builder;
UDmabuf *udmabuf;
gboolean combine_uv = FALSE;
guchar *data;
gsize size0, size1, size2;
GdkTexture *texture;
if (!udmabuf_initialize (error))
return NULL;
width = decoder->image->width;
height = decoder->image->height;
depth = decoder->image->depth;
if (decoder->image->alphaPlane)
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
"no yuv dmabuf with alpha");
return NULL;
}
switch (decoder->image->yuvFormat)
{
case AVIF_PIXEL_FORMAT_YUV444:
DEBUG ("load: format yuv444");
if (depth == 8)
fourcc = DRM_FORMAT_YUV444;
break;
case AVIF_PIXEL_FORMAT_YUV422:
DEBUG ("load: format yuv422");
if (depth == 8)
fourcc = DRM_FORMAT_YUV422;
break;
case AVIF_PIXEL_FORMAT_YUV420:
DEBUG ("load: format yuv420");
combine_uv = TRUE;
if (depth == 8)
fourcc = DRM_FORMAT_NV12;
else if (depth == 10)
fourcc = DRM_FORMAT_P010;
else if (depth == 12)
fourcc = DRM_FORMAT_P012;
else if (depth == 16)
fourcc = DRM_FORMAT_P016;
break;
case AVIF_PIXEL_FORMAT_YUV400:
case AVIF_PIXEL_FORMAT_NONE:
case AVIF_PIXEL_FORMAT_COUNT:
default:
break;
}
if (fourcc == 0)
{
const char *names[] = { "none", "yuv444", "yuv422", "yuv420", "yuv400" };
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
"unsupported pixel format %s, depth %u",
names[decoder->image->yuvFormat], decoder->image->depth);
return NULL;
}
DEBUG ("load: use fourcc %.4s", (char *)&fourcc);
builder = gdk_dmabuf_texture_builder_new ();
gdk_dmabuf_texture_builder_set_display (builder, gdk_display_get_default ());
gdk_dmabuf_texture_builder_set_width (builder, width);
gdk_dmabuf_texture_builder_set_height (builder, height);
gdk_dmabuf_texture_builder_set_color_state (builder, color_state);
gdk_dmabuf_texture_builder_set_fourcc (builder, fourcc);
gdk_dmabuf_texture_builder_set_modifier (builder, DRM_FORMAT_MOD_LINEAR);
gdk_dmabuf_texture_builder_set_premultiplied (builder, FALSE);
if (combine_uv)
{
size0 = height * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
size1 = height / 2 * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
udmabuf = udmabuf_allocate (size0 + size1, NULL);
data = (guchar *) udmabuf->data;
if (depth == 8)
{
memcpy (data, avifImagePlane (decoder->image, AVIF_CHAN_Y), size0);
for (int i = 0; i < height / 2; i++)
{
guchar *usrc = avifImagePlane (decoder->image, AVIF_CHAN_U) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U);
guchar *vsrc = avifImagePlane (decoder->image, AVIF_CHAN_V) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V);
guchar *dest = data + size0 + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
for (int j = 0; j < width / 2; j++)
{
dest[2*j] = usrc[j];
dest[2*j+1] = vsrc[j];
}
}
}
else
{
for (int i = 0; i < height; i++)
{
guint16 *src = (guint16 *) (avifImagePlane (decoder->image, AVIF_CHAN_Y) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
guint16 *dest = (guint16 *) (data + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
for (int j = 0; j < width; j++)
dest[j] = src[j] << (16 - depth);
}
for (int i = 0; i < height / 2; i++)
{
guint16 *usrc = (guint16 *)(avifImagePlane (decoder->image, AVIF_CHAN_U) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U));
guint16 *vsrc = (guint16 *)(avifImagePlane (decoder->image, AVIF_CHAN_V) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V));
guint16 *dest = (guint16 *)(data + size0 + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
for (int j = 0; j < width / 2; j++)
{
dest[2*j] = usrc[j] << (16 - depth);
dest[2*j+1] = vsrc[j] << (16 - depth);
}
}
}
gdk_dmabuf_texture_builder_set_n_planes (builder, 2);
gdk_dmabuf_texture_builder_set_fd (builder, 0, udmabuf->dmabuf_fd);
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
gdk_dmabuf_texture_builder_set_stride (builder, 0, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
gdk_dmabuf_texture_builder_set_fd (builder, 1, udmabuf->dmabuf_fd);
gdk_dmabuf_texture_builder_set_offset (builder, 1, size0);
gdk_dmabuf_texture_builder_set_stride (builder, 1, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
}
else
{
size0 = height * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
size1 = height * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U);
size2 = height * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V);
udmabuf = udmabuf_allocate (size0 + size1 + size2, NULL);
data = (guchar *) udmabuf->data;
memcpy (data, avifImagePlane (decoder->image, AVIF_CHAN_Y), size0);
memcpy (data + size0, avifImagePlane (decoder->image, AVIF_CHAN_U), size1);
memcpy (data + size0 + size1, avifImagePlane (decoder->image, AVIF_CHAN_V), size2);
gdk_dmabuf_texture_builder_set_n_planes (builder, 3);
gdk_dmabuf_texture_builder_set_fd (builder, 0, udmabuf->dmabuf_fd);
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
gdk_dmabuf_texture_builder_set_stride (builder, 0, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
gdk_dmabuf_texture_builder_set_fd (builder, 1, udmabuf->dmabuf_fd);
gdk_dmabuf_texture_builder_set_offset (builder, 1, size0);
gdk_dmabuf_texture_builder_set_stride (builder, 1, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U));
gdk_dmabuf_texture_builder_set_fd (builder, 2, udmabuf->dmabuf_fd);
gdk_dmabuf_texture_builder_set_offset (builder, 2, size0 + size1);
gdk_dmabuf_texture_builder_set_stride (builder, 2, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V));
}
texture = gdk_dmabuf_texture_builder_build (builder, udmabuf_free, udmabuf, error);
g_object_unref (builder);
return texture;
}
#endif /* HAVE_DMABUF */
/* }}} */
/* {{{ memory texture support */
static GdkTexture *
gdk_avif_create_memory_texture (avifDecoder *decoder,
GdkColorState *color_state,
GError **error)
{
guint32 width, height, depth, stride, bpp;
GdkTexture *texture;
GdkMemoryTextureBuilder *builder;
guchar *data;
GBytes *bytes;
GdkMemoryFormat format = GDK_MEMORY_N_FORMATS;
int X_SUB, Y_SUB;
width = decoder->image->width;
height = decoder->image->height;
depth = decoder->image->depth;
switch (decoder->image->yuvFormat)
{
case AVIF_PIXEL_FORMAT_YUV444:
X_SUB = 1; Y_SUB = 1;
if (depth == 8)
{
format = GDK_MEMORY_R8G8B8A8;
bpp = 4;
}
else
{
format = GDK_MEMORY_R16G16B16A16;
bpp = 8;
}
break;
case AVIF_PIXEL_FORMAT_YUV422:
X_SUB = 2; Y_SUB = 1;
if (depth == 8)
{
format = GDK_MEMORY_R8G8B8A8;
bpp = 8;
}
else
{
format = GDK_MEMORY_R16G16B16A16;
bpp = 8;
}
break;
case AVIF_PIXEL_FORMAT_YUV420:
X_SUB = 2; Y_SUB = 2;
break;
case AVIF_PIXEL_FORMAT_YUV400:
case AVIF_PIXEL_FORMAT_NONE:
case AVIF_PIXEL_FORMAT_COUNT:
if (depth == 8)
{
format = GDK_MEMORY_R8G8B8A8;
bpp = 4;
}
else
{
format = GDK_MEMORY_R16G16B16A16;
bpp = 8;
}
default:
break;
}
if (format == GDK_MEMORY_N_FORMATS)
{
const char *names[] = { "none", "yuv444", "yuv422", "yuv420", "yuv400" };
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
"unsupported pixel format for YUVA %s, depth %u",
names[decoder->image->yuvFormat], depth);
return NULL;
}
stride = width * bpp;
data = g_malloc (stride * height);
if (depth == 8)
{
guchar *y_data = avifImagePlane (decoder->image, AVIF_CHAN_Y);
guchar *u_data = avifImagePlane (decoder->image, AVIF_CHAN_U);
guchar *v_data = avifImagePlane (decoder->image, AVIF_CHAN_V);
guchar *a_data = avifImagePlane (decoder->image, AVIF_CHAN_A);
guchar *dst_data = data;
gsize y_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
gsize u_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U);
gsize v_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V);
gsize a_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_A);
gsize dst_stride = stride;
for (int y = 0; y < height; y += Y_SUB)
{
for (int x = 0; x < width; x += X_SUB)
{
guint y_, u_, v_, a_;
u_ = u_data[x / X_SUB];
v_ = v_data[x / X_SUB];
for (int ys = 0; ys < Y_SUB && y + ys < height; ys++)
for (int xs = 0; xs < X_SUB && x + xs < width; xs++)
{
guchar *dest = &dst_data[4 * (x + xs) + dst_stride * ys];
y_ = y_data[x + xs + y_stride * ys];
a_ = a_data ? a_data[x + xs + a_stride * ys] : 0xff;
dest[0] = y_;
dest[1] = u_;
dest[2] = v_;
dest[3] = a_;
}
}
dst_data += Y_SUB * dst_stride;
y_data += Y_SUB * y_stride;
u_data += u_stride;
v_data += v_stride;
if (a_data)
a_data += a_stride;
}
}
else
{
guint16 *y_data = (guint16 *) avifImagePlane (decoder->image, AVIF_CHAN_Y);
guint16 *u_data = (guint16 *) avifImagePlane (decoder->image, AVIF_CHAN_U);
guint16 *v_data = (guint16 *) avifImagePlane (decoder->image, AVIF_CHAN_V);
guint16 *a_data = (guint16 *) avifImagePlane (decoder->image, AVIF_CHAN_A);
guint16 *dst_data = (guint16 *) data;
gsize y_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y) / 2;
gsize u_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U) / 2;
gsize v_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V) / 2;
gsize a_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_A) / 2;
gsize dst_stride = stride / 2;
for (int y = 0; y < height; y += Y_SUB)
{
for (int x = 0; x < width; x += X_SUB)
{
guint y_, u_, v_, a_;
u_ = u_data[x / X_SUB] << (16 - depth);
v_ = v_data[x / X_SUB] << (16 - depth);
for (int ys = 0; ys < Y_SUB && y + ys < height; ys++)
for (int xs = 0; xs < X_SUB && x + xs < width; xs++)
{
guint16 *dest = &dst_data[4 * (x + xs) + dst_stride * ys];
y_ = y_data[x + xs + y_stride * ys] << (16 - depth);
a_ = (a_data ? a_data[x + xs + a_stride * ys] : 0xffff) << (16 - depth);
dest[0] = y_ | (y_ >> depth);
dest[1] = u_ | (u_ >> depth);
dest[2] = v_ | (v_ >> depth);
dest[3] = a_ | (a_ >> depth);
}
}
dst_data += Y_SUB * dst_stride;
y_data += Y_SUB * y_stride;
u_data += u_stride;
v_data += v_stride;
}
}
builder = gdk_memory_texture_builder_new ();
bytes = g_bytes_new_take (data, stride * height);
gdk_memory_texture_builder_set_width (builder, width);
gdk_memory_texture_builder_set_height (builder, height);
gdk_memory_texture_builder_set_bytes (builder, bytes);
gdk_memory_texture_builder_set_stride (builder, stride);
gdk_memory_texture_builder_set_format (builder, format);
gdk_memory_texture_builder_set_color_state (builder, color_state);
texture = gdk_memory_texture_builder_build (builder);
g_bytes_unref (bytes);
g_object_unref (builder);
return texture;
}
/* }}} */
/* {{{ Public API */
GdkTexture *
gdk_load_avif (GBytes *bytes,
GError **error)
{
avifDecoder *decoder;
avifResult result;
GdkCicpParams *params;
GdkColorState *color_state = NULL;
GdkTexture *texture = NULL;
GError *local_error = NULL;
decoder = avifDecoderCreate ();
result = avifDecoderSetIOMemory (decoder,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
if (result != AVIF_RESULT_OK)
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
"avifDecoderSetIOFile failed: %u", result);
goto fail;
}
result = avifDecoderParse (decoder);
if (result != AVIF_RESULT_OK)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"avifDecoderParse failed: %u", result);
goto fail;
}
result = avifDecoderNextImage (decoder);
if (result != AVIF_RESULT_OK)
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
"avifDecoderNextImage failed: %u", result);
goto fail;
}
DEBUG ("load: depth %u", decoder->image->depth);
DEBUG ("load: cicp %u/%u/%u/%u",
decoder->image->colorPrimaries,
decoder->image->transferCharacteristics,
decoder->image->matrixCoefficients,
decoder->image->yuvRange);
params = gdk_cicp_params_new ();
gdk_cicp_params_set_color_primaries (params, decoder->image->colorPrimaries);
gdk_cicp_params_set_transfer_function (params, decoder->image->transferCharacteristics);
gdk_cicp_params_set_matrix_coefficients (params, decoder->image->matrixCoefficients);
gdk_cicp_params_set_range (params, decoder->image->yuvRange == AVIF_RANGE_LIMITED
? GDK_CICP_RANGE_NARROW
: GDK_CICP_RANGE_FULL);
color_state = gdk_cicp_params_build_color_state (params, error);
g_object_unref (params);
if (!color_state)
goto fail;
#ifdef HAVE_DMABUF
texture = gdk_avif_create_dmabuf_texture (decoder, color_state, &local_error);
if (!texture)
{
DEBUG ("load: creating dmabuf failed: %s", local_error->message);
g_clear_error (&local_error);
}
#endif
if (!texture)
texture = gdk_avif_create_memory_texture (decoder, color_state, error);
(gdk_color_state_unref) (color_state);
fail:
avifDecoderDestroy (decoder);
return texture;
}
static int
bytes_per_channel (GdkMemoryFormat format)
{
switch (format)
{
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_A8B8G8R8:
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
case GDK_MEMORY_G8A8_PREMULTIPLIED:
case GDK_MEMORY_G8A8:
case GDK_MEMORY_G8:
case GDK_MEMORY_A8:
case GDK_MEMORY_A8B8G8R8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8X8:
case GDK_MEMORY_X8R8G8B8:
case GDK_MEMORY_R8G8B8X8:
case GDK_MEMORY_X8B8G8R8:
return 1;
case GDK_MEMORY_R16G16B16:
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16:
case GDK_MEMORY_R16G16B16_FLOAT:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16_FLOAT:
case GDK_MEMORY_G16A16_PREMULTIPLIED:
case GDK_MEMORY_G16A16:
case GDK_MEMORY_G16:
case GDK_MEMORY_A16:
case GDK_MEMORY_A16_FLOAT:
return 2;
case GDK_MEMORY_R32G32B32_FLOAT:
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
case GDK_MEMORY_R32G32B32A32_FLOAT:
case GDK_MEMORY_A32_FLOAT:
return 4;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
}
}
GBytes *
gdk_save_avif (GdkTexture *texture)
{
uint32_t width, height, depth;
GdkColorState *color_state;
const GdkCicp *cicp;
avifEncoder *encoder;
avifImage *image = NULL;
avifRWData output = AVIF_DATA_EMPTY;
GdkTextureDownloader *downloader;
GBytes *bytes = NULL;
gsize stride;
GBytes *out_bytes = NULL;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
if (bytes_per_channel (gdk_texture_get_format (texture)) == 1)
depth = 8;
else
depth = 12;
color_state = gdk_texture_get_color_state (texture);
cicp = gdk_color_state_get_cicp (color_state);
DEBUG ("save: depth %u", depth);
DEBUG ("save: cicp %u/%u/%u/%u",
cicp->color_primaries,
cicp->transfer_function,
cicp->matrix_coefficients,
cicp->range);
downloader = gdk_texture_downloader_new (texture);
if (depth == 8)
gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R8G8B8A8);
else
gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R16G16B16A16);
gdk_texture_downloader_set_color_state (downloader, gdk_texture_get_color_state (texture));
bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
gdk_texture_downloader_free (downloader);
if (cicp->matrix_coefficients != 0)
{
/* some form of yuv */
image = avifImageCreate (width, height, depth, AVIF_PIXEL_FORMAT_YUV444);
image->colorPrimaries = cicp->color_primaries;
image->transferCharacteristics = cicp->transfer_function;
image->matrixCoefficients = cicp->matrix_coefficients;
image->yuvRange = cicp->range == GDK_CICP_RANGE_NARROW
? AVIF_RANGE_LIMITED
: AVIF_RANGE_FULL;
avifImageAllocatePlanes (image, AVIF_PLANES_YUV);
if (depth == 8)
{
for (gsize y = 0; y < height; y++)
{
const guchar *orig = (guchar *) g_bytes_get_data (bytes, NULL) + y * stride;
guchar *y_ = avifImagePlane (image, AVIF_CHAN_Y) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_Y);
guchar *u_ = avifImagePlane (image, AVIF_CHAN_U) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_U);
guchar *v_ = avifImagePlane (image, AVIF_CHAN_V) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_V);
for (gsize x = 0; x < width; x++)
{
y_[x] = orig[4*x + 0];
u_[x] = orig[4*x + 1];
v_[x] = orig[4*x + 2];
}
}
}
else
{
for (gsize y = 0; y < height; y++)
{
const guint16 *orig = (guint16 *) ((guchar *) g_bytes_get_data (bytes, NULL) + y * stride);
guint16 *y_ = (guint16 *) (avifImagePlane (image, AVIF_CHAN_Y) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_Y));
guint16 *u_ = (guint16 *) (avifImagePlane (image, AVIF_CHAN_U) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_U));
guint16 *v_ = (guint16 *) (avifImagePlane (image, AVIF_CHAN_V) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_V));
for (gsize x = 0; x < width; x++)
{
y_[x] = orig[4*x + 0] >> (16 - depth);
u_[x] = orig[4*x + 1] >> (16 - depth);
v_[x] = orig[4*x + 2] >> (16 - depth);
}
}
}
}
else
{
avifRGBImage rgb;
image = avifImageCreate (width, height, depth, AVIF_PIXEL_FORMAT_YUV444);
image->colorPrimaries = cicp->color_primaries;
image->transferCharacteristics = cicp->transfer_function;
image->matrixCoefficients = cicp->matrix_coefficients;
image->yuvRange = cicp->range == GDK_CICP_RANGE_NARROW
? AVIF_RANGE_LIMITED
: AVIF_RANGE_FULL;
avifRGBImageSetDefaults (&rgb, image);
avifRGBImageAllocatePixels (&rgb);
if (depth == 8)
{
for (gsize y = 0; y < height; y++)
{
const guchar *orig = (guchar *) g_bytes_get_data (bytes, NULL) + y * stride;
guchar *pixels = rgb.pixels + y * rgb.rowBytes;
for (gsize x = 0; x < width; x++)
{
pixels[4*x + 0] = orig[4*x + 0];
pixels[4*x + 1] = orig[4*x + 1];
pixels[4*x + 2] = orig[4*x + 2];
pixels[4*x + 3] = orig[4*x + 3];
}
}
}
else
{
for (gsize y = 0; y < height; y++)
{
const guint16 *orig = (const guint16 *) ((guchar *) g_bytes_get_data (bytes, NULL) + y * stride);
guint16 *pixels = (guint16 *) (rgb.pixels + y * rgb.rowBytes);
for (gsize x = 0; x < width; x++)
{
pixels[4*x + 0] = orig[4*x + 0] >> (16 - depth);
pixels[4*x + 1] = orig[4*x + 1] >> (16 - depth);
pixels[4*x + 2] = orig[4*x + 2] >> (16 - depth);
pixels[4*x + 3] = orig[4*x + 3] >> (16 - depth);
}
}
}
avifImageRGBToYUV(image, &rgb);
avifRGBImageFreePixels (&rgb);
}
DEBUG ("save: cicp in image %u/%u/%u/%u",
image->colorPrimaries,
image->transferCharacteristics,
image->matrixCoefficients,
image->yuvRange);
encoder = avifEncoderCreate ();
if (avifEncoderWrite (encoder, image, &output) != AVIF_RESULT_OK)
goto fail;
out_bytes = g_bytes_new_take (output.data, output.size);
fail:
g_clear_pointer (&bytes, g_bytes_unref);
avifEncoderDestroy (encoder);
if (image)
avifImageDestroy (image);
return out_bytes;
}
gboolean
gdk_is_avif (GBytes *bytes)
{
avifROData input;
input.data = g_bytes_get_data (bytes, &input.size);
return avifPeekCompatibleFileType (&input);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */
+28
View File
@@ -0,0 +1,28 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2024 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gdk.h>
#include <gio/gio.h>
GdkTexture *gdk_load_avif (GBytes *bytes,
GError **error);
GBytes *gdk_save_avif (GdkTexture *texture);
gboolean gdk_is_avif (GBytes *bytes);
+41 -28
View File
@@ -149,37 +149,39 @@ gdk_load_jpeg (GBytes *input_bytes,
g_bytes_get_size (input_bytes));
jpeg_read_header (&info, TRUE);
if (info.jpeg_color_space == JCS_GRAYSCALE)
{
color_state = GDK_COLOR_STATE_SRGB;
info.out_color_space = JCS_GRAYSCALE;
format = GDK_MEMORY_G8;
}
else if (info.jpeg_color_space == JCS_YCbCr)
{
color_state = GDK_COLOR_STATE_JPEG;
info.out_color_space = JCS_YCbCr;
format = GDK_MEMORY_R8G8B8;
}
else if (info.jpeg_color_space == JCS_CMYK)
{
color_state = GDK_COLOR_STATE_SRGB;
info.out_color_space = JCS_CMYK;
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
}
else
{
color_state = GDK_COLOR_STATE_SRGB;
info.out_color_space = JCS_RGB;
format = GDK_MEMORY_R8G8B8;
}
jpeg_start_decompress (&info);
width = info.output_width;
height = info.output_height;
stride = gdk_memory_format_bytes_per_pixel (format) * width;
color_state = GDK_COLOR_STATE_SRGB;
switch ((int)info.out_color_space)
{
case JCS_GRAYSCALE:
stride = width;
data = g_try_malloc_n (stride, height);
format = GDK_MEMORY_G8;
break;
case JCS_RGB:
stride = 3 * width;
data = g_try_malloc_n (stride, height);
format = GDK_MEMORY_R8G8B8;
break;
case JCS_CMYK:
stride = 4 * width;
data = g_try_malloc_n (stride, height);
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
break;
default:
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
_("Unsupported JPEG colorspace (%d)"), info.out_color_space);
jpeg_destroy_decompress (&info);
return NULL;
}
data = g_try_malloc_n (stride, height);
if (!data)
{
@@ -215,7 +217,6 @@ gdk_load_jpeg (GBytes *input_bytes,
texture = gdk_memory_texture_builder_build (builder);
gdk_color_state_unref (color_state);
g_object_unref (builder);
g_bytes_unref (bytes);
@@ -239,6 +240,7 @@ gdk_save_jpeg (GdkTexture *texture)
gsize texstride;
guchar *row;
int width, height;
GdkColorState *color_state;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
@@ -268,13 +270,24 @@ gdk_save_jpeg (GdkTexture *texture)
jpeg_set_defaults (&info);
jpeg_set_quality (&info, 75, TRUE);
color_state = gdk_texture_get_color_state (texture);
if (gdk_color_state_equal (color_state, GDK_COLOR_STATE_JPEG))
{
info.in_color_space = JCS_YCbCr;
}
else
{
info.in_color_space = JCS_RGB;
color_state = GDK_COLOR_STATE_SRGB;
}
info.mem->max_memory_to_use = 300 * 1024 * 1024;
jpeg_mem_dest (&info, &data, &size);
gdk_texture_downloader_init (&downloader, texture);
gdk_texture_downloader_set_format (&downloader, GDK_MEMORY_R8G8B8);
gdk_texture_downloader_set_color_state (&downloader, GDK_COLOR_STATE_SRGB);
gdk_texture_downloader_set_color_state (&downloader, color_state);
texbytes = gdk_texture_downloader_download_bytes (&downloader, &texstride);
gdk_texture_downloader_finish (&downloader);
texdata = g_bytes_get_data (texbytes, NULL);
+2 -21
View File
@@ -107,32 +107,13 @@ _gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
cairo_clip (cr);
}
/* If we have some exposed transparent area in the damage region,
* we need to clear the existing content first to leave an transparent
* area for cairo. We use (surface_bounds or damage)-(opaque) to get
* the smallest set of rectangles we need to clear as it's expensive.
*/
if (!opaque)
{
cairo_region_t *transparent;
cairo_rectangle_int_t r = { 0, 0, width/scale, height/scale };
cairo_save (cr);
if (damage != NULL)
cairo_region_get_extents (damage, &r);
transparent = cairo_region_create_rectangle (&r);
if (surface->opaque_region)
cairo_region_subtract (transparent, surface->opaque_region);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
if (!cairo_region_is_empty (transparent))
{
gdk_cairo_region (cr, transparent);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_fill (cr);
}
cairo_region_destroy (transparent);
cairo_restore (cr);
}
+1 -1
View File
@@ -242,7 +242,7 @@ gdk_macos_gl_context_allocate (GdkMacosGLContext *self)
return;
/* Alter to an opaque surface if necessary */
opaque = _gdk_macos_surface_is_opaque (GDK_MACOS_SURFACE (surface));
opaque = gdk_surface_is_opaque (surface);
if (opaque != self->last_opaque)
{
self->last_opaque = !!opaque;
-1
View File
@@ -86,7 +86,6 @@ CGDirectDisplayID _gdk_macos_surface_get_screen_id (GdkMacosSurface
const char *_gdk_macos_surface_get_title (GdkMacosSurface *self);
void _gdk_macos_surface_set_title (GdkMacosSurface *self,
const char *title);
gboolean _gdk_macos_surface_is_opaque (GdkMacosSurface *self);
NSView *_gdk_macos_surface_get_view (GdkMacosSurface *self);
gboolean _gdk_macos_surface_get_modal_hint (GdkMacosSurface *self);
void _gdk_macos_surface_set_modal_hint (GdkMacosSurface *self,
-23
View File
@@ -553,29 +553,6 @@ gdk_macos_surface_init (GdkMacosSurface *self)
self->monitors = g_ptr_array_new_with_free_func (g_object_unref);
}
gboolean
_gdk_macos_surface_is_opaque (GdkMacosSurface *self)
{
GdkSurface *surface = (GdkSurface *)self;
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), FALSE);
if (surface->opaque_region != NULL &&
cairo_region_num_rectangles (surface->opaque_region) == 1)
{
cairo_rectangle_int_t extents;
cairo_region_get_extents (surface->opaque_region, &extents);
return (extents.x == 0 &&
extents.y == 0 &&
extents.width == GDK_SURFACE (self)->width &&
extents.height == GDK_SURFACE (self)->height);
}
return FALSE;
}
const char *
_gdk_macos_surface_get_title (GdkMacosSurface *self)
{
+7
View File
@@ -74,6 +74,12 @@ gdk_public_sources = files([
'loaders/gdkjpeg.c',
])
if avif_dep.found()
gdk_public_sources += [
'loaders/gdkavif.c'
]
endif
gdk_public_headers = files([
'gdk.h',
'gdkapplaunchcontext.h',
@@ -237,6 +243,7 @@ gdk_deps = [
png_dep,
tiff_dep,
jpeg_dep,
avif_dep,
]
if profiler_enabled
+36 -10
View File
@@ -1,9 +1,10 @@
#include "config.h"
#include "gdkwaylandcolor-private.h"
#include "gdksurface-wayland-private.h"
#include <gdk/wayland/xx-color-management-v4-client-protocol.h>
typedef struct _ImageDescription ImageDescription;
static uint primaries_map[] = {
[XX_COLOR_MANAGER_V4_PRIMARIES_SRGB] = 1,
[XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M] = 4,
@@ -426,11 +427,12 @@ struct _GdkWaylandColorSurface
GdkWaylandColor *color;
struct xx_color_management_surface_v4 *surface;
struct xx_color_management_feedback_surface_v4 *feedback;
ImageDescription *current_desc;
GdkColorStateChanged callback;
gpointer data;
};
typedef struct
struct _ImageDescription
{
GdkWaylandColorSurface *surface;
@@ -460,7 +462,7 @@ typedef struct
unsigned int has_target_luminance : 1;
unsigned int has_target_max_cll : 1;
unsigned int has_target_max_fall : 1;
} ImageDescription;
};
static GdkColorState *
gdk_color_state_from_image_description_bits (ImageDescription *desc)
@@ -480,6 +482,21 @@ gdk_color_state_from_image_description_bits (ImageDescription *desc)
return NULL;
}
static void
gdk_wayland_color_surface_clear_image_desc (GdkWaylandColorSurface *self)
{
ImageDescription *desc = self->current_desc;
if (desc == NULL)
return;
g_clear_pointer (&desc->image_desc, xx_image_description_v4_destroy);
g_clear_pointer (&desc->info, xx_image_description_info_v4_destroy);
g_free (desc);
self->current_desc = NULL;
}
static void
image_desc_info_done (void *data,
struct xx_image_description_info_v4 *info)
@@ -488,6 +505,8 @@ image_desc_info_done (void *data,
GdkWaylandColorSurface *self = desc->surface;
GdkColorState *cs;
g_assert (self->current_desc == desc);
cs = gdk_color_state_from_image_description_bits (desc);
if (cs)
{
@@ -498,7 +517,7 @@ image_desc_info_done (void *data,
else
{
cs = GDK_COLOR_STATE_SRGB;
xx_image_description_v4_destroy (desc->image_desc);
g_clear_pointer (&desc->image_desc, xx_image_description_v4_destroy);
}
if (self->callback)
@@ -506,8 +525,7 @@ image_desc_info_done (void *data,
gdk_color_state_unref (cs);
xx_image_description_info_v4_destroy (desc->info);
g_free (desc);
gdk_wayland_color_surface_clear_image_desc (self);
}
static void
@@ -663,10 +681,11 @@ image_desc_failed (void *data,
ImageDescription *desc = data;
GdkWaylandColorSurface *self = desc->surface;
g_assert (self->current_desc == desc);
self->callback (self, GDK_COLOR_STATE_SRGB, self->data);
xx_image_description_v4_destroy (desc->image_desc);
g_free (desc);
gdk_wayland_color_surface_clear_image_desc (self);
}
static void
@@ -678,13 +697,14 @@ image_desc_ready (void *data,
GdkWaylandColorSurface *self = desc->surface;
GdkColorState *cs;
g_assert (self->current_desc == desc);
cs = g_hash_table_lookup (self->color->id_to_cs, GUINT_TO_POINTER (identity));
if (cs)
{
self->callback (self, cs, self->data);
xx_image_description_v4_destroy (desc->image_desc);
g_free (desc);
gdk_wayland_color_surface_clear_image_desc (self);
return;
}
@@ -709,9 +729,13 @@ preferred_changed (void *data,
if (!self->callback)
return;
/* If there's still an ongoing query, cancel it. It's outdated. */
gdk_wayland_color_surface_clear_image_desc (self);
desc = g_new0 (ImageDescription, 1);
desc->surface = self;
self->current_desc = desc;
desc->image_desc = xx_color_management_feedback_surface_v4_get_preferred (self->feedback);
@@ -749,6 +773,8 @@ gdk_wayland_color_surface_new (GdkWaylandColor *color,
void
gdk_wayland_color_surface_free (GdkWaylandColorSurface *self)
{
gdk_wayland_color_surface_clear_image_desc (self);
xx_color_management_surface_v4_destroy (self->surface);
xx_color_management_feedback_surface_v4_destroy (self->feedback);
+3 -16
View File
@@ -120,20 +120,6 @@ maybe_wait_for_vblank (GdkDisplay *display,
}
}
static GLXDrawable
gdk_x11_gl_context_glx_get_drawable (GdkX11GLContextGLX *self)
{
GdkDrawContext *draw_context = GDK_DRAW_CONTEXT (self);
GdkSurface *surface;
if (gdk_draw_context_is_in_frame (draw_context))
surface = gdk_draw_context_get_surface (draw_context);
else
surface = GDK_X11_DISPLAY (gdk_draw_context_get_display (draw_context))->leader_gdk_surface;
return gdk_x11_surface_get_glx_drawable (surface);
}
static void
gdk_x11_gl_context_glx_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted)
@@ -318,10 +304,11 @@ gdk_x11_gl_context_glx_get_damage (GdkGLContext *context)
if (display_x11->has_glx_buffer_age)
{
GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (context);
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
gdk_gl_context_make_current (context);
glXQueryDrawable (dpy, gdk_x11_gl_context_glx_get_drawable (self),
glXQueryDrawable (dpy,
gdk_x11_surface_get_glx_drawable (surface),
GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
if (buffer_age > 0 && buffer_age <= GDK_GL_MAX_TRACKED_BUFFERS)
+2 -2
View File
@@ -934,7 +934,7 @@ gsk_broadway_renderer_render (GskRenderer *renderer,
self->node_lookup = g_hash_table_new (g_direct_hash, g_direct_equal);
gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->draw_context), update_area);
gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->draw_context), GDK_MEMORY_U8, update_area, NULL);
/* These are owned by the draw context between begin and end, but
cache them here for easier access during the render */
@@ -946,7 +946,7 @@ gsk_broadway_renderer_render (GskRenderer *renderer,
self->nodes = NULL;
self->node_textures = NULL;
gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->draw_context));
gdk_draw_context_end_frame_full (GDK_DRAW_CONTEXT (self->draw_context));
if (self->last_node_lookup)
g_hash_table_unref (self->last_node_lookup);
+4 -4
View File
@@ -133,7 +133,7 @@ void half_to_float4 (const guint16 h[4], float f[4]) __attribute__((ifunc ("reso
void float_to_half (const float *f, guint16 *h, int n) __attribute__((ifunc ("resolve_float_to_half")));
void half_to_float (const guint16 *h, float *f, int n) __attribute__((ifunc ("resolve_half_to_float")));
static void * __attribute__ ((no_sanitize_address))
static void * __attribute__ ((no_sanitize_address)) G_GNUC_UNUSED
resolve_float_to_half4 (void)
{
__builtin_cpu_init ();
@@ -143,7 +143,7 @@ resolve_float_to_half4 (void)
return float_to_half4_c;
}
static void * __attribute__ ((no_sanitize_address))
static void * __attribute__ ((no_sanitize_address)) G_GNUC_UNUSED
resolve_half_to_float4 (void)
{
__builtin_cpu_init ();
@@ -153,7 +153,7 @@ resolve_half_to_float4 (void)
return half_to_float4_c;
}
static void * __attribute__ ((no_sanitize_address))
static void * __attribute__ ((no_sanitize_address)) G_GNUC_UNUSED
resolve_float_to_half (void)
{
__builtin_cpu_init ();
@@ -163,7 +163,7 @@ resolve_float_to_half (void)
return float_to_half_c;
}
static void * __attribute__ ((no_sanitize_address))
static void * __attribute__ ((no_sanitize_address)) G_GNUC_UNUSED
resolve_half_to_float (void)
{
__builtin_cpu_init ();
+12
View File
@@ -43,6 +43,7 @@
#include <gdk/gdkmemoryformatprivate.h>
#include <gdk/gdkprofilerprivate.h>
#include <gdk/gdktextureprivate.h>
#include <gdk/gdkdmabufeglprivate.h>
#include <gdk/gdkmemoryformatprivate.h>
#include <gdk/gdkdmabuftextureprivate.h>
@@ -217,6 +218,9 @@ gsk_gl_driver_dispose (GObject *object)
g_assert (GSK_IS_GL_DRIVER (self));
g_assert (self->in_frame == FALSE);
if (self->shared_command_queue)
gsk_gl_command_queue_make_current (self->shared_command_queue);
#define GSK_GL_NO_UNIFORMS
#define GSK_GL_SHADER_RESOURCE(name)
#define GSK_GL_SHADER_STRING(str)
@@ -811,6 +815,8 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
gboolean external;
GdkMemoryFormat format;
gboolean premultiply;
GdkColorState *color_state;
int color_space, range;
gdk_gl_context_make_current (context);
@@ -828,10 +834,16 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
dmabuf = gdk_dmabuf_texture_get_dmabuf (texture);
format = gdk_texture_get_format (GDK_TEXTURE (texture));
premultiply = gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT;
color_state = gdk_texture_get_color_state (GDK_TEXTURE (texture));
gdk_dmabuf_get_egl_yuv_hints (dmabuf, color_state, &color_space, &range);
texture_id = gdk_gl_context_import_dmabuf (context,
width, height,
dmabuf,
color_space,
range,
&external);
if (texture_id == 0)
return 0;
+17 -69
View File
@@ -192,12 +192,12 @@ gsk_gl_renderer_realize (GskRenderer *renderer,
g_assert (self->context == NULL);
g_assert (self->command_queue == NULL);
if (surface == NULL)
context = gdk_display_create_gl_context (display, error);
else
context = gdk_surface_create_gl_context (surface, error);
if (!gdk_display_prepare_gl (display, error))
goto failure;
if (!context || !gdk_gl_context_realize (context, error))
context = gdk_gl_context_new (display, surface, surface != NULL);
if (!gdk_gl_context_realize (context, error))
goto failure;
api = gdk_gl_context_get_api (context);
@@ -258,6 +258,8 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer)
g_clear_object (&self->driver);
g_clear_object (&self->command_queue);
g_clear_object (&self->context);
gdk_gl_context_clear_current ();
}
static cairo_region_t *
@@ -293,65 +295,6 @@ get_render_region (GdkSurface *surface,
return cairo_region_create_rectangle (&extents);
}
static gboolean
update_area_requires_clear (GdkSurface *surface,
const cairo_region_t *update_area)
{
cairo_rectangle_int_t rect;
guint n_rects;
g_assert (GDK_IS_SURFACE (surface));
/* No opaque region, assume we have to clear */
if (surface->opaque_region == NULL)
return TRUE;
/* If the update_area is the whole surface, then clear it
* because many drivers optimize for this by avoiding extra
* work to reload any contents.
*/
if (update_area == NULL)
return TRUE;
if (cairo_region_num_rectangles (update_area) == 1)
{
cairo_region_get_rectangle (update_area, 0, &rect);
if (rect.x == 0 &&
rect.y == 0 &&
rect.width == surface->width &&
rect.height == surface->height)
return TRUE;
}
/* If the entire surface is opaque, then we can skip clearing
* (with the exception of full surface clearing above).
*/
if (cairo_region_num_rectangles (surface->opaque_region) == 1)
{
cairo_region_get_rectangle (surface->opaque_region, 0, &rect);
if (rect.x == 0 &&
rect.y == 0 &&
rect.width == surface->width &&
rect.height == surface->height)
return FALSE;
}
/* If any update_area rectangle overlaps our transparent
* regions, then we need to clear the area.
*/
n_rects = cairo_region_num_rectangles (update_area);
for (guint i = 0; i < n_rects; i++)
{
cairo_region_get_rectangle (update_area, i, &rect);
if (cairo_region_contains_rectangle (surface->opaque_region, &rect) != CAIRO_REGION_OVERLAP_IN)
return TRUE;
}
return FALSE;
}
static void
gsk_gl_renderer_render (GskRenderer *renderer,
GskRenderNode *root,
@@ -362,7 +305,8 @@ gsk_gl_renderer_render (GskRenderer *renderer,
graphene_rect_t viewport;
GskGLRenderJob *job;
GdkSurface *surface;
gboolean clear_framebuffer;
graphene_rect_t opaque_tmp;
const graphene_rect_t *opaque;
float scale;
g_assert (GSK_IS_GL_RENDERER (renderer));
@@ -382,23 +326,27 @@ gsk_gl_renderer_render (GskRenderer *renderer,
viewport.size.width = gdk_surface_get_width (surface) * scale;
viewport.size.height = gdk_surface_get_height (surface) * scale;
if (gsk_render_node_get_opaque_rect (root, &opaque_tmp))
opaque = &opaque_tmp;
else
opaque = NULL;
gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->context),
gsk_render_node_get_preferred_depth (root),
update_area);
update_area,
opaque);
gdk_gl_context_make_current (self->context);
/* Must be called *AFTER* gdk_draw_context_begin_frame() */
render_region = get_render_region (surface, self->context);
clear_framebuffer = update_area_requires_clear (surface, render_region);
gsk_gl_driver_begin_frame (self->driver, self->command_queue);
job = gsk_gl_render_job_new (self->driver, &viewport, scale, render_region, 0, clear_framebuffer);
job = gsk_gl_render_job_new (self->driver, &viewport, scale, render_region, 0, TRUE);
gsk_gl_render_job_render (job, root);
gsk_gl_driver_end_frame (self->driver);
gsk_gl_render_job_free (job);
gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->context));
gdk_draw_context_end_frame_full (GDK_DRAW_CONTEXT (self->context));
gsk_gl_driver_after_frame (self->driver);
+16 -4
View File
@@ -2182,6 +2182,10 @@ gsk_gl_render_job_visit_unblurred_inset_shadow_node (GskGLRenderJob *job,
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow)))
{
const GdkRGBA rgba;
gdk_color_to_float (gsk_inset_shadow_node_get_color2 (node), GDK_COLOR_STATE_SRGB, (float *) &rgba);
gsk_gl_program_set_uniform_rounded_rect (job->current_program,
UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0,
&transformed_outline);
@@ -2192,7 +2196,7 @@ gsk_gl_render_job_visit_unblurred_inset_shadow_node (GskGLRenderJob *job,
UNIFORM_INSET_SHADOW_OFFSET, 0,
gsk_inset_shadow_node_get_dx (node),
gsk_inset_shadow_node_get_dy (node));
rgba_to_half (gsk_inset_shadow_node_get_color (node), color);
rgba_to_half (&rgba, color);
gsk_gl_render_job_draw_rect_with_color (job, &node->bounds, color);
gsk_gl_render_job_end_draw (job);
}
@@ -2285,6 +2289,10 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job,
/* Actual inset shadow outline drawing */
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow)))
{
const GdkRGBA rgba;
gdk_color_to_float (gsk_inset_shadow_node_get_color2 (node), GDK_COLOR_STATE_SRGB, (float *) &rgba);
gsk_gl_program_set_uniform_rounded_rect (job->current_program,
UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0,
&transformed_outline);
@@ -2295,7 +2303,7 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job,
UNIFORM_INSET_SHADOW_OFFSET, 0,
offset_x * scale_x,
offset_y * scale_y);
rgba_to_half (gsk_inset_shadow_node_get_color (node), color);
rgba_to_half (&rgba, color);
gsk_gl_render_job_draw_with_color (job,
0, 0, texture_width, texture_height,
color);
@@ -2378,6 +2386,7 @@ gsk_gl_render_job_visit_unblurred_outset_shadow_node (GskGLRenderJob *job,
float spread = gsk_outset_shadow_node_get_spread (node);
float dx = gsk_outset_shadow_node_get_dx (node);
float dy = gsk_outset_shadow_node_get_dy (node);
GdkRGBA rgba;
guint16 color[4];
const float edge_sizes[] = { // Top, right, bottom, left
spread - dy, spread + dx, spread + dy, spread - dx
@@ -2389,7 +2398,8 @@ gsk_gl_render_job_visit_unblurred_outset_shadow_node (GskGLRenderJob *job,
{ outline->corner[3].width + spread - dx, outline->corner[3].height + spread + dy },
};
rgba_to_half (gsk_outset_shadow_node_get_color (node), color);
gdk_color_to_float (gsk_outset_shadow_node_get_color2 (node), GDK_COLOR_STATE_SRGB, (float *) &rgba);
rgba_to_half (&rgba, color);
gsk_gl_render_job_translate_rounded_rect (job, outline, &transformed_outline);
@@ -2473,11 +2483,13 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job,
int blurred_texture_id;
int cached_tid;
gboolean do_slicing;
GdkRGBA rgba;
guint16 color[4];
float half_width = outline->bounds.size.width / 2;
float half_height = outline->bounds.size.height / 2;
rgba_to_half (gsk_outset_shadow_node_get_color (node), color);
gdk_color_to_float (gsk_outset_shadow_node_get_color2 (node), GDK_COLOR_STATE_SRGB, (float *) &rgba);
rgba_to_half (&rgba, color);
/* scaled_outline is the minimal outline we need to draw the given drop shadow,
* enlarged by the spread and offset by the blur radius. */
+40 -2
View File
@@ -10,6 +10,7 @@
#include "gskglimageprivate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkdmabufeglprivate.h"
#include "gdkglcontextprivate.h"
#include "gdkgltextureprivate.h"
@@ -92,7 +93,7 @@ gsk_gl_frame_upload_texture (GskGpuFrame *frame,
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)
@@ -105,19 +106,56 @@ gsk_gl_frame_upload_texture (GskGpuFrame *frame,
{
gboolean external;
GLuint tex_id;
int color_space_hint = 0;
int range_hint = 0;
#if defined (HAVE_DMABUF) && defined (HAVE_EGL)
gdk_dmabuf_get_egl_yuv_hints (gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture)),
gdk_texture_get_color_state (texture),
&color_space_hint,
&range_hint);
#endif
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)),
color_space_hint,
range_hint,
&external);
if (tex_id)
{
GskGpuImageFlags flags = 0;
if (external)
flags |= GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT;
#if defined (HAVE_DMABUF) && defined (HAVE_EGL)
switch (color_space_hint)
{
case EGL_ITU_REC709_EXT:
flags |= GSK_GPU_IMAGE_BT709;
break;
case EGL_ITU_REC601_EXT:
flags |= GSK_GPU_IMAGE_BT601;
break;
case EGL_ITU_REC2020_EXT:
flags |= GSK_GPU_IMAGE_BT2020;
break;
default:
break;
}
if (range_hint == EGL_YUV_NARROW_RANGE_EXT)
flags |= GSK_GPU_IMAGE_NARROW_RANGE;
#endif
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));
flags);
}
}
+25 -13
View File
@@ -56,18 +56,22 @@ static const GskGpuShaderOpClass GSK_GPU_BLUR_OP_CLASS = {
static void
gsk_gpu_blur_op_full (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
guint32 variation,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
guint32 variation,
const GskGpuShaderImage *image,
const graphene_vec2_t *blur_direction,
float blur_color[4])
const GdkColor *blur_color)
{
GskGpuBlurInstance *instance;
GdkColorState *alt;
alt = gsk_gpu_color_states_find (ccs, blur_color);
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_BLUR_OP_CLASS,
color_states,
gsk_gpu_color_states_create (ccs, TRUE, alt, variation & VARIATION_COLORIZE ? FALSE : TRUE),
variation,
clip,
(GskGpuImage *[1]) { image->image },
@@ -77,41 +81,49 @@ gsk_gpu_blur_op_full (GskGpuFrame *frame,
gsk_gpu_rect_to_float (image->coverage, offset, instance->rect);
gsk_gpu_rect_to_float (image->bounds, offset, instance->tex_rect);
graphene_vec2_to_float (blur_direction, instance->blur_direction);
gsk_gpu_vec4_to_float (blur_color, instance->blur_color);
gsk_gpu_color_to_float (blur_color, alt, opacity, instance->blur_color);
}
void
gsk_gpu_blur_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
const GskGpuShaderImage *image,
const graphene_vec2_t *blur_direction)
{
GdkColor blur_color;
gdk_color_init (&blur_color, ccs, (float[]) { 1, 1, 1, 1 });
gsk_gpu_blur_op_full (frame,
clip,
color_states,
0,
ccs,
opacity,
offset,
0,
image,
blur_direction,
(float[4]) { 1, 1, 1, 1 });
&blur_color);
gdk_color_finish (&blur_color);
}
void
gsk_gpu_blur_shadow_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
const GskGpuShaderImage *image,
const graphene_vec2_t *blur_direction,
float shadow_color[4])
const GdkColor *shadow_color)
{
gsk_gpu_blur_op_full (frame,
clip,
color_states,
VARIATION_COLORIZE,
ccs,
opacity,
offset,
VARIATION_COLORIZE,
image,
blur_direction,
shadow_color);
+5 -3
View File
@@ -8,18 +8,20 @@ G_BEGIN_DECLS
void gsk_gpu_blur_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
const GskGpuShaderImage *image,
const graphene_vec2_t *blur_direction);
void gsk_gpu_blur_shadow_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
const GskGpuShaderImage *image,
const graphene_vec2_t *blur_direction,
float shadow_color[4]);
const GdkColor *shadow_color);
G_END_DECLS
+15 -5
View File
@@ -97,19 +97,29 @@ static const GskGpuShaderOpClass GSK_GPU_BORDER_OP_CLASS = {
void
gsk_gpu_border_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
const GskRoundedRect *outline,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
const GskRoundedRect *outline,
const graphene_point_t *inside_offset,
const float widths[4],
const float colors[4][4])
const GdkColor colors[4])
{
GskGpuBorderInstance *instance;
guint i;
GdkColorState *alt;
if (GDK_IS_DEFAULT_COLOR_STATE (colors[0].color_state) &&
gdk_color_state_equal (colors[0].color_state, colors[1].color_state) &&
gdk_color_state_equal (colors[0].color_state, colors[2].color_state) &&
gdk_color_state_equal (colors[0].color_state, colors[3].color_state))
alt = colors[0].color_state;
else
alt = ccs;
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_BORDER_OP_CLASS,
color_states,
gsk_gpu_color_states_create (ccs, TRUE, alt, FALSE),
0,
clip,
NULL,
@@ -121,7 +131,7 @@ gsk_gpu_border_op (GskGpuFrame *frame,
for (i = 0; i < 4; i++)
{
instance->border_widths[i] = widths[i];
gsk_gpu_vec4_to_float (colors[i], &instance->border_colors[4 * i]);
gsk_gpu_color_to_float (&colors[i], alt, opacity, &instance->border_colors[4 * i]);
}
instance->offset[0] = inside_offset->x;
instance->offset[1] = inside_offset->y;
+5 -3
View File
@@ -2,6 +2,7 @@
#include "gskgputypesprivate.h"
#include "gsktypes.h"
#include "gdkcolorprivate.h"
#include <graphene.h>
@@ -9,12 +10,13 @@ G_BEGIN_DECLS
void gsk_gpu_border_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
const GskRoundedRect *outline,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
const GskRoundedRect *outline,
const graphene_point_t *inside_offset,
const float widths[4],
const float colors[4][4]);
const GdkColor colors[4]);
G_END_DECLS
+9 -5
View File
@@ -76,24 +76,28 @@ static const GskGpuShaderOpClass GSK_GPU_BOX_SHADOW_OP_CLASS = {
void
gsk_gpu_box_shadow_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
gboolean inset,
const graphene_rect_t *bounds,
const GskRoundedRect *outline,
const graphene_point_t *shadow_offset,
float spread,
float blur_radius,
const graphene_point_t *offset,
const float color[4])
const GdkColor *color)
{
GskGpuBoxshadowInstance *instance;
GdkColorState *alt;
/* Use border shader for no blurring */
g_return_if_fail (blur_radius > 0.0f);
alt = gsk_gpu_color_states_find (ccs, color);
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_BOX_SHADOW_OP_CLASS,
color_states,
gsk_gpu_color_states_create (ccs, TRUE, alt, FALSE),
inset ? VARIATION_INSET : 0,
clip,
NULL,
@@ -102,7 +106,7 @@ gsk_gpu_box_shadow_op (GskGpuFrame *frame,
gsk_gpu_rect_to_float (bounds, offset, instance->bounds);
gsk_rounded_rect_to_float (outline, offset, instance->outline);
gsk_gpu_vec4_to_float (color, instance->color);
gsk_gpu_color_to_float (color, alt, opacity, instance->color);
instance->shadow_offset[0] = shadow_offset->x;
instance->shadow_offset[1] = shadow_offset->y;
instance->shadow_spread = spread;
+5 -3
View File
@@ -2,6 +2,7 @@
#include "gskgputypesprivate.h"
#include "gsktypes.h"
#include "gdkcolorprivate.h"
#include <graphene.h>
@@ -9,15 +10,16 @@ G_BEGIN_DECLS
void gsk_gpu_box_shadow_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
gboolean inset,
const graphene_rect_t *bounds,
const GskRoundedRect *outline,
const graphene_point_t *shadow_offset,
float spread,
float blur_radius,
const graphene_point_t *offset,
const float color[4]);
const GdkColor *color);
G_END_DECLS
+1 -1
View File
@@ -682,7 +682,7 @@ gsk_gpu_cache_lookup_tile (GskGpuCache *self,
gsk_gpu_cached_use (self, (GskGpuCached *) tile);
*out_color_state = tile->color_state;
*out_color_state = gdk_color_state_ref (tile->color_state);
return g_object_ref (tile->image);
}
+8 -4
View File
@@ -52,16 +52,20 @@ static const GskGpuShaderOpClass GSK_GPU_COLORIZE_OP_CLASS = {
void
gsk_gpu_colorize_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
const GskGpuShaderImage *image,
const float color[4])
const GdkColor *color)
{
GskGpuColorizeInstance *instance;
GdkColorState *alt;
alt = gsk_gpu_color_states_find (ccs, color);
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_COLORIZE_OP_CLASS,
color_states,
gsk_gpu_color_states_create (ccs, TRUE, alt, FALSE),
0,
clip,
(GskGpuImage *[1]) { image->image },
@@ -70,5 +74,5 @@ gsk_gpu_colorize_op (GskGpuFrame *frame,
gsk_gpu_rect_to_float (image->coverage ? image->coverage : image->bounds, offset, instance->rect);
gsk_gpu_rect_to_float (image->bounds, offset, instance->tex_rect);
gsk_gpu_vec4_to_float (color, instance->color);
gsk_gpu_color_to_float (color, alt, opacity, instance->color);
}
+3 -2
View File
@@ -8,10 +8,11 @@ G_BEGIN_DECLS
void gsk_gpu_colorize_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
const GskGpuShaderImage *image,
const float color[4]);
const GdkColor *color);
G_END_DECLS
+6 -1
View File
@@ -36,7 +36,8 @@ gsk_gpu_convert_cicp_op_print_instance (GskGpuShaderOp *shader,
g_string_append_printf (string, "cicp %u/%u/%u/%u",
instance->color_primaries,
instance->transfer_function,
0, 1);
instance->matrix_coefficients,
instance->range);
}
static const GskGpuShaderOpClass GSK_GPU_CONVERT_OP_CLASS = {
@@ -88,6 +89,8 @@ gsk_gpu_convert_from_cicp_op (GskGpuFrame *frame,
instance->opacity = opacity;
instance->color_primaries = cicp->color_primaries;
instance->transfer_function = cicp->transfer_function;
instance->matrix_coefficients = cicp->matrix_coefficients;
instance->range = cicp->range == GDK_CICP_RANGE_NARROW ? 0 : 1;
}
void
@@ -118,4 +121,6 @@ gsk_gpu_convert_to_cicp_op (GskGpuFrame *frame,
instance->opacity = opacity;
instance->color_primaries = cicp->color_primaries;
instance->transfer_function = cicp->transfer_function;
instance->matrix_coefficients = cicp->matrix_coefficients;
instance->range = cicp->range == GDK_CICP_RANGE_NARROW ? 0 : 1;
}
+7 -101
View File
@@ -33,8 +33,6 @@ struct _GskGpuDownloadOp
GskGpuOp op;
GskGpuImage *image;
GdkColorState *image_cs;
GdkColorState *download_cs;
gboolean allow_dmabuf;
GdkGpuDownloadOpCreateFunc create_func;
GskGpuDownloadFunc func;
@@ -55,60 +53,8 @@ gsk_gpu_download_op_finish (GskGpuOp *op)
if (self->create_func)
self->create_func (self);
g_print ("downloaded texture: %s %.4s depth %s format %s color state %s\n",
GDK_IS_DMABUF_TEXTURE (self->texture)
? "dmabuf"
: (GDK_IS_GL_TEXTURE (self->texture)
? "gl"
: "memory"),
GDK_IS_DMABUF_TEXTURE (self->texture)
? (char *) &gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (self->texture))->fourcc
: "",
gdk_memory_depth_get_name (gdk_memory_format_get_depth (gdk_texture_get_format (self->texture), FALSE)),
gdk_memory_format_get_name (gdk_texture_get_format (self->texture)),
gdk_color_state_get_name (gdk_texture_get_color_state (self->texture)));
if (!gdk_color_state_equal (gdk_texture_get_color_state (self->texture), self->download_cs))
{
GdkTextureDownloader *downloader;
GdkMemoryTextureBuilder *builder;
GBytes *bytes;
gsize stride;
GdkTexture *texture;
g_print ("converting rendered %s texture after download: %s -> %s\n",
GDK_IS_DMABUF_TEXTURE (self->texture) ? "dmabuf" :
(GDK_IS_GL_TEXTURE (self->texture) ? "gl" : "memory"),
gdk_color_state_get_name (gdk_texture_get_color_state (self->texture)),
gdk_color_state_get_name (self->download_cs));
downloader = gdk_texture_downloader_new (self->texture);
gdk_texture_downloader_set_format (downloader, gdk_texture_get_format (self->texture));
gdk_texture_downloader_set_color_state (downloader, self->download_cs);
bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
gdk_texture_downloader_free (downloader);
builder = gdk_memory_texture_builder_new ();
gdk_memory_texture_builder_set_bytes (builder, bytes);
gdk_memory_texture_builder_set_stride (builder, stride);
gdk_memory_texture_builder_set_width (builder, gdk_texture_get_width (self->texture));
gdk_memory_texture_builder_set_height (builder, gdk_texture_get_height (self->texture));
gdk_memory_texture_builder_set_format (builder, gdk_texture_get_format (self->texture));
gdk_memory_texture_builder_set_color_state (builder, self->download_cs);
texture = gdk_memory_texture_builder_build (builder);
g_object_unref (builder);
g_set_object (&self->texture, texture);
g_bytes_unref (bytes);
g_object_unref (texture);
}
self->func (self->user_data, self->texture);
gdk_color_state_unref (self->image_cs);
gdk_color_state_unref (self->download_cs);
g_object_unref (self->texture);
g_object_unref (self->image);
g_clear_object (&self->buffer);
@@ -124,7 +70,6 @@ gsk_gpu_download_op_print (GskGpuOp *op,
gsk_gpu_print_op (string, indent, "download");
gsk_gpu_print_image (string, self->image);
gsk_gpu_print_string (string, gdk_color_state_get_name (self->download_cs));
gsk_gpu_print_newline (string);
}
@@ -173,7 +118,6 @@ gsk_gpu_download_op_vk_create (GskGpuDownloadOp *self)
guchar *data;
gsize width, height, stride;
GdkMemoryFormat format;
GdkMemoryTextureBuilder *builder;
data = gsk_gpu_buffer_map (self->buffer);
width = gsk_gpu_image_get_width (self->image);
@@ -181,18 +125,11 @@ gsk_gpu_download_op_vk_create (GskGpuDownloadOp *self)
format = gsk_gpu_image_get_format (self->image);
stride = width * gdk_memory_format_bytes_per_pixel (format);
bytes = g_bytes_new (data, stride * height);
builder = gdk_memory_texture_builder_new ();
gdk_memory_texture_builder_set_bytes (builder, bytes);
gdk_memory_texture_builder_set_stride (builder, stride);
gdk_memory_texture_builder_set_width (builder, width);
gdk_memory_texture_builder_set_height (builder, height);
gdk_memory_texture_builder_set_format (builder, format);
gdk_memory_texture_builder_set_color_state (builder, self->image_cs);
self->texture = gdk_memory_texture_builder_build (builder);
g_object_unref (builder);
self->texture = gdk_memory_texture_new (width,
height,
format,
bytes,
stride);
g_bytes_unref (bytes);
gsk_gpu_buffer_unmap (self->buffer, 0);
}
@@ -207,17 +144,7 @@ gsk_gpu_download_op_vk_command (GskGpuOp *op,
#ifdef HAVE_DMABUF
if (self->allow_dmabuf)
{
GdkColorState *cs;
if (gsk_gpu_image_get_flags (self->image) & GSK_GPU_IMAGE_SRGB)
cs = GDK_COLOR_STATE_SRGB;
else
cs = self->image_cs;
self->texture = gsk_vulkan_image_to_dmabuf_texture (GSK_VULKAN_IMAGE (self->image), cs);
}
self->texture = gsk_vulkan_image_to_dmabuf_texture (GSK_VULKAN_IMAGE (self->image));
if (self->texture)
{
GskGpuDevice *device = gsk_gpu_frame_get_device (frame);
@@ -368,16 +295,10 @@ gsk_gpu_download_op_gl_command (GskGpuOp *op,
GskGLTextureData *data;
GdkGLContext *context;
guint texture_id;
GdkColorState *cs;
context = GDK_GL_CONTEXT (gsk_gpu_frame_get_context (frame));
texture_id = gsk_gl_image_steal_texture (GSK_GL_IMAGE (self->image));
if (gsk_gpu_image_get_flags (self->image) & GSK_GPU_IMAGE_SRGB)
cs = GDK_COLOR_STATE_SRGB_LINEAR;
else
cs = self->image_cs;
#ifdef HAVE_DMABUF
if (self->allow_dmabuf)
{
@@ -396,20 +317,12 @@ gsk_gpu_download_op_gl_command (GskGpuOp *op,
gdk_dmabuf_texture_builder_set_width (db, gsk_gpu_image_get_width (self->image));
gdk_dmabuf_texture_builder_set_height (db, gsk_gpu_image_get_height (self->image));
gdk_dmabuf_texture_builder_set_color_state (db, cs);
g_print ("dmabuf downloader color state: %s\n", gdk_color_state_get_name (gdk_dmabuf_texture_builder_get_color_state (db)));
self->texture = gdk_dmabuf_texture_builder_build (db,
release_dmabuf_texture,
texture,
NULL);
self->texture = gdk_dmabuf_texture_builder_build (db, release_dmabuf_texture, texture, NULL);
g_object_unref (db);
if (self->texture)
return op->next;
else
g_print ("failed to build dmabuf texture\n");
}
g_free (texture);
@@ -430,7 +343,6 @@ gsk_gpu_download_op_gl_command (GskGpuOp *op,
gdk_gl_texture_builder_set_width (builder, gsk_gpu_image_get_width (self->image));
gdk_gl_texture_builder_set_height (builder, gsk_gpu_image_get_height (self->image));
gdk_gl_texture_builder_set_sync (builder, data->sync);
gdk_gl_texture_builder_set_color_state (builder, cs);
self->texture = gdk_gl_texture_builder_build (builder,
gsk_gl_texture_data_free,
@@ -455,8 +367,6 @@ static const GskGpuOpClass GSK_GPU_DOWNLOAD_OP_CLASS = {
void
gsk_gpu_download_op (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *image_cs,
GdkColorState *download_cs,
gboolean allow_dmabuf,
GskGpuDownloadFunc func,
gpointer user_data)
@@ -467,10 +377,6 @@ gsk_gpu_download_op (GskGpuFrame *frame,
self->image = g_object_ref (image);
self->allow_dmabuf = allow_dmabuf;
self->image_cs = gdk_color_state_ref (image_cs);
self->download_cs = gdk_color_state_ref (download_cs);
self->func = func,
self->user_data = user_data;
}
-2
View File
@@ -9,8 +9,6 @@ typedef void (* GskGpuDownloadFunc) (gpointe
void gsk_gpu_download_op (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *image_cs,
GdkColorState *download_cs,
gboolean allow_dmabuf,
GskGpuDownloadFunc func,
gpointer user_data);
+15 -53
View File
@@ -78,19 +78,20 @@ gsk_gpu_frame_default_cleanup (GskGpuFrame *self)
}
static void
gsk_gpu_frame_default_begin (GskGpuFrame *self,
GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region)
gsk_gpu_frame_default_begin (GskGpuFrame *self,
GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region,
const graphene_rect_t *opaque)
{
gdk_draw_context_begin_frame_full (context, depth, region);
gdk_draw_context_begin_frame_full (context, depth, region, opaque);
}
static void
gsk_gpu_frame_default_end (GskGpuFrame *self,
GdkDrawContext *context)
{
gdk_draw_context_end_frame (context);
gdk_draw_context_end_frame_full (context);
}
static void
@@ -202,9 +203,10 @@ void
gsk_gpu_frame_begin (GskGpuFrame *self,
GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region)
const cairo_region_t *region,
const graphene_rect_t *opaque)
{
GSK_GPU_FRAME_GET_CLASS (self)->begin (self, context, depth, region);
GSK_GPU_FRAME_GET_CLASS (self)->begin (self, context, depth, region, opaque);
}
void
@@ -632,7 +634,7 @@ gsk_gpu_frame_record (GskGpuFrame *self,
gint64 timestamp,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_region_t *clip,
cairo_region_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport,
GdkTexture **texture)
@@ -643,48 +645,10 @@ gsk_gpu_frame_record (GskGpuFrame *self,
priv->timestamp = timestamp;
gsk_gpu_cache_set_time (gsk_gpu_device_get_cache (priv->device), timestamp);
if (clip)
{
int i;
for (i = 0; i < cairo_region_num_rectangles (clip); i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (clip, i, &rect);
gsk_gpu_node_processor_process (self, target, target_color_state, &rect, node, viewport, pass_type);
}
}
else
{
gsk_gpu_node_processor_process (self,
target,
target_color_state,
&(cairo_rectangle_int_t) {
0, 0,
gsk_gpu_image_get_width (target),
gsk_gpu_image_get_height (target)
},
node,
viewport,
pass_type);
}
gsk_gpu_node_processor_process (self, target, target_color_state, clip, node, viewport, pass_type);
if (texture)
{
GdkColorState *image_cs;
GdkColorState *download_cs;
image_cs = gdk_color_state_get_rendering_color_state (target_color_state,
gsk_gpu_image_get_flags (target) & GSK_GPU_IMAGE_SRGB);
if (image_cs == GDK_COLOR_STATE_SRGB_LINEAR)
download_cs = GDK_COLOR_STATE_SRGB;
else
download_cs = image_cs;
gsk_gpu_download_op (self, target, target_color_state, download_cs, TRUE, copy_texture, texture);
}
gsk_gpu_download_op (self, target, TRUE, copy_texture, texture);
}
static void
@@ -723,7 +687,7 @@ gsk_gpu_frame_render (GskGpuFrame *self,
gint64 timestamp,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_region_t *region,
cairo_region_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport,
GdkTexture **texture)
@@ -732,7 +696,7 @@ gsk_gpu_frame_render (GskGpuFrame *self,
gsk_gpu_frame_cleanup (self);
gsk_gpu_frame_record (self, timestamp, target, target_color_state, region, node, viewport, texture);
gsk_gpu_frame_record (self, timestamp, target, target_color_state, clip, node, viewport, texture);
gsk_gpu_frame_submit (self, pass_type);
}
@@ -791,8 +755,6 @@ gsk_gpu_frame_download_texture (GskGpuFrame *self,
gsk_gpu_download_op (self,
image,
gdk_texture_get_color_state (texture),
color_state,
FALSE,
do_download,
g_memdup (&(Download) {
+5 -3
View File
@@ -30,7 +30,8 @@ struct _GskGpuFrameClass
void (* begin) (GskGpuFrame *self,
GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region);
const cairo_region_t *region,
const graphene_rect_t *opaque);
void (* end) (GskGpuFrame *self,
GdkDrawContext *context);
GskGpuImage * (* upload_texture) (GskGpuFrame *self,
@@ -66,7 +67,8 @@ gsize gsk_gpu_frame_get_texture_vertex_size (GskGpuF
void gsk_gpu_frame_begin (GskGpuFrame *self,
GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region);
const cairo_region_t *region,
const graphene_rect_t *opaque);
void gsk_gpu_frame_end (GskGpuFrame *self,
GdkDrawContext *context);
@@ -102,7 +104,7 @@ void gsk_gpu_frame_render (GskGpuF
gint64 timestamp,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_region_t *region,
cairo_region_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport,
GdkTexture **texture);
+59
View File
@@ -1,6 +1,7 @@
#include "config.h"
#include "gskgpuimageprivate.h"
#include "gdkcolorstateprivate.h"
typedef struct _GskGpuImagePrivate GskGpuImagePrivate;
@@ -162,3 +163,61 @@ gsk_gpu_image_get_projection_matrix (GskGpuImage *self,
{
GSK_GPU_IMAGE_GET_CLASS (self)->get_projection_matrix (self, out_projection);
}
GdkColorState *
gsk_gpu_image_adjust_color_state (GskGpuImage *self,
GdkColorState *color_state)
{
GskGpuImagePrivate *priv = gsk_gpu_image_get_instance_private (self);
GdkColorState *adjusted;
GdkCicp cicp;
adjusted = gdk_color_state_ref (color_state);
if (priv->flags & GSK_GPU_IMAGE_SRGB)
{
GdkColorState *no_srgb;
no_srgb = gdk_color_state_get_no_srgb_tf (adjusted);
g_assert (no_srgb);
gdk_color_state_unref (adjusted);
adjusted = gdk_color_state_ref (no_srgb);
}
if (!gdk_color_state_get_cicp (adjusted))
return adjusted;
cicp = *gdk_color_state_get_cicp (adjusted);
if (priv->flags & GSK_GPU_IMAGE_NARROW_RANGE)
cicp.range = GDK_CICP_RANGE_FULL;
switch (priv->flags & GSK_GPU_IMAGE_YUV)
{
case GSK_GPU_IMAGE_BT709:
g_assert (cicp.matrix_coefficients == 1);
cicp.matrix_coefficients = 0;
break;
case GSK_GPU_IMAGE_BT601:
g_assert (cicp.matrix_coefficients == 5 ||
cicp.matrix_coefficients == 6);
cicp.matrix_coefficients = 0;
break;
case GSK_GPU_IMAGE_BT2020:
g_assert (cicp.matrix_coefficients == 9);
cicp.matrix_coefficients = 0;
break;
default:
break;
}
if (!gdk_cicp_equal (&cicp, gdk_color_state_get_cicp (adjusted)))
{
gdk_color_state_unref (adjusted);
adjusted = gdk_color_state_new_for_cicp (&cicp, NULL);
g_assert (adjusted);
}
return adjusted;
}
+3
View File
@@ -48,6 +48,9 @@ void gsk_gpu_image_set_flags (GskGpuI
void gsk_gpu_image_get_projection_matrix (GskGpuImage *self,
graphene_matrix_t *out_projection);
GdkColorState * gsk_gpu_image_adjust_color_state (GskGpuImage *self,
GdkColorState *color_state);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskGpuImage, g_object_unref)
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -8,7 +8,7 @@ G_BEGIN_DECLS
void gsk_gpu_node_processor_process (GskGpuFrame *frame,
GskGpuImage *target,
GdkColorState *target_color_state,
const cairo_rectangle_int_t *clip,
cairo_region_t *clip,
GskRenderNode *node,
const graphene_rect_t *viewport,
GskRenderPassType pass_type);
+33 -21
View File
@@ -264,6 +264,7 @@ gsk_gpu_renderer_fallback_render_texture (GskGpuRenderer *self,
guchar *data;
GdkTexture *texture;
GdkTextureDownloader downloader;
cairo_region_t *clip_region;
GskGpuFrame *frame;
max_size = gsk_gpu_device_get_max_image_size (priv->device);
@@ -299,14 +300,22 @@ gsk_gpu_renderer_fallback_render_texture (GskGpuRenderer *self,
MIN (image_width, width - x),
MIN (image_height, height - y));
color_state = GDK_COLOR_STATE_SRGB;
if (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_SRGB)
color_state = GDK_COLOR_STATE_SRGB_LINEAR;
else
color_state = GDK_COLOR_STATE_SRGB;
clip_region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
0, 0,
gsk_gpu_image_get_width (image),
gsk_gpu_image_get_height (image)
});
frame = gsk_gpu_renderer_create_frame (self);
gsk_gpu_frame_render (frame,
g_get_monotonic_time (),
image,
color_state,
NULL,
clip_region,
root,
&GRAPHENE_RECT_INIT (rounded_viewport->origin.x + x,
rounded_viewport->origin.y + y,
@@ -349,7 +358,7 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer,
GdkTexture *texture;
graphene_rect_t rounded_viewport;
GdkColorState *color_state;
GdkMemoryDepth depth;
cairo_region_t *clip_region;
gsk_gpu_device_maybe_gc (priv->device);
@@ -359,34 +368,33 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer,
viewport->origin.y,
ceil (viewport->size.width),
ceil (viewport->size.height));
if (gsk_render_node_is_hdr (root))
color_state = GDK_COLOR_STATE_REC2100_PQ;
else
color_state = GDK_COLOR_STATE_SRGB;
depth = gdk_memory_depth_merge (gsk_render_node_get_preferred_depth (root),
gdk_color_state_get_depth (color_state));
image = gsk_gpu_device_create_download_image (priv->device,
depth,
gsk_render_node_get_preferred_depth (root),
rounded_viewport.size.width,
rounded_viewport.size.height);
if (image == NULL)
return gsk_gpu_renderer_fallback_render_texture (self, root, &rounded_viewport);
g_print ("render_texture: image depth %s, target color state %s\n",
gdk_memory_depth_get_name (depth), gdk_color_state_get_name (color_state));
if (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_SRGB)
color_state = GDK_COLOR_STATE_SRGB_LINEAR;
else
color_state = GDK_COLOR_STATE_SRGB;
frame = gsk_gpu_renderer_create_frame (self);
clip_region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
0, 0,
gsk_gpu_image_get_width (image),
gsk_gpu_image_get_height (image)
});
texture = NULL;
gsk_gpu_frame_render (frame,
g_get_monotonic_time (),
image,
color_state,
NULL,
clip_region,
root,
&rounded_viewport,
&texture);
@@ -412,6 +420,8 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
GskGpuFrame *frame;
GskGpuImage *backbuffer;
cairo_region_t *render_region;
graphene_rect_t opaque_tmp;
const graphene_rect_t *opaque;
double scale;
GdkMemoryDepth depth;
@@ -423,13 +433,17 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
gsk_gpu_device_maybe_gc (priv->device);
gsk_gpu_renderer_make_current (self);
depth = gsk_render_node_get_preferred_depth (root);
frame = gsk_gpu_renderer_get_frame (self);
scale = gsk_gpu_renderer_get_scale (self);
gsk_gpu_frame_begin (frame, priv->context, depth, region);
gsk_gpu_renderer_make_current (self);
if (gsk_render_node_get_opaque_rect (root, &opaque_tmp))
opaque = &opaque_tmp;
else
opaque = NULL;
gsk_gpu_frame_begin (frame, priv->context, depth, region, opaque);
backbuffer = GSK_GPU_RENDERER_GET_CLASS (self)->get_backbuffer (self);
@@ -451,8 +465,6 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
gsk_gpu_frame_end (frame, priv->context);
gsk_gpu_device_queue_gc (priv->device);
g_clear_pointer (&render_region, cairo_region_destroy);
}
static double
+6
View File
@@ -29,8 +29,14 @@ typedef enum {
GSK_GPU_IMAGE_FILTERABLE = (1 << 6),
GSK_GPU_IMAGE_RENDERABLE = (1 << 7),
GSK_GPU_IMAGE_SRGB = (1 << 8),
GSK_GPU_IMAGE_NARROW_RANGE = (1 << 9),
GSK_GPU_IMAGE_BT601 = (1 << 10),
GSK_GPU_IMAGE_BT709 = (2 << 10),
GSK_GPU_IMAGE_BT2020 = (3 << 10),
} GskGpuImageFlags;
#define GSK_GPU_IMAGE_YUV (GSK_GPU_IMAGE_BT2020)
typedef enum {
GSK_GPU_SAMPLER_DEFAULT,
GSK_GPU_SAMPLER_TRANSPARENT,
+5 -6
View File
@@ -45,14 +45,11 @@ gsk_ngl_renderer_create_context (GskGpuRenderer *renderer,
{
GdkGLContext *context;
if (surface)
context = gdk_surface_create_gl_context (surface, error);
else
context = gdk_display_create_gl_context (display, error);
if (context == NULL)
if (!gdk_display_prepare_gl (display, error))
return NULL;
context = gdk_gl_context_new (display, surface, surface != NULL);
/* GLES 2 is not supported */
gdk_gl_context_set_required_version (context, 3, 0);
@@ -142,6 +139,8 @@ gsk_ngl_renderer_unrealize (GskRenderer *renderer)
gsk_ngl_renderer_free_backbuffer (self);
gdk_gl_context_clear_current ();
GSK_RENDERER_CLASS (gsk_ngl_renderer_parent_class)->unrealize (renderer);
}
+1 -1
View File
@@ -76,7 +76,7 @@ gsk_vulkan_handle_result (VkResult res,
{
if (res != VK_SUCCESS)
{
GSK_DEBUG (VULKAN, "%s(): %s (%d)", called_function, gdk_vulkan_strerror (res), res);
g_warning ("%s(): %s (%d)", called_function, gdk_vulkan_strerror (res), res);
}
return res;
}
+8 -5
View File
@@ -148,15 +148,16 @@ gsk_vulkan_frame_cleanup (GskGpuFrame *frame)
}
static void
gsk_vulkan_frame_begin (GskGpuFrame *frame,
GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region)
gsk_vulkan_frame_begin (GskGpuFrame *frame,
GdkDrawContext *context,
GdkMemoryDepth depth,
const cairo_region_t *region,
const graphene_rect_t *opaque)
{
GskVulkanFrame *self = GSK_VULKAN_FRAME (frame);
gdk_vulkan_context_set_draw_semaphore (GDK_VULKAN_CONTEXT (context), self->vk_acquire_semaphore);
GSK_GPU_FRAME_CLASS (gsk_vulkan_frame_parent_class)->begin (frame, context, depth, region);
GSK_GPU_FRAME_CLASS (gsk_vulkan_frame_parent_class)->begin (frame, context, depth, region, opaque);
}
static GskGpuImage *
@@ -187,6 +188,7 @@ gsk_vulkan_frame_upload_texture (GskGpuFrame *frame,
image = gsk_vulkan_image_new_for_dmabuf (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
gdk_texture_get_color_state (texture),
&dmabuf,
gdk_memory_format_alpha (gdk_texture_get_format (texture)) == GDK_MEMORY_ALPHA_PREMULTIPLIED);
@@ -209,6 +211,7 @@ gsk_vulkan_frame_upload_texture (GskGpuFrame *frame,
image = gsk_vulkan_image_new_for_dmabuf (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
gdk_texture_get_color_state (texture),
gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture)),
gdk_memory_format_alpha (gdk_texture_get_format (texture)) == GDK_MEMORY_ALPHA_PREMULTIPLIED);
if (image)
+33 -10
View File
@@ -844,6 +844,7 @@ GskGpuImage *
gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
gsize width,
gsize height,
GdkColorState *color_state,
const GdkDmabuf *dmabuf,
gboolean premultiplied)
{
@@ -859,6 +860,7 @@ gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
GdkMemoryFormat format;
GskGpuImageFlags flags;
gboolean is_yuv;
const GdkCicp *cicp;
if (!gsk_vulkan_device_has_feature (device, GDK_VULKAN_FEATURE_DMABUF))
{
@@ -968,13 +970,36 @@ gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
return NULL;
}
gsk_gpu_image_setup (GSK_GPU_IMAGE (self),
flags |
(gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT ? GSK_GPU_IMAGE_STRAIGHT_ALPHA : 0) |
(is_yuv ? (GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT) : 0) |
(gsk_component_mapping_is_framebuffer_compatible (&vk_components) ? 0 : GSK_GPU_IMAGE_NO_BLIT),
format,
width, height);
if (is_yuv)
flags |= GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT;
if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT)
flags |= GSK_GPU_IMAGE_STRAIGHT_ALPHA;
if (!gsk_component_mapping_is_framebuffer_compatible (&vk_components))
flags |= GSK_GPU_IMAGE_NO_BLIT;
cicp = gdk_color_state_get_cicp (color_state);
switch (cicp->matrix_coefficients)
{
case 1:
flags |= GSK_GPU_IMAGE_BT709;
break;
case 5:
case 6:
flags |= GSK_GPU_IMAGE_BT601;
break;
case 9:
flags |= GSK_GPU_IMAGE_BT2020;
break;
default:
break;
}
if (cicp->range == GDK_CICP_RANGE_NARROW)
flags |= GSK_GPU_IMAGE_NARROW_RANGE;
gsk_gpu_image_setup (GSK_GPU_IMAGE (self), flags, format, width, height);
self->allocator = gsk_vulkan_device_get_external_allocator (device);
gsk_vulkan_allocator_ref (self->allocator);
@@ -1176,8 +1201,7 @@ gsk_vulkan_image_get_n_planes (GskVulkanImage *self,
}
GdkTexture *
gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self,
GdkColorState *color_state)
gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self)
{
GskGpuImage *image = GSK_GPU_IMAGE (self);
GdkDmabufTextureBuilder *builder;
@@ -1227,7 +1251,6 @@ gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self,
gdk_dmabuf_texture_builder_set_display (builder, gsk_gpu_device_get_display (GSK_GPU_DEVICE (self->device)));
gdk_dmabuf_texture_builder_set_width (builder, gsk_gpu_image_get_width (image));
gdk_dmabuf_texture_builder_set_height (builder, gsk_gpu_image_get_height (image));
gdk_dmabuf_texture_builder_set_color_state (builder, color_state);
gdk_dmabuf_texture_builder_set_fourcc (builder, fourcc);
gdk_dmabuf_texture_builder_set_modifier (builder, properties.drmFormatModifier);
gdk_dmabuf_texture_builder_set_premultiplied (builder, !(gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_STRAIGHT_ALPHA));
+2 -2
View File
@@ -42,10 +42,10 @@ GskGpuImage * gsk_vulkan_image_new_dmabuf (GskVulk
GskGpuImage * gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
gsize width,
gsize height,
GdkColorState *color_state,
const GdkDmabuf *dmabuf,
gboolean premultiplied);
GdkTexture * gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self,
GdkColorState *color_state);
GdkTexture * gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self);
#endif
guchar * gsk_vulkan_image_get_data (GskVulkanImage *self,
+97
View File
@@ -14,6 +14,8 @@ PASS(2) vec2 _tex_coord;
PASS_FLAT(3) float _opacity;
PASS_FLAT(4) uint _transfer_function;
PASS_FLAT(5) mat3 _mat;
PASS_FLAT(8) mat3 _yuv;
PASS_FLAT(11) uint _range;
#ifdef GSK_VERTEX_SHADER
@@ -22,6 +24,8 @@ IN(1) vec4 in_tex_rect;
IN(2) float in_opacity;
IN(3) uint in_color_primaries;
IN(4) uint in_transfer_function;
IN(5) uint in_matrix_coefficients;
IN(6) uint in_range;
const mat3 identity = mat3(
@@ -90,6 +94,42 @@ const mat3 xyz_to_p3 = mat3(
-0.4027108, 0.0236247, 0.9568845
);
const mat3 rgb_to_bt601 = mat3(
0.299000, -0.168736, 0.500000,
0.587000, -0.331264, -0.418688,
0.114000, 0.500000, -0.081312
);
const mat3 bt601_to_rgb = mat3(
1.000000, 1.000000, 1.000000,
0.000000, -0.344136, 1.772000,
1.402000, -0.714136, 0.000000
);
const mat3 rgb_to_bt709 = mat3(
0.212600, -0.114572, 0.500000,
0.715200, -0.385428, -0.454153,
0.072200, 0.500000, -0.045847
);
const mat3 bt709_to_rgb = mat3(
1.000000, 1.000000, 1.000000,
0.000000, -0.187324, 1.855600,
1.574800, -0.468124, -0.000000
);
const mat3 rgb_to_bt2020 = mat3(
0.262700, -0.139630, 0.500000,
0.678000, -0.360370, -0.459786,
0.059300, 0.500000, -0.040214
);
const mat3 bt2020_to_rgb = mat3(
1.000000, 1.000000, 1.000000,
-0.000000, -0.164553, 1.881400,
1.474600, -0.571353, -0.000000
);
mat3
cicp_to_xyz (uint cp)
{
@@ -121,6 +161,34 @@ cicp_from_xyz (uint cp)
}
mat3
yuv_to_rgb (uint mc)
{
switch (mc)
{
case 0u: return identity;
case 1u: return bt709_to_rgb;
case 5u:
case 6u: return bt601_to_rgb;
case 9u: return bt2020_to_rgb;
}
return mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
}
mat3
rgb_to_yuv (uint mc)
{
switch (mc)
{
case 0u: return identity;
case 1u: return rgb_to_bt709;
case 5u:
case 6u: return rgb_to_bt601;
case 9u: return rgb_to_bt2020;
}
return mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
}
void
run (out vec2 pos)
{
@@ -133,6 +201,7 @@ run (out vec2 pos)
_tex_coord = rect_get_coord (rect_from_gsk (in_tex_rect), pos);
_opacity = in_opacity;
_transfer_function = in_transfer_function;
_range = in_range;
if (HAS_VARIATION (VARIATION_REVERSE))
{
@@ -141,6 +210,8 @@ run (out vec2 pos)
_mat = cicp_from_xyz (in_color_primaries) * srgb_to_xyz;
else
_mat = cicp_from_xyz (in_color_primaries) * rec2020_to_xyz;
_yuv = rgb_to_yuv (in_matrix_coefficients);
}
else
{
@@ -149,6 +220,8 @@ run (out vec2 pos)
_mat = xyz_to_srgb * cicp_to_xyz (in_color_primaries);
else
_mat = xyz_to_rec2020 * cicp_to_xyz (in_color_primaries);
_yuv = yuv_to_rgb (in_matrix_coefficients);
}
}
@@ -329,6 +402,18 @@ convert_color_from_cicp (vec4 color,
if (from_premul)
color = color_unpremultiply (color);
if (_range == 0u)
{
color.r = (color.r - 16.0/255.0) * 255.0/219.0;
color.g = (color.g - 16.0/255.0) * 255.0/224.0;
color.b = (color.b - 16.0/255.0) * 255.0/224.0;
}
color.g -= 0.5;
color.b -= 0.5;
color.rgb = _yuv * color.rgb;
color.rgb = apply_cicp_eotf (color.rgb, _transfer_function);
color.rgb = _mat * color.rgb;
color.rgb = apply_oetf (color.rgb, to);
@@ -352,6 +437,18 @@ convert_color_to_cicp (vec4 color,
color.rgb = _mat * color.rgb;
color.rgb = apply_cicp_oetf (color.rgb, _transfer_function);
color.rgb = _yuv * color.rgb;
color.g += 0.5;
color.b += 0.5;
if (_range == 0u)
{
color.r = color.r * 219.0/255.0 + 16.0/255.0;
color.g = color.g * 224.0/255.0 + 16.0/255.0;
color.b = color.b * 224.0/255.0 + 16.0/255.0;
}
if (to_premul)
color = color_premultiply (color);
+3 -2
View File
@@ -23,6 +23,7 @@
#include "config.h"
#include "gskcairoblurprivate.h"
#include "gdkcairoprivate.h"
#include "gdkcairoprivate.h"
@@ -377,7 +378,7 @@ cairo_t *
gsk_cairo_blur_finish_drawing (cairo_t *cr,
GdkColorState *ccs,
float radius,
const GdkRGBA *color,
const GdkColor *color,
GskBlurFlags blur_flags)
{
cairo_t *original_cr;
@@ -397,7 +398,7 @@ gsk_cairo_blur_finish_drawing (cairo_t *cr,
gsk_cairo_blur_surface (surface, x_scale * radius, blur_flags);
gdk_cairo_set_source_rgba_ccs (original_cr, ccs, color);
gdk_cairo_set_source_color (original_cr, ccs, color);
if (blur_flags & GSK_BLUR_REPEAT)
mask_surface_repeat (original_cr, surface);
else
+3 -2
View File
@@ -25,6 +25,7 @@
#include <gdk/gdk.h>
#include <cairo.h>
#include "gdkcolorprivate.h"
G_BEGIN_DECLS
@@ -37,7 +38,7 @@ typedef enum {
void gsk_cairo_blur_surface (cairo_surface_t *surface,
double radius,
GskBlurFlags flags);
GskBlurFlags flags);
int gsk_cairo_blur_compute_pixels (double radius) G_GNUC_CONST;
cairo_t * gsk_cairo_blur_start_drawing (cairo_t *cr,
@@ -46,7 +47,7 @@ cairo_t * gsk_cairo_blur_start_drawing (cairo_t *cr,
cairo_t * gsk_cairo_blur_finish_drawing (cairo_t *cr,
GdkColorState *ccs,
float radius,
const GdkRGBA *color,
const GdkColor *color,
GskBlurFlags blur_flags);
G_END_DECLS
+11 -3
View File
@@ -159,10 +159,18 @@ gsk_cairo_renderer_render (GskRenderer *renderer,
const cairo_region_t *region)
{
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
graphene_rect_t opaque_tmp;
const graphene_rect_t *opaque;
cairo_t *cr;
gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->cairo_context),
region);
if (gsk_render_node_get_opaque_rect (root, &opaque_tmp))
opaque = &opaque_tmp;
else
opaque = NULL;
gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->cairo_context),
GDK_MEMORY_U8,
region,
opaque);
cr = gdk_cairo_context_cairo_create (self->cairo_context);
g_return_if_fail (cr != NULL);
@@ -188,7 +196,7 @@ gsk_cairo_renderer_render (GskRenderer *renderer,
cairo_destroy (cr);
gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->cairo_context));
gdk_draw_context_end_frame_full (GDK_DRAW_CONTEXT (self->cairo_context));
}
static void
+1
View File
@@ -15,6 +15,7 @@ static const GdkDebugKey gsk_debug_keys[] = {
{ "staging", GSK_DEBUG_STAGING, "Use a staging image for texture upload (Vulkan only)" },
{ "offload-disable", GSK_DEBUG_OFFLOAD_DISABLE, "Disable graphics offload" },
{ "cairo", GSK_DEBUG_CAIRO, "Overlay error pattern over Cairo drawing (finds fallbacks)" },
{ "occlusion", GSK_DEBUG_OCCLUSION, "Overlay highlight over areas optimized via occlusion culling" },
};
static guint gsk_debug_flags;
+1
View File
@@ -18,6 +18,7 @@ typedef enum {
GSK_DEBUG_STAGING = 1 << 10,
GSK_DEBUG_OFFLOAD_DISABLE = 1 << 11,
GSK_DEBUG_CAIRO = 1 << 12,
GSK_DEBUG_OCCLUSION = 1 << 13,
} GskDebugFlags;
#define GSK_DEBUG_ANY ((1 << 13) - 1)
+12
View File
@@ -5,6 +5,8 @@
#include <graphene.h>
#include <math.h>
#define GSK_RECT_INIT_CAIRO(cairo_rect) GRAPHENE_RECT_INIT((cairo_rect)->x, (cairo_rect)->y, (cairo_rect)->width, (cairo_rect)->height)
static inline void
gsk_rect_init (graphene_rect_t *r,
float x,
@@ -185,6 +187,16 @@ gsk_rect_to_cairo_grow (const graphene_rect_t *graphene,
cairo->height = ceilf (graphene->origin.y + graphene->size.height) - cairo->y;
}
static inline void
gsk_rect_to_cairo_shrink (const graphene_rect_t *graphene,
cairo_rectangle_int_t *cairo)
{
cairo->x = ceilf (graphene->origin.x);
cairo->y = ceilf (graphene->origin.y);
cairo->width = floorf (graphene->origin.x + graphene->size.width) - cairo->x;
cairo->height = floorf (graphene->origin.y + graphene->size.height) - cairo->y;
}
static inline gboolean
gsk_rect_equal (const graphene_rect_t *r1,
const graphene_rect_t *r2)
+2 -2
View File
@@ -380,7 +380,7 @@ gsk_render_node_draw_ccs (GskRenderNode *node,
GdkColorState *ccs)
{
/* Check that the calling function did pass a correct color state */
g_assert (ccs == gdk_color_state_get_rendering_color_state (ccs, FALSE));
g_assert (ccs == gdk_color_state_get_rendering_color_state (ccs));
cairo_save (cr);
@@ -413,7 +413,7 @@ gsk_render_node_draw_with_color_state (GskRenderNode *node,
{
GdkColorState *ccs;
ccs = gdk_color_state_get_rendering_color_state (color_state, FALSE);
ccs = gdk_color_state_get_rendering_color_state (color_state);
if (gdk_color_state_equal (color_state, ccs))
{
+1 -1
View File
@@ -124,7 +124,7 @@ void gsk_render_node_get_bounds (GskRenderNode
GDK_AVAILABLE_IN_4_16
gboolean gsk_render_node_get_opaque_rect (GskRenderNode *self,
graphene_rect_t *out_opaque);
graphene_rect_t *out_opaque) G_GNUC_WARN_UNUSED_RESULT;
GDK_AVAILABLE_IN_ALL
void gsk_render_node_draw (GskRenderNode *node,
+431 -92
View File
@@ -61,6 +61,11 @@
*/
#define MAX_RECTS_IN_DIFF 30
/* This lock protects all on-demand created legacy rgba data of
* render nodes.
*/
G_LOCK_DEFINE_STATIC (rgba);
static gboolean
gsk_color_stops_are_opaque (const GskColorStop *stops,
gsize n_stops)
@@ -96,7 +101,7 @@ color_state_is_hdr (GdkColorState *color_state)
{
GdkColorState *rendering_cs;
rendering_cs = gdk_color_state_get_rendering_color_state (color_state, FALSE);
rendering_cs = gdk_color_state_get_rendering_color_state (color_state);
return rendering_cs != GDK_COLOR_STATE_SRGB &&
rendering_cs != GDK_COLOR_STATE_SRGB_LINEAR;
@@ -1450,13 +1455,28 @@ struct _GskBorderNode
bool uniform_color: 1;
GskRoundedRect outline;
float border_width[4];
GdkRGBA border_color[4];
GdkColor border_color[4];
GdkRGBA *border_rgba;
};
static void
gsk_border_node_finalize (GskRenderNode *node)
{
GskBorderNode *self = (GskBorderNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_BORDER_NODE));
for (int i = 0; i < 4; i++)
gdk_color_finish (&self->border_color[i]);
g_free (self->border_rgba);
parent_class->finalize (node);
}
static void
gsk_border_node_mesh_add_patch (cairo_pattern_t *pattern,
GdkColorState *ccs,
const GdkRGBA *rgba,
const GdkColor *color,
double x0,
double y0,
double x1,
@@ -1466,18 +1486,19 @@ gsk_border_node_mesh_add_patch (cairo_pattern_t *pattern,
double x3,
double y3)
{
float color[4];
float values[4];
gdk_color_to_float (color, ccs, values);
gdk_color_state_from_rgba (ccs, rgba, color);
cairo_mesh_pattern_begin_patch (pattern);
cairo_mesh_pattern_move_to (pattern, x0, y0);
cairo_mesh_pattern_line_to (pattern, x1, y1);
cairo_mesh_pattern_line_to (pattern, x2, y2);
cairo_mesh_pattern_line_to (pattern, x3, y3);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, color[0], color[1], color[2], color[3]);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 1, color[0], color[1], color[2], color[3]);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, color[0], color[1], color[2], color[3]);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 3, color[0], color[1], color[2], color[3]);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, values[0], values[1], values[2], values[3]);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 1, values[0], values[1], values[2], values[3]);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, values[0], values[1], values[2], values[3]);
cairo_mesh_pattern_set_corner_color_rgba (pattern, 3, values[0], values[1], values[2], values[3]);
cairo_mesh_pattern_end_patch (pattern);
}
@@ -1500,11 +1521,11 @@ gsk_border_node_draw (GskRenderNode *node,
gsk_rounded_rect_path (&self->outline, cr);
gsk_rounded_rect_path (&inside, cr);
if (gdk_rgba_equal (&self->border_color[0], &self->border_color[1]) &&
gdk_rgba_equal (&self->border_color[0], &self->border_color[2]) &&
gdk_rgba_equal (&self->border_color[0], &self->border_color[3]))
if (gdk_color_equal (&self->border_color[0], &self->border_color[1]) &&
gdk_color_equal (&self->border_color[0], &self->border_color[2]) &&
gdk_color_equal (&self->border_color[0], &self->border_color[3]))
{
gdk_cairo_set_source_rgba_ccs (cr, ccs, &self->border_color[0]);
gdk_cairo_set_source_color (cr, ccs, &self->border_color[0]);
}
else
{
@@ -1612,7 +1633,7 @@ gsk_border_node_diff (GskRenderNode *node1,
uniform2 &&
self1->border_width[0] == self2->border_width[0] &&
gsk_rounded_rect_equal (&self1->outline, &self2->outline) &&
gdk_rgba_equal (&self1->border_color[0], &self2->border_color[0]))
gdk_color_equal (&self1->border_color[0], &self2->border_color[0]))
return;
/* Different uniformity -> diff impossible */
@@ -1626,10 +1647,10 @@ gsk_border_node_diff (GskRenderNode *node1,
self1->border_width[1] == self2->border_width[1] &&
self1->border_width[2] == self2->border_width[2] &&
self1->border_width[3] == self2->border_width[3] &&
gdk_rgba_equal (&self1->border_color[0], &self2->border_color[0]) &&
gdk_rgba_equal (&self1->border_color[1], &self2->border_color[1]) &&
gdk_rgba_equal (&self1->border_color[2], &self2->border_color[2]) &&
gdk_rgba_equal (&self1->border_color[3], &self2->border_color[3]) &&
gdk_color_equal (&self1->border_color[0], &self2->border_color[0]) &&
gdk_color_equal (&self1->border_color[1], &self2->border_color[1]) &&
gdk_color_equal (&self1->border_color[2], &self2->border_color[2]) &&
gdk_color_equal (&self1->border_color[3], &self2->border_color[3]) &&
gsk_rounded_rect_equal (&self1->outline, &self2->outline))
return;
@@ -1644,6 +1665,7 @@ gsk_border_node_class_init (gpointer g_class,
node_class->node_type = GSK_BORDER_NODE;
node_class->finalize = gsk_border_node_finalize;
node_class->draw = gsk_border_node_draw;
node_class->diff = gsk_border_node_diff;
}
@@ -1694,9 +1716,23 @@ gsk_border_node_get_widths (const GskRenderNode *node)
const GdkRGBA *
gsk_border_node_get_colors (const GskRenderNode *node)
{
const GskBorderNode *self = (const GskBorderNode *) node;
GskBorderNode *self = (GskBorderNode *) node;
const GdkRGBA *colors;
return self->border_color;
G_LOCK (rgba);
if (self->border_rgba == NULL)
{
self->border_rgba = g_new (GdkRGBA, 4);
for (int i = 0; i < 4; i++)
gdk_color_to_float (&self->border_color[i], GDK_COLOR_STATE_SRGB, (float *) &self->border_rgba[i]);
}
colors = self->border_rgba;
G_UNLOCK (rgba);
return colors;
}
/**
@@ -1718,6 +1754,37 @@ GskRenderNode *
gsk_border_node_new (const GskRoundedRect *outline,
const float border_width[4],
const GdkRGBA border_color[4])
{
GdkColor color[4];
for (int i = 0; i < 4; i++)
gdk_color_init_from_rgba (&color[i], &border_color[i]);
return gsk_border_node_new2 (outline, border_width, color);
for (int i = 0; i < 4; i++)
gdk_color_finish (&color[i]);
}
/*< private >
* gsk_border_node_new2:
* @outline: a `GskRoundedRect` describing the outline of the border
* @border_width: (array fixed-size=4): the stroke width of the border on
* the top, right, bottom and left side respectively.
* @border_color: (array fixed-size=4): the color used on the top, right,
* bottom and left side.
*
* Creates a `GskRenderNode` that will stroke a border rectangle inside the
* given @outline.
*
* The 4 sides of the border can have different widths and colors.
*
* Returns: (transfer full) (type GskBorderNode): A new `GskRenderNode`
*/
GskRenderNode *
gsk_border_node_new2 (const GskRoundedRect *outline,
const float border_width[4],
const GdkColor border_color[4])
{
GskBorderNode *self;
GskRenderNode *node;
@@ -1730,14 +1797,16 @@ gsk_border_node_new (const GskRoundedRect *outline,
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->preferred_depth = gdk_memory_depth_merge (
gdk_memory_depth_merge (my_color_get_depth (&border_color[0]),
my_color_get_depth (&border_color[1])),
gdk_memory_depth_merge (my_color_get_depth (&border_color[2]),
my_color_get_depth (&border_color[3])));
gdk_memory_depth_merge (gdk_color_get_depth (&border_color[0]),
gdk_color_get_depth (&border_color[1])),
gdk_memory_depth_merge (gdk_color_get_depth (&border_color[2]),
gdk_color_get_depth (&border_color[3])));
gsk_rounded_rect_init_copy (&self->outline, outline);
memcpy (self->border_width, border_width, sizeof (self->border_width));
memcpy (self->border_color, border_color, sizeof (self->border_color));
for (int i = 0; i < 4; i++)
gdk_color_init_copy (&self->border_color[i], &border_color[i]);
if (border_width[0] == border_width[1] &&
border_width[0] == border_width[2] &&
@@ -1746,9 +1815,9 @@ gsk_border_node_new (const GskRoundedRect *outline,
else
self->uniform_width = FALSE;
if (gdk_rgba_equal (&border_color[0], &border_color[1]) &&
gdk_rgba_equal (&border_color[0], &border_color[2]) &&
gdk_rgba_equal (&border_color[0], &border_color[3]))
if (gdk_color_equal (&border_color[0], &border_color[1]) &&
gdk_color_equal (&border_color[0], &border_color[2]) &&
gdk_color_equal (&border_color[0], &border_color[3]))
self->uniform_color = TRUE;
else
self->uniform_color = FALSE;
@@ -1758,7 +1827,23 @@ gsk_border_node_new (const GskRoundedRect *outline,
return node;
}
/* Private */
/*< private >
* gsk_border_node_get_colors2:
* @node: (type GskBorderNode): a `GskRenderNode` for a border
*
* Retrieves the colors of the border.
*
* Returns: (transfer none): an array of 4 `GdkColor` structs
* for the top, right, bottom and left color of the border
*/
const GdkColor *
gsk_border_node_get_colors2 (const GskRenderNode *node)
{
const GskBorderNode *self = (const GskBorderNode *) node;
return self->border_color;
}
bool
gsk_border_node_get_uniform (const GskRenderNode *self)
{
@@ -2238,13 +2323,23 @@ struct _GskInsetShadowNode
GskRenderNode render_node;
GskRoundedRect outline;
GdkRGBA color;
float dx;
float dy;
GdkColor color;
graphene_point_t offset;
float spread;
float blur_radius;
};
static void
gsk_inset_shadow_node_finalize (GskRenderNode *node)
{
GskInsetShadowNode *self = (GskInsetShadowNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_INSET_SHADOW_NODE));
gdk_color_finish (&self->color);
parent_class->finalize (node);
}
static gboolean
has_empty_clip (cairo_t *cr)
{
@@ -2261,7 +2356,7 @@ draw_shadow (cairo_t *cr,
const GskRoundedRect *box,
const GskRoundedRect *clip_box,
float radius,
const GdkRGBA *color,
const GdkColor *color,
GskBlurFlags blur_flags)
{
cairo_t *shadow_cr;
@@ -2269,7 +2364,7 @@ draw_shadow (cairo_t *cr,
if (has_empty_clip (cr))
return;
gdk_cairo_set_source_rgba_ccs (cr, ccs, color);
gdk_cairo_set_source_color (cr, ccs, color);
shadow_cr = gsk_cairo_blur_start_drawing (cr, radius, blur_flags);
cairo_set_fill_rule (shadow_cr, CAIRO_FILL_RULE_EVEN_ODD);
@@ -2319,7 +2414,7 @@ draw_shadow_corner (cairo_t *cr,
const GskRoundedRect *box,
const GskRoundedRect *clip_box,
float radius,
const GdkRGBA *color,
const GdkColor *color,
GskCorner corner,
cairo_rectangle_int_t *drawn_rect)
{
@@ -2443,7 +2538,7 @@ draw_shadow_corner (cairo_t *cr,
g_hash_table_insert (corner_mask_cache, g_memdup2 (&key, sizeof (key)), mask);
}
gdk_cairo_set_source_rgba_ccs (cr, ccs, color);
gdk_cairo_set_source_color (cr, ccs, color);
pattern = cairo_pattern_create_for_surface (mask);
cairo_matrix_init_identity (&matrix);
cairo_matrix_scale (&matrix, sx, sy);
@@ -2460,7 +2555,7 @@ draw_shadow_side (cairo_t *cr,
const GskRoundedRect *box,
const GskRoundedRect *clip_box,
float radius,
const GdkRGBA *color,
const GdkColor *color,
Side side,
cairo_rectangle_int_t *drawn_rect)
{
@@ -2537,7 +2632,7 @@ gsk_inset_shadow_node_draw (GskRenderNode *node,
double blur_radius;
/* We don't need to draw invisible shadows */
if (gdk_rgba_is_clear (&self->color))
if (gdk_color_is_clear (&self->color))
return;
_graphene_rect_init_from_clip_extents (&clip_rect, cr);
@@ -2554,14 +2649,16 @@ gsk_inset_shadow_node_draw (GskRenderNode *node,
cairo_clip (cr);
gsk_rounded_rect_init_copy (&box, &self->outline);
gsk_rounded_rect_offset (&box, self->dx, self->dy);
gsk_rounded_rect_offset (&box, self->offset.x, self->offset.y);
gsk_rounded_rect_shrink (&box, self->spread, self->spread, self->spread, self->spread);
gsk_rounded_rect_init_copy (&clip_box, &self->outline);
gsk_rounded_rect_shrink (&clip_box, -clip_radius, -clip_radius, -clip_radius, -clip_radius);
if (!needs_blur (blur_radius))
draw_shadow (cr, ccs, TRUE, &box, &clip_box, blur_radius, &self->color, GSK_BLUR_NONE);
{
draw_shadow (cr, ccs, TRUE, &box, &clip_box, blur_radius, &self->color, GSK_BLUR_NONE);
}
else
{
cairo_region_t *remaining;
@@ -2633,9 +2730,8 @@ gsk_inset_shadow_node_diff (GskRenderNode *node1,
GskInsetShadowNode *self2 = (GskInsetShadowNode *) node2;
if (gsk_rounded_rect_equal (&self1->outline, &self2->outline) &&
gdk_rgba_equal (&self1->color, &self2->color) &&
self1->dx == self2->dx &&
self1->dy == self2->dy &&
gdk_color_equal (&self1->color, &self2->color) &&
graphene_point_equal (&self1->offset, &self2->offset) &&
self1->spread == self2->spread &&
self1->blur_radius == self2->blur_radius)
return;
@@ -2651,6 +2747,7 @@ gsk_inset_shadow_node_class_init (gpointer g_class,
node_class->node_type = GSK_INSET_SHADOW_NODE;
node_class->finalize = gsk_inset_shadow_node_finalize;
node_class->draw = gsk_inset_shadow_node_draw;
node_class->diff = gsk_inset_shadow_node_diff;
}
@@ -2676,23 +2773,56 @@ gsk_inset_shadow_node_new (const GskRoundedRect *outline,
float dy,
float spread,
float blur_radius)
{
GdkColor color2;
GskRenderNode *node;
gdk_color_init_from_rgba (&color2, color);
node = gsk_inset_shadow_node_new2 (outline,
&color2,
&GRAPHENE_POINT_INIT (dx, dy),
spread, blur_radius);
gdk_color_finish (&color2);
return node;
}
/*< private >
* gsk_inset_shadow_node_new2:
* @outline: outline of the region containing the shadow
* @color: color of the shadow
* @offset: offset of shadow
* @spread: how far the shadow spreads towards the inside
* @blur_radius: how much blur to apply to the shadow
*
* Creates a `GskRenderNode` that will render an inset shadow
* into the box given by @outline.
*
* Returns: (transfer full) (type GskInsetShadowNode): A new `GskRenderNode`
*/
GskRenderNode *
gsk_inset_shadow_node_new2 (const GskRoundedRect *outline,
const GdkColor *color,
const graphene_point_t *offset,
float spread,
float blur_radius)
{
GskInsetShadowNode *self;
GskRenderNode *node;
g_return_val_if_fail (outline != NULL, NULL);
g_return_val_if_fail (color != NULL, NULL);
g_return_val_if_fail (offset != NULL, NULL);
g_return_val_if_fail (blur_radius >= 0, NULL);
self = gsk_render_node_alloc (GSK_INSET_SHADOW_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->preferred_depth = my_color_get_depth (color);
node->preferred_depth = gdk_color_get_depth (color);
gsk_rounded_rect_init_copy (&self->outline, outline);
self->color = *color;
self->dx = dx;
self->dy = dy;
gdk_color_init_copy (&self->color, color);
self->offset = *offset;
self->spread = spread;
self->blur_radius = blur_radius;
@@ -2723,6 +2853,9 @@ gsk_inset_shadow_node_get_outline (const GskRenderNode *node)
*
* Retrieves the color of the inset shadow.
*
* The value returned by this function will not be correct
* if the render node was created for a non-sRGB color.
*
* Returns: (transfer none): the color of the shadow
*/
const GdkRGBA *
@@ -2730,6 +2863,23 @@ gsk_inset_shadow_node_get_color (const GskRenderNode *node)
{
const GskInsetShadowNode *self = (const GskInsetShadowNode *) node;
/* NOTE: This is only correct for nodes with sRGB colors */
return (const GdkRGBA *) &self->color.values;
}
/*< private >
* gsk_inset_shadow_node_get_color2:
* @node: (type GskInsetShadowNode): a `GskRenderNode`
*
* Retrieves the color of the given @node.
*
* Returns: (transfer none): the color of the node
*/
const GdkColor *
gsk_inset_shadow_node_get_color2 (const GskRenderNode *node)
{
const GskInsetShadowNode *self = (const GskInsetShadowNode *) node;
return &self->color;
}
@@ -2746,7 +2896,7 @@ gsk_inset_shadow_node_get_dx (const GskRenderNode *node)
{
const GskInsetShadowNode *self = (const GskInsetShadowNode *) node;
return self->dx;
return self->offset.x;
}
/**
@@ -2762,7 +2912,23 @@ gsk_inset_shadow_node_get_dy (const GskRenderNode *node)
{
const GskInsetShadowNode *self = (const GskInsetShadowNode *) node;
return self->dy;
return self->offset.y;
}
/**
* gsk_inset_shadow_node_get_offset:
* @node: (type GskInsetShadowNode): a `GskRenderNode` for an inset shadow
*
* Retrieves the offset of the inset shadow.
*
* Returns: an offset, in pixels
**/
const graphene_point_t *
gsk_inset_shadow_node_get_offset (const GskRenderNode *node)
{
const GskInsetShadowNode *self = (const GskInsetShadowNode *) node;
return &self->offset;
}
/**
@@ -2810,13 +2976,23 @@ struct _GskOutsetShadowNode
GskRenderNode render_node;
GskRoundedRect outline;
GdkRGBA color;
float dx;
float dy;
GdkColor color;
graphene_point_t offset;
float spread;
float blur_radius;
};
static void
gsk_outset_shadow_node_finalize (GskRenderNode *node)
{
GskInsetShadowNode *self = (GskInsetShadowNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_OUTSET_SHADOW_NODE));
gdk_color_finish (&self->color);
parent_class->finalize (node);
}
static void
gsk_outset_shadow_get_extents (GskOutsetShadowNode *self,
float *top,
@@ -2827,10 +3003,10 @@ gsk_outset_shadow_get_extents (GskOutsetShadowNode *self,
float clip_radius;
clip_radius = gsk_cairo_blur_compute_pixels (ceil (self->blur_radius / 2.0));
*top = MAX (0, ceil (clip_radius + self->spread - self->dy));
*right = MAX (0, ceil (clip_radius + self->spread + self->dx));
*bottom = MAX (0, ceil (clip_radius + self->spread + self->dy));
*left = MAX (0, ceil (clip_radius + self->spread - self->dx));
*top = MAX (0, ceil (clip_radius + self->spread - self->offset.y));
*right = MAX (0, ceil (clip_radius + self->spread + self->offset.x));
*bottom = MAX (0, ceil (clip_radius + self->spread + self->offset.y));
*left = MAX (0, ceil (clip_radius + self->spread - self->offset.x));
}
static void
@@ -2846,7 +3022,7 @@ gsk_outset_shadow_node_draw (GskRenderNode *node,
double blur_radius;
/* We don't need to draw invisible shadows */
if (gdk_rgba_is_clear (&self->color))
if (gdk_color_is_clear (&self->color))
return;
_graphene_rect_init_from_clip_extents (&clip_rect, cr);
@@ -2870,11 +3046,13 @@ gsk_outset_shadow_node_draw (GskRenderNode *node,
cairo_clip (cr);
gsk_rounded_rect_init_copy (&box, &self->outline);
gsk_rounded_rect_offset (&box, self->dx, self->dy);
gsk_rounded_rect_offset (&box, self->offset.x, self->offset.y);
gsk_rounded_rect_shrink (&box, -self->spread, -self->spread, -self->spread, -self->spread);
if (!needs_blur (blur_radius))
draw_shadow (cr, ccs, FALSE, &box, &clip_box, blur_radius, &self->color, GSK_BLUR_NONE);
{
draw_shadow (cr, ccs, FALSE, &box, &clip_box, blur_radius, &self->color, GSK_BLUR_NONE);
}
else
{
int i;
@@ -2948,9 +3126,8 @@ gsk_outset_shadow_node_diff (GskRenderNode *node1,
GskOutsetShadowNode *self2 = (GskOutsetShadowNode *) node2;
if (gsk_rounded_rect_equal (&self1->outline, &self2->outline) &&
gdk_rgba_equal (&self1->color, &self2->color) &&
self1->dx == self2->dx &&
self1->dy == self2->dy &&
gdk_color_equal (&self1->color, &self2->color) &&
graphene_point_equal (&self1->offset, &self2->offset) &&
self1->spread == self2->spread &&
self1->blur_radius == self2->blur_radius)
return;
@@ -2966,6 +3143,7 @@ gsk_outset_shadow_node_class_init (gpointer g_class,
node_class->node_type = GSK_OUTSET_SHADOW_NODE;
node_class->finalize = gsk_outset_shadow_node_finalize;
node_class->draw = gsk_outset_shadow_node_draw;
node_class->diff = gsk_outset_shadow_node_diff;
}
@@ -2991,6 +3169,39 @@ gsk_outset_shadow_node_new (const GskRoundedRect *outline,
float dy,
float spread,
float blur_radius)
{
GdkColor color2;
GskRenderNode *node;
gdk_color_init_from_rgba (&color2, color);
node = gsk_outset_shadow_node_new2 (outline,
&color2,
&GRAPHENE_POINT_INIT (dx, dy),
spread, blur_radius);
gdk_color_finish (&color2);
return node;
}
/*< private >
* gsk_outset_shadow_node_new2:
* @outline: outline of the region surrounded by shadow
* @color: color of the shadow
* @offset: offset of shadow
* @spread: how far the shadow spreads towards the inside
* @blur_radius: how much blur to apply to the shadow
*
* Creates a `GskRenderNode` that will render an outset shadow
* around the box given by @outline.
*
* Returns: (transfer full) (type GskOutsetShadowNode): A new `GskRenderNode`
*/
GskRenderNode *
gsk_outset_shadow_node_new2 (const GskRoundedRect *outline,
const GdkColor *color,
const graphene_point_t *offset,
float spread,
float blur_radius)
{
GskOutsetShadowNode *self;
GskRenderNode *node;
@@ -3003,12 +3214,11 @@ gsk_outset_shadow_node_new (const GskRoundedRect *outline,
self = gsk_render_node_alloc (GSK_OUTSET_SHADOW_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->preferred_depth = my_color_get_depth (color);
node->preferred_depth = gdk_color_get_depth (color);
gsk_rounded_rect_init_copy (&self->outline, outline);
self->color = *color;
self->dx = dx;
self->dy = dy;
gdk_color_init_copy (&self->color, color);
self->offset = *offset;
self->spread = spread;
self->blur_radius = blur_radius;
@@ -3045,6 +3255,9 @@ gsk_outset_shadow_node_get_outline (const GskRenderNode *node)
*
* Retrieves the color of the outset shadow.
*
* The value returned by this function will not be correct
* if the render node was created for a non-sRGB color.
*
* Returns: (transfer none): a color
*/
const GdkRGBA *
@@ -3052,6 +3265,23 @@ gsk_outset_shadow_node_get_color (const GskRenderNode *node)
{
const GskOutsetShadowNode *self = (const GskOutsetShadowNode *) node;
/* NOTE: This is only correct for nodes with sRGB colors */
return (const GdkRGBA *) &self->color.values;
}
/*< private >
* gsk_color_node_get_color2:
* @node: (type GskOutsetShadowNode): a `GskRenderNode`
*
* Retrieves the color of the given @node.
*
* Returns: (transfer none): the color of the node
*/
const GdkColor *
gsk_outset_shadow_node_get_color2 (const GskRenderNode *node)
{
const GskOutsetShadowNode *self = (const GskOutsetShadowNode *) node;
return &self->color;
}
@@ -3068,7 +3298,7 @@ gsk_outset_shadow_node_get_dx (const GskRenderNode *node)
{
const GskOutsetShadowNode *self = (const GskOutsetShadowNode *) node;
return self->dx;
return self->offset.x;
}
/**
@@ -3084,7 +3314,23 @@ gsk_outset_shadow_node_get_dy (const GskRenderNode *node)
{
const GskOutsetShadowNode *self = (const GskOutsetShadowNode *) node;
return self->dy;
return self->offset.y;
}
/**
* gsk_outset_shadow_node_get_offset:
* @node: (type GskOutsetShadowNode): a `GskRenderNode` for an outset shadow
*
* Retrieves the offset of the outset shadow.
*
* Returns: an offset, in pixels
**/
const graphene_point_t *
gsk_outset_shadow_node_get_offset (const GskRenderNode *node)
{
const GskOutsetShadowNode *self = (const GskOutsetShadowNode *) node;
return &self->offset;
}
/**
@@ -5343,7 +5589,9 @@ struct _GskShadowNode
GskRenderNode *child;
gsize n_shadows;
GskShadow *shadows;
GskShadow2 *shadows;
GskShadow *rgba_shadows;
};
static void
@@ -5353,8 +5601,13 @@ gsk_shadow_node_finalize (GskRenderNode *node)
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_SHADOW_NODE));
gsk_render_node_unref (self->child);
for (gsize i = 0; i < self->n_shadows; i++)
gdk_color_finish (&self->shadows[i].color);
g_free (self->shadows);
g_free (self->rgba_shadows);
parent_class->finalize (node);
}
@@ -5374,23 +5627,23 @@ gsk_shadow_node_draw (GskRenderNode *node,
for (i = 0; i < self->n_shadows; i++)
{
GskShadow *shadow = &self->shadows[i];
GskShadow2 *shadow = &self->shadows[i];
cairo_pattern_t *pattern;
/* We don't need to draw invisible shadows */
if (gdk_rgba_is_clear (&shadow->color))
if (gdk_color_is_clear (&shadow->color))
continue;
cairo_save (cr);
cr = gsk_cairo_blur_start_drawing (cr, 0.5 * shadow->radius, GSK_BLUR_X | GSK_BLUR_Y);
cairo_save (cr);
cairo_translate (cr, shadow->dx, shadow->dy);
cairo_translate (cr, shadow->offset.x, shadow->offset.y);
cairo_push_group (cr);
gsk_render_node_draw_ccs (self->child, cr, ccs);
pattern = cairo_pop_group (cr);
cairo_reset_clip (cr);
gdk_cairo_set_source_rgba_ccs (cr, ccs, &shadow->color);
gdk_cairo_set_source_color (cr, ccs, &shadow->color);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
cairo_restore (cr);
@@ -5422,13 +5675,12 @@ gsk_shadow_node_diff (GskRenderNode *node1,
for (i = 0; i < self1->n_shadows; i++)
{
GskShadow *shadow1 = &self1->shadows[i];
GskShadow *shadow2 = &self2->shadows[i];
GskShadow2 *shadow1 = &self1->shadows[i];
GskShadow2 *shadow2 = &self2->shadows[i];
float clip_radius;
if (!gdk_rgba_equal (&shadow1->color, &shadow2->color) ||
shadow1->dx != shadow2->dx ||
shadow1->dy != shadow2->dy ||
if (!gdk_color_equal (&shadow1->color, &shadow2->color) ||
!graphene_point_equal (&shadow1->offset, &shadow2->offset) ||
shadow1->radius != shadow2->radius)
{
gsk_render_node_diff_impossible (node1, node2, data);
@@ -5436,10 +5688,10 @@ gsk_shadow_node_diff (GskRenderNode *node1,
}
clip_radius = gsk_cairo_blur_compute_pixels (shadow1->radius / 2.0);
top = MAX (top, ceil (clip_radius - shadow1->dy));
right = MAX (right, ceil (clip_radius + shadow1->dx));
bottom = MAX (bottom, ceil (clip_radius + shadow1->dy));
left = MAX (left, ceil (clip_radius - shadow1->dx));
top = MAX (top, ceil (clip_radius - shadow1->offset.y));
right = MAX (right, ceil (clip_radius + shadow1->offset.x));
bottom = MAX (bottom, ceil (clip_radius + shadow1->offset.y));
left = MAX (left, ceil (clip_radius - shadow1->offset.x));
}
sub = cairo_region_create ();
@@ -5470,10 +5722,10 @@ gsk_shadow_node_get_bounds (GskShadowNode *self,
for (i = 0; i < self->n_shadows; i++)
{
float clip_radius = gsk_cairo_blur_compute_pixels (self->shadows[i].radius / 2.0);
top = MAX (top, clip_radius - self->shadows[i].dy);
right = MAX (right, clip_radius + self->shadows[i].dx);
bottom = MAX (bottom, clip_radius + self->shadows[i].dy);
left = MAX (left, clip_radius - self->shadows[i].dx);
top = MAX (top, clip_radius - self->shadows[i].offset.y);
right = MAX (right, clip_radius + self->shadows[i].offset.x);
bottom = MAX (bottom, clip_radius + self->shadows[i].offset.y);
left = MAX (left, clip_radius - self->shadows[i].offset.x);
}
bounds->origin.x -= left;
@@ -5510,10 +5762,52 @@ GskRenderNode *
gsk_shadow_node_new (GskRenderNode *child,
const GskShadow *shadows,
gsize n_shadows)
{
GskShadow2 *shadows2;
GskRenderNode *node;
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
g_return_val_if_fail (shadows != NULL, NULL);
g_return_val_if_fail (n_shadows > 0, NULL);
shadows2 = g_new (GskShadow2, n_shadows);
for (gsize i = 0; i < n_shadows; i++)
{
gdk_color_init_from_rgba (&shadows2[i].color, &shadows[i].color);
graphene_point_init (&shadows2[i].offset, shadows[i].dx, shadows[i].dy);
shadows2[i].radius = shadows[i].radius;
}
node = gsk_shadow_node_new2 (child, shadows2, n_shadows);
for (gsize i = 0; i < n_shadows; i++)
gdk_color_finish (&shadows2[i].color);
g_free (shadows2);
return node;
}
/*< private >
* gsk_shadow_node_new2:
* @child: The node to draw
* @shadows: (array length=n_shadows): The shadows to apply
* @n_shadows: number of entries in the @shadows array
*
* Creates a `GskRenderNode` that will draw a @child with the given
* @shadows below it.
*
* Returns: (transfer full) (type GskShadowNode): A new `GskRenderNode`
*/
GskRenderNode *
gsk_shadow_node_new2 (GskRenderNode *child,
const GskShadow2 *shadows,
gsize n_shadows)
{
GskShadowNode *self;
GskRenderNode *node;
gsize i;
GdkMemoryDepth depth;
gboolean is_hdr;
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
g_return_val_if_fail (shadows != NULL, NULL);
@@ -5525,19 +5819,25 @@ gsk_shadow_node_new (GskRenderNode *child,
self->child = gsk_render_node_ref (child);
self->n_shadows = n_shadows;
self->shadows = g_malloc_n (n_shadows, sizeof (GskShadow));
memcpy (self->shadows, shadows, n_shadows * sizeof (GskShadow));
self->shadows = g_new (GskShadow2, n_shadows);
gsk_shadow_node_get_bounds (self, &node->bounds);
depth = gsk_render_node_get_preferred_depth (child);
is_hdr = gsk_render_node_is_hdr (child);
node->preferred_depth = gsk_render_node_get_preferred_depth (child);
node->is_hdr = gsk_render_node_is_hdr (child);
for (i = 0; i < n_shadows; i++)
{
node->preferred_depth = gdk_memory_depth_merge (node->preferred_depth,
my_color_get_depth (&shadows->color));
gdk_color_init_copy (&self->shadows[i].color, &shadows[i].color);
graphene_point_init_from_point (&self->shadows[i].offset, &shadows[i].offset);
self->shadows[i].radius = shadows[i].radius;
depth = gdk_memory_depth_merge (depth, gdk_color_get_depth (&shadows[i].color));
is_hdr = is_hdr || color_state_is_hdr (shadows[i].color.color_state);
}
node->preferred_depth = depth;
node->is_hdr = is_hdr;
gsk_shadow_node_get_bounds (self, &node->bounds);
return node;
}
@@ -5569,6 +5869,45 @@ gsk_shadow_node_get_child (const GskRenderNode *node)
const GskShadow *
gsk_shadow_node_get_shadow (const GskRenderNode *node,
gsize i)
{
GskShadowNode *self = (GskShadowNode *) node;
const GskShadow *shadow;
G_LOCK (rgba);
if (self->rgba_shadows == NULL)
{
self->rgba_shadows = g_new (GskShadow, self->n_shadows);
for (gsize j = 0; j < self->n_shadows; j++)
{
gdk_color_to_float (&self->shadows[j].color,
GDK_COLOR_STATE_SRGB,
(float *) &self->rgba_shadows[j].color);
self->rgba_shadows[j].dx = self->shadows[j].offset.x;
self->rgba_shadows[j].dy = self->shadows[j].offset.y;
self->rgba_shadows[j].radius = self->shadows[j].radius;
}
}
shadow = &self->rgba_shadows[i];
G_UNLOCK (rgba);
return shadow;
}
/*< private >
* gsk_shadow_node_get_shadow2:
* @node: (type GskShadowNode): a shadow `GskRenderNode`
* @i: the given index
*
* Retrieves the shadow data at the given index @i.
*
* Returns: (transfer none): the shadow data
*/
const GskShadow2 *
gsk_shadow_node_get_shadow2 (const GskRenderNode *node,
gsize i)
{
const GskShadowNode *self = (const GskShadowNode *) node;
+167 -124
View File
@@ -41,6 +41,7 @@
#include "gtk/css/gtkcssdataurlprivate.h"
#include "gtk/css/gtkcssparserprivate.h"
#include "gtk/css/gtkcssserializerprivate.h"
#include "gdk/loaders/gdkavifprivate.h"
#ifdef CAIRO_HAS_SCRIPT_SURFACE
#include <cairo-script.h>
@@ -216,11 +217,19 @@ parse_texture (GtkCssParser *parser,
if (scheme && g_ascii_strcasecmp (scheme, "data") == 0)
{
GBytes *bytes;
char *mimetype;
bytes = gtk_css_data_url_parse (url, NULL, &error);
bytes = gtk_css_data_url_parse (url, &mimetype, &error);
if (bytes)
{
texture = gdk_texture_new_from_bytes (bytes, &error);
#ifdef HAVE_AVIF
if (strcmp (mimetype, "image/avif") == 0)
texture = gdk_load_avif (bytes, &error);
else
#endif
texture = gdk_texture_new_from_bytes (bytes, &error);
g_free (mimetype);
g_bytes_unref (bytes);
}
else
@@ -693,33 +702,9 @@ parse_float4 (GtkCssParser *parser,
return TRUE;
}
static gboolean
parse_colors4 (GtkCssParser *parser,
Context *context,
gpointer out_colors)
{
GdkRGBA colors[4];
int i;
for (i = 0; i < 4 && !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF); i ++)
{
if (!gdk_rgba_parser_parse (parser, &colors[i]))
return FALSE;
}
if (i == 0)
{
gtk_css_parser_error_syntax (parser, "Expected a color");
return FALSE;
}
for (; i < 4; i++)
{
colors[i] = colors[(i - 1) >> 1];
}
memcpy (out_colors, colors, sizeof (GdkRGBA) * 4);
return TRUE;
}
static gboolean parse_color2 (GtkCssParser *parser,
Context *context,
gpointer color);
static gboolean
parse_shadows (GtkCssParser *parser,
@@ -730,10 +715,11 @@ parse_shadows (GtkCssParser *parser,
do
{
GskShadow shadow = { GDK_RGBA("000000"), 0, 0, 0 };
GskShadow2 shadow;
GdkColor color = GDK_COLOR_SRGB (0, 0, 0, 1);
double dx = 0, dy = 0, radius = 0;
if (!gdk_rgba_parser_parse (parser, &shadow.color))
if (!parse_color2 (parser, context, &color))
gtk_css_parser_error_value (parser, "Expected shadow color");
if (!gtk_css_parser_consume_number (parser, &dx))
@@ -748,11 +734,13 @@ parse_shadows (GtkCssParser *parser,
gtk_css_parser_error_value (parser, "Expected shadow blur radius");
}
shadow.dx = dx;
shadow.dy = dy;
gdk_color_init_copy (&shadow.color, &color);
graphene_point_init (&shadow.offset, dx, dy);
shadow.radius = radius;
g_array_append_val (shadows, shadow);
gdk_color_finish (&color);
}
while (gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COMMA));
@@ -762,7 +750,15 @@ parse_shadows (GtkCssParser *parser,
static void
clear_shadows (gpointer inout_shadows)
{
g_array_set_size (inout_shadows, 0);
GArray *shadows = inout_shadows;
for (gsize i = 0; i < shadows->len; i++)
{
GskShadow2 *shadow = &g_array_index (shadows, GskShadow2, i);
gdk_color_finish (&shadow->color);
}
g_array_set_size (shadows, 0);
}
static const struct
@@ -1465,12 +1461,6 @@ create_default_path (void)
return gsk_path_builder_free_to_path (builder);
}
typedef struct
{
GdkColorState *color_state;
float values[4];
} Color;
static gboolean
parse_cicp_range (GtkCssParser *parser,
Context *context,
@@ -1606,35 +1596,6 @@ parse_color_state (GtkCssParser *parser,
return TRUE;
}
static gboolean
gtk_css_parser_consume_number_or_percentage (GtkCssParser *parser,
double min,
double max,
double *value)
{
if (gtk_css_parser_has_percentage (parser))
{
double number;
gtk_css_parser_consume_percentage (parser, &number);
*value = min + (number / 100.0) * (max - min);
return TRUE;
}
else if (gtk_css_parser_has_number (parser))
{
double number;
gtk_css_parser_consume_number (parser, &number);
*value = number;
return TRUE;
}
else
{
gtk_css_parser_error_syntax (parser, "Expected a number or percentage");
return FALSE;
}
}
typedef struct {
Context *context;
GdkColor *color;
@@ -1705,6 +1666,34 @@ parse_color2 (GtkCssParser *parser,
return FALSE;
}
static gboolean
parse_colors4 (GtkCssParser *parser,
Context *context,
gpointer out_colors)
{
GdkColor colors[4];
int i;
for (i = 0; i < 4 && !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF); i ++)
{
if (!parse_color2 (parser, context, &colors[i]))
return FALSE;
}
if (i == 0)
{
gtk_css_parser_error_syntax (parser, "Expected a color");
return FALSE;
}
for (; i < 4; i++)
{
colors[i] = colors[(i - 1) >> 1];
}
memcpy (out_colors, colors, sizeof (GdkColor) * 4);
return TRUE;
}
static GskRenderNode *
parse_color_node (GtkCssParser *parser,
Context *context)
@@ -1878,20 +1867,25 @@ parse_inset_shadow_node (GtkCssParser *parser,
Context *context)
{
GskRoundedRect outline = GSK_ROUNDED_RECT_INIT (0, 0, 50, 50);
GdkRGBA color = GDK_RGBA("000000");
GdkColor color = GDK_COLOR_SRGB (0, 0, 0, 1);
double dx = 1, dy = 1, blur = 0, spread = 0;
const Declaration declarations[] = {
{ "outline", parse_rounded_rect, NULL, &outline },
{ "color", parse_color, NULL, &color },
{ "color", parse_color2, NULL, &color },
{ "dx", parse_double, NULL, &dx },
{ "dy", parse_double, NULL, &dy },
{ "spread", parse_double, NULL, &spread },
{ "blur", parse_positive_double, NULL, &blur }
};
GskRenderNode *node;
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
return gsk_inset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
node = gsk_inset_shadow_node_new2 (&outline, &color, &GRAPHENE_POINT_INIT (dx, dy), spread, blur);
gdk_color_finish (&color);
return node;
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -2173,16 +2167,21 @@ parse_border_node (GtkCssParser *parser,
{
GskRoundedRect outline = GSK_ROUNDED_RECT_INIT (0, 0, 50, 50);
float widths[4] = { 1, 1, 1, 1 };
GdkRGBA colors[4] = { GDK_RGBA("000"), GDK_RGBA("000"), GDK_RGBA("000"), GDK_RGBA("000") };
GdkColor colors[4] = {
GDK_COLOR_SRGB (0, 0, 0, 1),
GDK_COLOR_SRGB (0, 0, 0, 1),
GDK_COLOR_SRGB (0, 0, 0, 1),
GDK_COLOR_SRGB (0, 0, 0, 1),
};
const Declaration declarations[] = {
{ "outline", parse_rounded_rect, NULL, &outline },
{ "widths", parse_float4, NULL, &widths },
{ "colors", parse_colors4, NULL, &colors }
{ "colors", parse_colors4, NULL, &colors },
};
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
return gsk_border_node_new (&outline, widths, colors);
return gsk_border_node_new2 (&outline, widths, colors);
}
static GskRenderNode *
@@ -2282,20 +2281,25 @@ parse_outset_shadow_node (GtkCssParser *parser,
Context *context)
{
GskRoundedRect outline = GSK_ROUNDED_RECT_INIT (0, 0, 50, 50);
GdkRGBA color = GDK_RGBA("000000");
GdkColor color = GDK_COLOR_SRGB (0, 0, 0, 1);
double dx = 1, dy = 1, blur = 0, spread = 0;
const Declaration declarations[] = {
{ "outline", parse_rounded_rect, NULL, &outline },
{ "color", parse_color, NULL, &color },
{ "color", parse_color2, NULL, &color },
{ "dx", parse_double, NULL, &dx },
{ "dy", parse_double, NULL, &dy },
{ "spread", parse_double, NULL, &spread },
{ "blur", parse_positive_double, NULL, &blur }
};
GskRenderNode *node;
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
return gsk_outset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
node = gsk_outset_shadow_node_new2 (&outline, &color, &GRAPHENE_POINT_INIT (dx, dy), spread, blur);
gdk_color_finish (&color);
return node;
}
static GskRenderNode *
@@ -2920,10 +2924,10 @@ parse_shadow_node (GtkCssParser *parser,
Context *context)
{
GskRenderNode *child = NULL;
GArray *shadows = g_array_new (FALSE, TRUE, sizeof (GskShadow));
GArray *shadows = g_array_new (FALSE, TRUE, sizeof (GskShadow2));
const Declaration declarations[] = {
{ "child", parse_node, clear_node, &child },
{ "shadows", parse_shadows, clear_shadows, shadows }
{ "shadows", parse_shadows, clear_shadows, shadows },
};
GskRenderNode *result;
@@ -2933,12 +2937,13 @@ parse_shadow_node (GtkCssParser *parser,
if (shadows->len == 0)
{
GskShadow default_shadow = { GDK_RGBA("000000"), 1, 1, 0 };
GskShadow2 default_shadow = { GDK_COLOR_SRGB (0, 0, 0, 1), GRAPHENE_POINT_INIT (1, 1), 0 };
g_array_append_val (shadows, default_shadow);
}
result = gsk_shadow_node_new (child, (GskShadow *)shadows->data, shadows->len);
result = gsk_shadow_node_new2 (child, (GskShadow2 *)shadows->data, shadows->len);
clear_shadows (shadows);
g_array_free (shadows, TRUE);
gsk_render_node_unref (child);
@@ -3311,15 +3316,28 @@ printer_init_duplicates_for_node (Printer *printer,
printer_init_check_color_state (printer, gsk_color_node_get_color2 (node)->color_state);
break;
case GSK_BORDER_NODE:
{
const GdkColor *colors = gsk_border_node_get_colors2 (node);
for (int i = 0; i < 4; i++)
printer_init_check_color_state (printer, colors[i].color_state);
}
break;
case GSK_INSET_SHADOW_NODE:
printer_init_check_color_state (printer, gsk_inset_shadow_node_get_color2 (node)->color_state);
break;
case GSK_OUTSET_SHADOW_NODE:
printer_init_check_color_state (printer, gsk_outset_shadow_node_get_color2 (node)->color_state);
break;
case GSK_CAIRO_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_CONIC_GRADIENT_NODE:
case GSK_BORDER_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
/* no children */
break;
@@ -3361,6 +3379,11 @@ printer_init_duplicates_for_node (Printer *printer,
case GSK_SHADOW_NODE:
printer_init_duplicates_for_node (printer, gsk_shadow_node_get_child (node));
for (int i = 0; i < gsk_shadow_node_get_n_shadows (node); i++)
{
const GskShadow2 * shadow = gsk_shadow_node_get_shadow2 (node, i);
printer_init_check_color_state (printer, shadow->color.color_state);
}
break;
case GSK_DEBUG_NODE:
@@ -3908,12 +3931,27 @@ base64_encode_with_linebreaks (const guchar *data,
return out;
}
#ifdef HAVE_AVIF
static gboolean
texture_should_use_avif (GdkTexture *texture)
{
GdkColorState *color_state;
const GdkCicp *cicp;
color_state = gdk_texture_get_color_state (texture);
cicp = gdk_color_state_get_cicp (color_state);
return cicp->matrix_coefficients != 0;
}
#endif
static void
append_texture_param (Printer *p,
const char *param_name,
GdkTexture *texture)
{
GBytes *bytes;
const char *mimetype;
char *b64;
const char *texture_name;
@@ -3942,26 +3980,38 @@ append_texture_param (Printer *p,
g_hash_table_insert (p->named_textures, texture, new_name);
}
switch (gdk_texture_get_depth (texture))
#ifdef HAVE_AVIF
if (texture_should_use_avif (texture))
{
case GDK_MEMORY_U8:
case GDK_MEMORY_U8_SRGB:
case GDK_MEMORY_U16:
bytes = gdk_texture_save_to_png_bytes (texture);
g_string_append (p->str, "url(\"data:image/png;base64,\\\n");
break;
case GDK_MEMORY_FLOAT16:
case GDK_MEMORY_FLOAT32:
bytes = gdk_texture_save_to_tiff_bytes (texture);
g_string_append (p->str, "url(\"data:image/tiff;base64,\\\n");
break;
case GDK_MEMORY_NONE:
case GDK_N_DEPTHS:
default:
g_assert_not_reached ();
bytes = gdk_save_avif (texture);
mimetype = "image/avif";
}
else
#endif
{
switch (gdk_texture_get_depth (texture))
{
case GDK_MEMORY_U8:
case GDK_MEMORY_U8_SRGB:
case GDK_MEMORY_U16:
bytes = gdk_texture_save_to_png_bytes (texture);
mimetype = "image/png";
break;
case GDK_MEMORY_FLOAT16:
case GDK_MEMORY_FLOAT32:
bytes = gdk_texture_save_to_tiff_bytes (texture);
mimetype = "image/tiff";
break;
case GDK_MEMORY_NONE:
case GDK_N_DEPTHS:
default:
g_assert_not_reached ();
}
}
g_string_append_printf (p->str, "url(\"data:%s;base64,\\\n", mimetype);
b64 = base64_encode_with_linebreaks (g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
@@ -4322,13 +4372,11 @@ render_node_print (Printer *p,
case GSK_OUTSET_SHADOW_NODE:
{
const GdkRGBA *color = gsk_outset_shadow_node_get_color (node);
start_node (p, "outset-shadow", node_name);
append_float_param (p, "blur", gsk_outset_shadow_node_get_blur_radius (node), 0.0f);
if (!gdk_rgba_equal (color, &GDK_RGBA("000")))
append_rgba_param (p, "color", color);
if (!gdk_color_equal (gsk_outset_shadow_node_get_color2 (node), &GDK_COLOR_SRGB (0, 0, 0, 1)))
append_color_param (p, "color", gsk_outset_shadow_node_get_color2 (node));
append_float_param (p, "dx", gsk_outset_shadow_node_get_dx (node), 1.0f);
append_float_param (p, "dy", gsk_outset_shadow_node_get_dy (node), 1.0f);
append_rounded_rect_param (p, "outline", gsk_outset_shadow_node_get_outline (node));
@@ -4426,18 +4474,18 @@ render_node_print (Printer *p,
case GSK_BORDER_NODE:
{
const GdkRGBA *colors = gsk_border_node_get_colors (node);
const GdkColor *colors = gsk_border_node_get_colors2 (node);
const float *widths = gsk_border_node_get_widths (node);
guint i, n;
start_node (p, "border", node_name);
if (!gdk_rgba_equal (&colors[3], &colors[1]))
if (!gdk_color_equal (&colors[3], &colors[1]))
n = 4;
else if (!gdk_rgba_equal (&colors[2], &colors[0]))
else if (!gdk_color_equal (&colors[2], &colors[0]))
n = 3;
else if (!gdk_rgba_equal (&colors[1], &colors[0]))
else if (!gdk_color_equal (&colors[1], &colors[0]))
n = 2;
else if (!gdk_rgba_equal (&colors[0], &GDK_RGBA("000000")))
else if (!gdk_color_equal (&colors[0], (&(GdkColor) { .color_state = GDK_COLOR_STATE_SRGB, .values = { 0, 0, 0, 1 } })))
n = 1;
else
n = 0;
@@ -4450,7 +4498,7 @@ render_node_print (Printer *p,
{
if (i > 0)
g_string_append_c (p->str, ' ');
gdk_rgba_print (&colors[i], p->str);
print_color (p, &colors[i]);
}
g_string_append (p->str, ";\n");
}
@@ -4496,25 +4544,21 @@ render_node_print (Printer *p,
g_string_append (p->str, "shadows: ");
for (i = 0; i < n_shadows; i ++)
{
const GskShadow *s = gsk_shadow_node_get_shadow (node, i);
char *color;
const GskShadow2 *s = gsk_shadow_node_get_shadow2 (node, i);
if (i > 0)
g_string_append (p->str, ", ");
color = gdk_rgba_to_string (&s->color);
g_string_append (p->str, color);
print_color (p, &s->color);
g_string_append_c (p->str, ' ');
string_append_double (p->str, s->dx);
string_append_double (p->str, s->offset.x);
g_string_append_c (p->str, ' ');
string_append_double (p->str, s->dy);
string_append_double (p->str, s->offset.y);
if (s->radius > 0)
{
g_string_append_c (p->str, ' ');
string_append_double (p->str, s->radius);
}
g_free (color);
}
g_string_append_c (p->str, ';');
@@ -4527,12 +4571,11 @@ render_node_print (Printer *p,
case GSK_INSET_SHADOW_NODE:
{
const GdkRGBA *color = gsk_inset_shadow_node_get_color (node);
start_node (p, "inset-shadow", node_name);
append_float_param (p, "blur", gsk_inset_shadow_node_get_blur_radius (node), 0.0f);
if (!gdk_rgba_equal (color, &GDK_RGBA("000")))
append_rgba_param (p, "color", color);
if (!gdk_color_equal (gsk_inset_shadow_node_get_color2 (node), &GDK_COLOR_SRGB (0, 0, 0, 1)))
append_color_param (p, "color", gsk_inset_shadow_node_get_color2 (node));
append_float_param (p, "dx", gsk_inset_shadow_node_get_dx (node), 1.0f);
append_float_param (p, "dy", gsk_inset_shadow_node_get_dy (node), 1.0f);
append_rounded_rect_param (p, "outline", gsk_inset_shadow_node_get_outline (node));
+40 -3
View File
@@ -123,10 +123,47 @@ _gsk_render_node_ref (GskRenderNode *node)
return node;
}
GskRenderNode * gsk_color_node_new2 (const GdkColor *color,
const graphene_rect_t *bounds);
GskRenderNode * gsk_color_node_new2 (const GdkColor *color,
const graphene_rect_t *bounds);
const GdkColor * gsk_color_node_get_color2 (const GskRenderNode *node);
GskRenderNode * gsk_border_node_new2 (const GskRoundedRect *outline,
const float border_width[4],
const GdkColor border_color[4]);
const GdkColor * gsk_border_node_get_colors2 (const GskRenderNode *node);
GskRenderNode * gsk_inset_shadow_node_new2 (const GskRoundedRect *outline,
const GdkColor *color,
const graphene_point_t *offset,
float spread,
float blur_radius);
const GdkColor * gsk_inset_shadow_node_get_color2 (const GskRenderNode *node);
const graphene_point_t *gsk_inset_shadow_node_get_offset (const GskRenderNode *node);
GskRenderNode * gsk_outset_shadow_node_new2 (const GskRoundedRect *outline,
const GdkColor *color,
const graphene_point_t *offset,
float spread,
float blur_radius);
const GdkColor * gsk_outset_shadow_node_get_color2 (const GskRenderNode *node);
const graphene_point_t *gsk_outset_shadow_node_get_offset (const GskRenderNode *node);
typedef struct _GskShadow2 GskShadow2;
struct _GskShadow2
{
GdkColor color;
graphene_point_t offset;
float radius;
};
GskRenderNode * gsk_shadow_node_new2 (GskRenderNode *child,
const GskShadow2 *shadows,
gsize n_shadows);
const GskShadow2 *gsk_shadow_node_get_shadow2 (const GskRenderNode *node,
gsize i);
const GdkColor* gsk_color_node_get_color2 (const GskRenderNode *node);
G_END_DECLS
+29
View File
@@ -1290,6 +1290,35 @@ gtk_css_parser_consume_percentage (GtkCssParser *self,
return FALSE;
}
gboolean
gtk_css_parser_consume_number_or_percentage (GtkCssParser *parser,
double min,
double max,
double *value)
{
double number = 0;
if (gtk_css_parser_has_percentage (parser))
{
if (gtk_css_parser_consume_percentage (parser, &number))
{
*value = min + (number / 100.0) * (max - min);
return TRUE;
}
}
else if (gtk_css_parser_has_number (parser))
{
if (gtk_css_parser_consume_number (parser, &number))
{
*value = number;
return TRUE;
}
}
gtk_css_parser_error_syntax (parser, "Expected a number or percentage");
return FALSE;
}
gsize
gtk_css_parser_consume_any (GtkCssParser *parser,
const GtkCssParseOption *options,
+5
View File
@@ -154,6 +154,11 @@ gboolean gtk_css_parser_consume_integer (GtkCssParser
int *number);
gboolean gtk_css_parser_consume_percentage (GtkCssParser *self,
double *number);
gboolean gtk_css_parser_consume_number_or_percentage
(GtkCssParser *parser,
double min,
double max,
double *value);
gboolean gtk_css_parser_consume_function (GtkCssParser *self,
guint min_args,
guint max_args,
+64 -48
View File
@@ -594,7 +594,7 @@ gtk_css_shadow_value_snapshot_outset (const GtkCssValue *value,
{
guint i;
double dx, dy, spread, radius;
const GdkRGBA *color;
GdkColor color;
g_return_if_fail (value->class == &GTK_CSS_VALUE_SHADOW);
@@ -605,11 +605,14 @@ gtk_css_shadow_value_snapshot_outset (const GtkCssValue *value,
if (shadow->inset)
continue;
color = gtk_css_color_value_get_rgba (shadow->color);
gtk_css_color_to_color (gtk_css_color_value_get_color (shadow->color), &color);
/* We don't need to draw invisible shadows */
if (gdk_rgba_is_clear (color))
continue;
if (gdk_color_is_clear (&color))
{
gdk_color_finish (&color);
continue;
}
dx = gtk_css_number_value_get (shadow->hoffset, 0);
dy = gtk_css_number_value_get (shadow->voffset, 0);
@@ -618,7 +621,11 @@ gtk_css_shadow_value_snapshot_outset (const GtkCssValue *value,
if (value->is_filter)
radius = 2 * radius;
gtk_snapshot_append_outset_shadow (snapshot, border_box, color, dx, dy, spread, radius);
gtk_snapshot_append_outset_shadow2 (snapshot, border_box,
&color,
&GRAPHENE_POINT_INIT (dx, dy),
spread, radius);
gdk_color_finish (&color);
}
}
@@ -629,7 +636,7 @@ gtk_css_shadow_value_snapshot_inset (const GtkCssValue *value,
{
guint i;
double dx, dy, spread, radius;
const GdkRGBA *color;
GdkColor color;
g_return_if_fail (value->class == &GTK_CSS_VALUE_SHADOW);
@@ -640,11 +647,14 @@ gtk_css_shadow_value_snapshot_inset (const GtkCssValue *value,
if (!shadow->inset)
continue;
color = gtk_css_color_value_get_rgba (shadow->color);
gtk_css_color_to_color (gtk_css_color_value_get_color (shadow->color), &color);
/* We don't need to draw invisible shadows */
if (gdk_rgba_is_clear (color))
continue;
if (gdk_color_is_clear (&color))
{
gdk_color_finish (&color);
continue;
}
dx = gtk_css_number_value_get (shadow->hoffset, 0);
dy = gtk_css_number_value_get (shadow->voffset, 0);
@@ -663,55 +673,58 @@ gtk_css_shadow_value_snapshot_inset (const GtkCssValue *value,
{
const float y = dy > 0 ? dy : 0;
gtk_snapshot_append_color (snapshot, color,
&GRAPHENE_RECT_INIT (
padding_bounds->origin.x,
padding_bounds->origin.y + y,
dx,
padding_bounds->size.height - ABS (dy)
));
gtk_snapshot_append_color2 (snapshot, &color,
&GRAPHENE_RECT_INIT (
padding_bounds->origin.x,
padding_bounds->origin.y + y,
dx,
padding_bounds->size.height - ABS (dy)
));
}
else if (dx < 0)
{
const float y = dy > 0 ? dy : 0;
gtk_snapshot_append_color (snapshot, color,
&GRAPHENE_RECT_INIT (
padding_bounds->origin.x + padding_bounds->size.width + dx,
padding_bounds->origin.y + y,
- dx,
padding_bounds->size.height - ABS (dy)
));
gtk_snapshot_append_color2 (snapshot, &color,
&GRAPHENE_RECT_INIT (
padding_bounds->origin.x + padding_bounds->size.width + dx,
padding_bounds->origin.y + y,
- dx,
padding_bounds->size.height - ABS (dy)
));
}
if (dy > 0)
{
gtk_snapshot_append_color (snapshot, color,
&GRAPHENE_RECT_INIT (
padding_bounds->origin.x,
padding_bounds->origin.y,
padding_bounds->size.width,
dy
));
gtk_snapshot_append_color2 (snapshot, &color,
&GRAPHENE_RECT_INIT (
padding_bounds->origin.x,
padding_bounds->origin.y,
padding_bounds->size.width,
dy
));
}
else if (dy < 0)
{
gtk_snapshot_append_color (snapshot, color,
&GRAPHENE_RECT_INIT (
padding_bounds->origin.x,
padding_bounds->origin.y + padding_bounds->size.height + dy,
padding_bounds->size.width,
- dy
));
gtk_snapshot_append_color2 (snapshot, &color,
&GRAPHENE_RECT_INIT (
padding_bounds->origin.x,
padding_bounds->origin.y + padding_bounds->size.height + dy,
padding_bounds->size.width,
- dy
));
}
}
else
{
gtk_snapshot_append_inset_shadow (snapshot,
padding_box,
color,
dx, dy, spread, radius);
gtk_snapshot_append_inset_shadow2 (snapshot,
padding_box,
&color,
&GRAPHENE_POINT_INIT (dx, dy),
spread, radius);
}
gdk_color_finish (&color);
}
}
@@ -744,28 +757,31 @@ gboolean
gtk_css_shadow_value_push_snapshot (const GtkCssValue *value,
GtkSnapshot *snapshot)
{
GskShadow *shadows;
GskShadow2 *shadows;
guint i;
if (gtk_css_shadow_value_is_clear (value))
return FALSE;
shadows = g_newa (GskShadow, value->n_shadows);
shadows = g_newa (GskShadow2, value->n_shadows);
for (i = 0; i < value->n_shadows; i++)
{
const ShadowValue *shadow = &value->shadows[i];
shadows[i].color = *gtk_css_color_value_get_rgba (shadow->color);
shadows[i].dx = gtk_css_number_value_get (shadow->hoffset, 0);
shadows[i].dy = gtk_css_number_value_get (shadow->voffset, 0);
gtk_css_color_to_color (gtk_css_color_value_get_color (shadow->color), &shadows[i].color);
graphene_point_init (&shadows[i].offset,
gtk_css_number_value_get (shadow->hoffset, 0),
gtk_css_number_value_get (shadow->voffset, 0));
shadows[i].radius = gtk_css_number_value_get (shadow->radius, 0);
if (value->is_filter)
shadows[i].radius *= 2;
}
gtk_snapshot_push_shadow (snapshot, shadows, value->n_shadows);
gtk_snapshot_push_shadow2 (snapshot, shadows, value->n_shadows);
for (i = 0; i < value->n_shadows; i++)
gdk_color_finish (&shadows[i].color);
return TRUE;
}
-182
View File
@@ -304,185 +304,3 @@ gtk_native_queue_relayout (GtkNative *self)
gdk_surface_request_layout (surface);
}
static void
corner_rect (const GtkCssValue *value,
cairo_rectangle_int_t *rect)
{
rect->width = _gtk_css_corner_value_get_x (value, 100);
rect->height = _gtk_css_corner_value_get_y (value, 100);
}
static void
subtract_decoration_corners_from_region (cairo_region_t *region,
cairo_rectangle_int_t *extents,
const GtkCssStyle *style)
{
cairo_rectangle_int_t rect;
corner_rect (style->border->border_top_left_radius, &rect);
rect.x = extents->x;
rect.y = extents->y;
cairo_region_subtract_rectangle (region, &rect);
corner_rect (style->border->border_top_right_radius, &rect);
rect.x = extents->x + extents->width - rect.width;
rect.y = extents->y;
cairo_region_subtract_rectangle (region, &rect);
corner_rect (style->border->border_bottom_left_radius, &rect);
rect.x = extents->x;
rect.y = extents->y + extents->height - rect.height;
cairo_region_subtract_rectangle (region, &rect);
corner_rect (style->border->border_bottom_right_radius, &rect);
rect.x = extents->x + extents->width - rect.width;
rect.y = extents->y + extents->height - rect.height;
cairo_region_subtract_rectangle (region, &rect);
}
static int
get_translucent_border_edge (GtkCssValue *border_color,
GtkCssValue *border_width)
{
if (!gdk_rgba_is_opaque (gtk_css_color_value_get_rgba (border_color)))
return round (gtk_css_number_value_get (border_width, 100));
return 0;
}
static void
get_translucent_border_width (GtkWidget *widget,
GtkBorder *border)
{
GtkCssNode *css_node = gtk_widget_get_css_node (widget);
GtkCssStyle *style = gtk_css_node_get_style (css_node);
border->top = get_translucent_border_edge (style->used->border_top_color,
style->border->border_top_width);
border->bottom = get_translucent_border_edge (style->used->border_bottom_color,
style->border->border_bottom_width);
border->left = get_translucent_border_edge (style->used->border_left_color,
style->border->border_left_width);
border->right = get_translucent_border_edge (style->used->border_right_color,
style->border->border_right_width);
}
static gboolean
get_opaque_rect (GtkWidget *widget,
cairo_rectangle_int_t *rect)
{
gboolean is_opaque;
if (gtk_widget_get_opacity (widget) < 1)
is_opaque = FALSE;
else
{
GtkCssNode *node;
GtkCssStyle *style;
const GdkRGBA *color;
node = gtk_widget_get_css_node (widget);
style = gtk_css_node_get_style (node);
color = gtk_css_color_value_get_rgba (style->used->background_color);
is_opaque = gdk_rgba_is_opaque (color);
}
if (is_opaque)
{
const graphene_rect_t *border_rect;
GtkCssBoxes css_boxes;
GtkBorder border;
gtk_css_boxes_init (&css_boxes, widget);
border_rect = gtk_css_boxes_get_border_rect (&css_boxes);
get_translucent_border_width (widget, &border);
rect->x = border_rect->origin.x + border.left;
rect->y = border_rect->origin.y + border.top;
rect->width = border_rect->size.width - border.left - border.right;
rect->height = border_rect->size.height - border.top - border.bottom;
}
return is_opaque;
}
static void
get_shadow_width (GtkWidget *widget,
GtkBorder *shadow_width,
int resize_handle_size)
{
GtkCssNode *css_node = gtk_widget_get_css_node (widget);
const GtkCssStyle *style = gtk_css_node_get_style (css_node);
gtk_css_shadow_value_get_extents (style->used->box_shadow, shadow_width);
shadow_width->left = MAX (shadow_width->left, resize_handle_size);
shadow_width->top = MAX (shadow_width->top, resize_handle_size);
shadow_width->bottom = MAX (shadow_width->bottom, resize_handle_size);
shadow_width->right = MAX (shadow_width->right, resize_handle_size);
}
void
gtk_native_update_opaque_region (GtkNative *native,
GtkWidget *contents,
gboolean subtract_decoration_corners,
gboolean subtract_shadow,
int resize_handle_size)
{
cairo_rectangle_int_t rect;
cairo_region_t *opaque_region = NULL;
GdkSurface *surface;
GtkBorder shadow;
g_return_if_fail (GTK_IS_NATIVE (native));
g_return_if_fail (!contents || GTK_IS_WIDGET (contents));
if (contents == NULL)
contents = GTK_WIDGET (native);
if (!_gtk_widget_get_realized (GTK_WIDGET (native)) ||
!_gtk_widget_get_realized (contents))
return;
if (subtract_shadow)
get_shadow_width (contents, &shadow, resize_handle_size);
else
shadow = (GtkBorder) {0, 0, 0, 0};
surface = gtk_native_get_surface (native);
if (get_opaque_rect (contents, &rect))
{
double native_x, native_y;
gtk_native_get_surface_transform (native, &native_x, &native_y);
rect.x += native_x;
rect.y += native_y;
if (contents != GTK_WIDGET (native))
{
graphene_point_t p;
if (!gtk_widget_compute_point (contents, GTK_WIDGET (native),
&GRAPHENE_POINT_INIT (0, 0), &p))
graphene_point_init (&p, 0, 0);
rect.x += p.x;
rect.y += p.y;
}
opaque_region = cairo_region_create_rectangle (&rect);
if (subtract_decoration_corners)
{
GtkCssStyle *style;
style = gtk_css_node_get_style (gtk_widget_get_css_node (contents));
subtract_decoration_corners_from_region (opaque_region, &rect, style);
}
}
gdk_surface_set_opaque_region (surface, opaque_region);
cairo_region_destroy (opaque_region);
}
-5
View File
@@ -28,11 +28,6 @@ struct _GtkNativeInterface
};
void gtk_native_queue_relayout (GtkNative *native);
void gtk_native_update_opaque_region (GtkNative *native,
GtkWidget *contents,
gboolean subtract_decoration_corners,
gboolean subtract_shadow,
int resize_handle_size);
G_END_DECLS
-5
View File
@@ -1029,8 +1029,6 @@ gtk_popover_realize (GtkWidget *widget)
priv->renderer = gsk_renderer_new_for_surface (priv->surface);
gtk_native_realize (GTK_NATIVE (popover));
gtk_native_update_opaque_region (GTK_NATIVE (popover), priv->contents_widget, TRUE, TRUE, 0);
}
static void
@@ -1467,9 +1465,6 @@ gtk_popover_update_shape (GtkPopover *popover)
gdk_surface_set_input_region (priv->surface, region);
cairo_region_destroy (region);
}
if (_gtk_widget_get_realized (GTK_WIDGET (popover)))
gtk_native_update_opaque_region (GTK_NATIVE (popover), priv->contents_widget, TRUE, TRUE, 0);
}
static int
+94 -73
View File
@@ -37,6 +37,9 @@
#include "gtksnapshotprivate.h"
#include "gdk/gdkhslaprivate.h"
#include "gdk/gdkrgbaprivate.h"
#include "gdk/gdkcolorprivate.h"
#include "gdk/gdkcairoprivate.h"
#include "gsk/gskroundedrectprivate.h"
#include "gsk/gskrectprivate.h"
@@ -335,27 +338,30 @@ static void
snapshot_frame_fill (GtkSnapshot *snapshot,
const GskRoundedRect *outline,
const float border_width[4],
const GdkRGBA colors[4],
const GdkColor colors[4],
guint hidden_side)
{
if (hidden_side)
{
GdkRGBA real_colors[4];
GdkColor real_colors[4];
guint i;
for (i = 0; i < 4; i++)
{
if (hidden_side & (1 << i))
real_colors[i] = (GdkRGBA) { 0, 0, 0, 0 };
gdk_color_init_from_rgba (&real_colors[i], &GDK_RGBA_TRANSPARENT);
else
real_colors[i] = colors[i];
gdk_color_init_copy (&real_colors[i], &colors[i]);
}
snapshot_frame_fill (snapshot, outline, border_width, real_colors, 0);
for (i = 0; i < 4; i++)
gdk_color_finish (&real_colors[i]);
return;
}
gtk_snapshot_append_border (snapshot, outline, border_width, colors);
gtk_snapshot_append_border2 (snapshot, outline, border_width, colors);
}
static void
@@ -409,7 +415,7 @@ static void
render_frame_stroke (cairo_t *cr,
const GskRoundedRect *border_box,
const double border_width[4],
GdkRGBA colors[4],
const GdkColor colors[4],
guint hidden_side,
GtkBorderStyle stroke_style)
{
@@ -417,9 +423,9 @@ render_frame_stroke (cairo_t *cr,
GskRoundedRect stroke_box;
guint i;
different_colors = !gdk_rgba_equal (&colors[0], &colors[1]) ||
!gdk_rgba_equal (&colors[0], &colors[2]) ||
!gdk_rgba_equal (&colors[0], &colors[3]);
different_colors = !gdk_color_equal (&colors[0], &colors[1]) ||
!gdk_color_equal (&colors[0], &colors[2]) ||
!gdk_color_equal (&colors[0], &colors[3]);
different_borders = border_width[0] != border_width[1] ||
border_width[0] != border_width[2] ||
border_width[0] != border_width[3] ;
@@ -436,14 +442,15 @@ render_frame_stroke (cairo_t *cr,
double length = 0;
/* FAST PATH:
* Mostly expected to trigger for focus rectangles */
for (i = 0; i < 4; i++)
* Mostly expected to trigger for focus rectangles
*/
for (i = 0; i < 4; i++)
{
length += _gtk_rounded_box_guess_length (&stroke_box, i);
}
gsk_rounded_rect_path (&stroke_box, cr);
gdk_cairo_set_source_rgba (cr, &colors[0]);
gdk_cairo_set_source_color (cr, GDK_COLOR_STATE_SRGB, &colors[0]);
set_stroke_style (cr, border_width[0], stroke_style, length);
cairo_stroke (cr);
}
@@ -480,7 +487,7 @@ render_frame_stroke (cairo_t *cr,
_gtk_rounded_box_path_side (&stroke_box, cr, i);
gdk_cairo_set_source_rgba (cr, &colors[i]);
gdk_cairo_set_source_color (cr, GDK_COLOR_STATE_SRGB, &colors[i]);
set_stroke_style (cr,
border_width[i],
stroke_style,
@@ -496,36 +503,38 @@ static void
snapshot_frame_stroke (GtkSnapshot *snapshot,
const GskRoundedRect *outline,
const float border_width[4],
GdkRGBA colors[4],
const GdkColor colors[4],
guint hidden_side,
GtkBorderStyle stroke_style)
{
double double_width[4] = { border_width[0], border_width[1], border_width[2], border_width[3] };
cairo_t *cr;
cr = gtk_snapshot_append_cairo (snapshot,
&outline->bounds);
cr = gtk_snapshot_append_cairo (snapshot, &outline->bounds);
render_frame_stroke (cr, outline, double_width, colors, hidden_side, stroke_style);
cairo_destroy (cr);
}
static void
color_shade (const GdkRGBA *color,
double factor,
GdkRGBA *color_return)
color_shade (const GdkColor *color,
double factor,
GdkColor *color_return)
{
GdkRGBA rgba;
GdkHSLA hsla;
_gdk_hsla_init_from_rgba (&hsla, color);
gdk_color_to_float (color, GDK_COLOR_STATE_SRGB, (float *) &rgba);
_gdk_hsla_init_from_rgba (&hsla, &rgba);
_gdk_hsla_shade (&hsla, &hsla, factor);
_gdk_rgba_init_from_hsla (color_return, &hsla);
_gdk_rgba_init_from_hsla (&rgba, &hsla);
gdk_color_from_rgba (color_return, color->color_state, &rgba);
}
static void
snapshot_border (GtkSnapshot *snapshot,
const GskRoundedRect *border_box,
const float border_width[4],
GdkRGBA colors[4],
GdkColor colors[4],
GtkBorderStyle border_style[4])
{
guint hidden_side = 0;
@@ -585,12 +594,12 @@ snapshot_border (GtkSnapshot *snapshot,
hidden_side |= (1 << j);
else
dont_draw |= (1 << j);
other_border[j] = border_width[j] / 3;
}
snapshot_frame_fill (snapshot, border_box, other_border, colors, dont_draw);
other_box = *border_box;
gsk_rounded_rect_shrink (&other_box,
2 * other_border[GTK_CSS_TOP],
@@ -604,7 +613,7 @@ snapshot_border (GtkSnapshot *snapshot,
case GTK_BORDER_STYLE_RIDGE:
{
GskRoundedRect other_box;
GdkRGBA other_colors[4];
GdkColor other_colors[4];
guint dont_draw = hidden_side;
float other_border[4];
@@ -622,9 +631,9 @@ snapshot_border (GtkSnapshot *snapshot,
dont_draw |= (1 << j);
other_border[j] = border_width[j] / 2;
}
snapshot_frame_fill (snapshot, border_box, other_border, colors, dont_draw);
other_box = *border_box;
gsk_rounded_rect_shrink (&other_box,
other_border[GTK_CSS_TOP],
@@ -639,7 +648,7 @@ snapshot_border (GtkSnapshot *snapshot,
break;
}
}
snapshot_frame_fill (snapshot, border_box, border_width, colors, hidden_side);
}
@@ -675,7 +684,7 @@ gtk_css_style_snapshot_border (GtkCssBoxes *boxes,
else
{
GtkBorderStyle border_style[4];
GdkRGBA colors[4];
GdkColor colors[4];
graphene_simd4f_t alpha_test_vector;
/* Optimize the most common case of "This widget has no border" */
@@ -683,46 +692,54 @@ gtk_css_style_snapshot_border (GtkCssBoxes *boxes,
gtk_css_boxes_get_padding_rect (boxes)))
return;
colors[0] = *gtk_css_color_value_get_rgba (style->used->border_top_color);
colors[1] = *gtk_css_color_value_get_rgba (style->used->border_right_color);
colors[2] = *gtk_css_color_value_get_rgba (style->used->border_bottom_color);
colors[3] = *gtk_css_color_value_get_rgba (style->used->border_left_color);
gtk_css_color_to_color (gtk_css_color_value_get_color (style->used->border_top_color), &colors[0]);
gtk_css_color_to_color (gtk_css_color_value_get_color (style->used->border_right_color), &colors[1]);
gtk_css_color_to_color (gtk_css_color_value_get_color (style->used->border_bottom_color), &colors[2]);
gtk_css_color_to_color (gtk_css_color_value_get_color (style->used->border_left_color), &colors[3]);
alpha_test_vector = graphene_simd4f_init (colors[0].alpha, colors[1].alpha, colors[2].alpha, colors[3].alpha);
if (graphene_simd4f_is_zero4 (alpha_test_vector))
return;
border_style[0] = _gtk_css_border_style_value_get (style->border->border_top_style);
border_style[1] = _gtk_css_border_style_value_get (style->border->border_right_style);
border_style[2] = _gtk_css_border_style_value_get (style->border->border_bottom_style);
border_style[3] = _gtk_css_border_style_value_get (style->border->border_left_style);
border_width[0] = gtk_css_number_value_get (style->border->border_top_width, 100);
border_width[1] = gtk_css_number_value_get (style->border->border_right_width, 100);
border_width[2] = gtk_css_number_value_get (style->border->border_bottom_width, 100);
border_width[3] = gtk_css_number_value_get (style->border->border_left_width, 100);
gtk_snapshot_push_debug (snapshot, "CSS border");
if (border_style[0] <= GTK_BORDER_STYLE_SOLID &&
border_style[1] <= GTK_BORDER_STYLE_SOLID &&
border_style[2] <= GTK_BORDER_STYLE_SOLID &&
border_style[3] <= GTK_BORDER_STYLE_SOLID)
alpha_test_vector = graphene_simd4f_init (colors[0].alpha,
colors[1].alpha,
colors[2].alpha,
colors[3].alpha);
if (!graphene_simd4f_is_zero4 (alpha_test_vector))
{
/* The most common case of a solid border */
gtk_snapshot_append_border (snapshot,
gtk_css_boxes_get_border_box (boxes),
border_width,
colors);
border_style[0] = _gtk_css_border_style_value_get (style->border->border_top_style);
border_style[1] = _gtk_css_border_style_value_get (style->border->border_right_style);
border_style[2] = _gtk_css_border_style_value_get (style->border->border_bottom_style);
border_style[3] = _gtk_css_border_style_value_get (style->border->border_left_style);
border_width[0] = gtk_css_number_value_get (style->border->border_top_width, 100);
border_width[1] = gtk_css_number_value_get (style->border->border_right_width, 100);
border_width[2] = gtk_css_number_value_get (style->border->border_bottom_width, 100);
border_width[3] = gtk_css_number_value_get (style->border->border_left_width, 100);
gtk_snapshot_push_debug (snapshot, "CSS border");
if (border_style[0] <= GTK_BORDER_STYLE_SOLID &&
border_style[1] <= GTK_BORDER_STYLE_SOLID &&
border_style[2] <= GTK_BORDER_STYLE_SOLID &&
border_style[3] <= GTK_BORDER_STYLE_SOLID)
{
/* The most common case of a solid border */
gtk_snapshot_append_border2 (snapshot,
gtk_css_boxes_get_border_box (boxes),
border_width,
colors);
}
else
{
snapshot_border (snapshot,
gtk_css_boxes_get_border_box (boxes),
border_width,
colors,
border_style);
}
gtk_snapshot_pop (snapshot);
}
else
{
snapshot_border (snapshot,
gtk_css_boxes_get_border_box (boxes),
border_width,
colors,
border_style);
}
gtk_snapshot_pop (snapshot);
gdk_color_finish (&colors[0]);
gdk_color_finish (&colors[1]);
gdk_color_finish (&colors[2]);
gdk_color_finish (&colors[3]);
}
}
@@ -733,17 +750,20 @@ gtk_css_style_snapshot_outline (GtkCssBoxes *boxes,
GtkCssStyle *style = boxes->style;
GtkBorderStyle border_style[4];
float border_width[4];
GdkRGBA colors[4];
GdkColor colors[4];
border_style[0] = _gtk_css_border_style_value_get (style->outline->outline_style);
if (border_style[0] != GTK_BORDER_STYLE_NONE)
{
const GdkRGBA *color;
GdkColor color;
color = gtk_css_color_value_get_rgba (style->used->outline_color);
gtk_css_color_to_color (gtk_css_color_value_get_color (style->used->outline_color), &color);
if (gdk_rgba_is_clear (color))
return;
if (gdk_color_is_clear (&color))
{
gdk_color_finish (&color);
return;
}
border_width[0] = gtk_css_number_value_get (style->outline->outline_width, 100);
@@ -752,7 +772,7 @@ gtk_css_style_snapshot_outline (GtkCssBoxes *boxes,
border_style[1] = border_style[2] = border_style[3] = border_style[0];
border_width[3] = border_width[2] = border_width[1] = border_width[0];
colors[0] = colors[1] = colors[2] = colors[3] = *color;
colors[0] = colors[1] = colors[2] = colors[3] = color;
gtk_snapshot_push_debug (snapshot, "CSS outline");
snapshot_border (snapshot,
@@ -761,5 +781,6 @@ gtk_css_style_snapshot_outline (GtkCssBoxes *boxes,
colors,
border_style);
gtk_snapshot_pop (snapshot);
gdk_color_finish (&color);
}
}
+172 -37
View File
@@ -119,8 +119,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
} stroke;
struct {
gsize n_shadows;
GskShadow *shadows;
GskShadow a_shadow; /* Used if n_shadows == 1 */
GskShadow2 *shadows;
GskShadow2 a_shadow; /* Used if n_shadows == 1 */
} shadow;
struct {
GskBlendMode blend_mode;
@@ -1348,11 +1348,11 @@ gtk_snapshot_collect_shadow (GtkSnapshot *snapshot,
if (node == NULL)
return NULL;
shadow_node = gsk_shadow_node_new (node,
state->data.shadow.shadows != NULL ?
state->data.shadow.shadows :
&state->data.shadow.a_shadow,
state->data.shadow.n_shadows);
shadow_node = gsk_shadow_node_new2 (node,
state->data.shadow.shadows != NULL
? state->data.shadow.shadows
: &state->data.shadow.a_shadow,
state->data.shadow.n_shadows);
gsk_render_node_unref (node);
@@ -1391,6 +1391,12 @@ gtk_snapshot_append_stroke (GtkSnapshot *snapshot,
static void
gtk_snapshot_clear_shadow (GtkSnapshotState *state)
{
if (state->data.shadow.shadows != 0)
for (gsize i = 0; i < state->data.shadow.n_shadows; i++)
gdk_color_finish (&state->data.shadow.shadows[i].color);
else
gdk_color_finish (&state->data.shadow.a_shadow.color);
g_free (state->data.shadow.shadows);
}
@@ -1408,6 +1414,41 @@ void
gtk_snapshot_push_shadow (GtkSnapshot *snapshot,
const GskShadow *shadow,
gsize n_shadows)
{
GskShadow2 *shadow2;
g_return_if_fail (n_shadows > 0);
shadow2 = g_new (GskShadow2, n_shadows);
for (gsize i = 0; i < n_shadows; i++)
{
gdk_color_init_from_rgba (&shadow2[i].color, &shadow[i].color);
graphene_point_init (&shadow2[i].offset, shadow[i].dx,shadow[i].dy);
shadow2[i].radius = shadow[i].radius;
}
gtk_snapshot_push_shadow2 (snapshot, shadow2, n_shadows);
for (gsize i = 0; i < n_shadows; i++)
gdk_color_finish (&shadow2[i].color);
g_free (shadow2);
}
/*< private >
* gtk_snapshot_push_shadow2:
* @snapshot: a `GtkSnapshot`
* @shadow: (array length=n_shadows): the first shadow specification
* @n_shadows: number of shadow specifications
*
* Applies a shadow to an image.
*
* The image is recorded until the next call to [method@Gtk.Snapshot.pop].
*/
void
gtk_snapshot_push_shadow2 (GtkSnapshot *snapshot,
const GskShadow2 *shadow,
gsize n_shadows)
{
GtkSnapshotState *state;
GskTransform *transform;
@@ -1429,20 +1470,23 @@ gtk_snapshot_push_shadow (GtkSnapshot *snapshot,
if (n_shadows == 1)
{
state->data.shadow.shadows = NULL;
memcpy (&state->data.shadow.a_shadow, shadow, sizeof (GskShadow));
state->data.shadow.a_shadow.dx *= scale_x;
state->data.shadow.a_shadow.dy *= scale_y;
state->data.shadow.a_shadow.radius *= scale_x;
gdk_color_init_copy (&state->data.shadow.a_shadow.color, &shadow->color);
graphene_point_init (&state->data.shadow.a_shadow.offset,
shadow->offset.x * scale_x,
shadow->offset.y * scale_y);
state->data.shadow.a_shadow.radius = shadow->radius * scale_x;
}
else
{
state->data.shadow.shadows = g_malloc (sizeof (GskShadow) * n_shadows);
memcpy (state->data.shadow.shadows, shadow, sizeof (GskShadow) * n_shadows);
state->data.shadow.shadows = g_malloc (sizeof (GskShadow2) * n_shadows);
memcpy (state->data.shadow.shadows, shadow, sizeof (GskShadow2) * n_shadows);
for (i = 0; i < n_shadows; i++)
{
state->data.shadow.shadows[i].dx *= scale_x;
state->data.shadow.shadows[i].dy *= scale_y;
state->data.shadow.shadows[i].radius *= scale_x;
gdk_color_init_copy (&state->data.shadow.shadows[i].color, &shadow[i].color);
graphene_point_init (&state->data.shadow.shadows[i].offset,
shadow[i].offset.x * scale_x,
shadow[i].offset.y * scale_y);
state->data.shadow.shadows[i].radius = shadow[i].radius * scale_x;
}
}
@@ -2805,6 +2849,36 @@ gtk_snapshot_append_border (GtkSnapshot *snapshot,
const GskRoundedRect *outline,
const float border_width[4],
const GdkRGBA border_color[4])
{
GdkColor color[4];
for (int i = 0; i < 4; i++)
gdk_color_init_from_rgba (&color[i], &border_color[i]);
gtk_snapshot_append_border2 (snapshot, outline, border_width, color);
for (int i = 0; i < 4; i++)
gdk_color_finish (&color[i]);
}
/*< private >
* gtk_snapshot_append_border2:
* @snapshot: a `GtkSnapshot`
* @outline: the outline of the border
* @border_width: (array fixed-size=4): the stroke width of the border on
* the top, right, bottom and left side respectively.
* @border_color: (array fixed-size=4): the color used on the top, right,
* bottom and left side.
*
* Appends a stroked border rectangle inside the given @outline.
*
* The four sides of the border can have different widths and colors.
*/
void
gtk_snapshot_append_border2 (GtkSnapshot *snapshot,
const GskRoundedRect *outline,
const float border_width[4],
const GdkColor border_color[4])
{
GskRenderNode *node;
GskRoundedRect real_outline;
@@ -2818,14 +2892,14 @@ gtk_snapshot_append_border (GtkSnapshot *snapshot,
gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &dx, &dy);
gsk_rounded_rect_scale_affine (&real_outline, outline, scale_x, scale_y, dx, dy);
node = gsk_border_node_new (&real_outline,
(float[4]) {
border_width[0] * scale_y,
border_width[1] * scale_x,
border_width[2] * scale_y,
border_width[3] * scale_x,
},
border_color);
node = gsk_border_node_new2 (&real_outline,
(float[4]) {
border_width[0] * scale_y,
border_width[1] * scale_x,
border_width[2] * scale_y,
border_width[3] * scale_x,
},
border_color);
gtk_snapshot_append_node_internal (snapshot, node);
}
@@ -2850,6 +2924,36 @@ gtk_snapshot_append_inset_shadow (GtkSnapshot *snapshot,
float dy,
float spread,
float blur_radius)
{
GdkColor color2;
gdk_color_init_from_rgba (&color2, color);
gtk_snapshot_append_inset_shadow2 (snapshot,
outline,
&color2,
&GRAPHENE_POINT_INIT (dx, dy),
spread, blur_radius);
gdk_color_finish (&color2);
}
/*< private >
* gtk_snapshot_append_inset_shadow2:
* @snapshot: a `GtkSnapshot`
* @outline: outline of the region surrounded by shadow
* @color: color of the shadow
* @offset: offset of shadow
* @spread: how far the shadow spreads towards the inside
* @blur_radius: how much blur to apply to the shadow
*
* Appends an inset shadow into the box given by @outline.
*/
void
gtk_snapshot_append_inset_shadow2 (GtkSnapshot *snapshot,
const GskRoundedRect *outline,
const GdkColor *color,
const graphene_point_t *offset,
float spread,
float blur_radius)
{
GskRenderNode *node;
GskRoundedRect real_outline;
@@ -2858,16 +2962,17 @@ gtk_snapshot_append_inset_shadow (GtkSnapshot *snapshot,
g_return_if_fail (snapshot != NULL);
g_return_if_fail (outline != NULL);
g_return_if_fail (color != NULL);
g_return_if_fail (offset != NULL);
gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &x, &y);
gsk_rounded_rect_scale_affine (&real_outline, outline, scale_x, scale_y, x, y);
node = gsk_inset_shadow_node_new (&real_outline,
color,
scale_x * dx,
scale_y * dy,
spread,
blur_radius);
node = gsk_inset_shadow_node_new2 (&real_outline,
color,
&GRAPHENE_POINT_INIT (scale_x * offset->x,
scale_y * offset->y),
spread,
blur_radius);
gtk_snapshot_append_node_internal (snapshot, node);
}
@@ -2892,6 +2997,36 @@ gtk_snapshot_append_outset_shadow (GtkSnapshot *snapshot,
float dy,
float spread,
float blur_radius)
{
GdkColor color2;
gdk_color_init_from_rgba (&color2, color);
gtk_snapshot_append_outset_shadow2 (snapshot,
outline,
&color2,
&GRAPHENE_POINT_INIT (dx, dy),
spread, blur_radius);
gdk_color_finish (&color2);
}
/*< private >
* gtk_snapshot_append_outset_shadow2:
* @snapshot: a `GtkSnapshot`
* @outline: outline of the region surrounded by shadow
* @color: color of the shadow
* @offset: offset of shadow
* @spread: how far the shadow spreads towards the outside
* @blur_radius: how much blur to apply to the shadow
*
* Appends an outset shadow node around the box given by @outline.
*/
void
gtk_snapshot_append_outset_shadow2 (GtkSnapshot *snapshot,
const GskRoundedRect *outline,
const GdkColor *color,
const graphene_point_t *offset,
float spread,
float blur_radius)
{
GskRenderNode *node;
GskRoundedRect real_outline;
@@ -2900,17 +3035,17 @@ gtk_snapshot_append_outset_shadow (GtkSnapshot *snapshot,
g_return_if_fail (snapshot != NULL);
g_return_if_fail (outline != NULL);
g_return_if_fail (color != NULL);
g_return_if_fail (offset != NULL);
gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &x, &y);
gsk_rounded_rect_scale_affine (&real_outline, outline, scale_x, scale_y, x, y);
node = gsk_outset_shadow_node_new (&real_outline,
color,
scale_x * dx,
scale_y * dy,
spread,
blur_radius);
node = gsk_outset_shadow_node_new2 (&real_outline,
color,
&GRAPHENE_POINT_INIT (scale_x * offset->x,
scale_y * offset->y),
spread,
blur_radius);
gtk_snapshot_append_node_internal (snapshot, node);
}
+22
View File
@@ -40,6 +40,28 @@ void gtk_snapshot_push_subsurface (GtkSnapshot
void gtk_snapshot_append_color2 (GtkSnapshot *snapshot,
const GdkColor *color,
const graphene_rect_t *bounds);
void gtk_snapshot_append_border2 (GtkSnapshot *snapshot,
const GskRoundedRect *outline,
const float border_width[4],
const GdkColor border_color[4]);
void gtk_snapshot_append_inset_shadow2 (GtkSnapshot *snapshot,
const GskRoundedRect *outline,
const GdkColor *color,
const graphene_point_t *offset,
float spread,
float blur_radius);
void gtk_snapshot_append_outset_shadow2 (GtkSnapshot *snapshot,
const GskRoundedRect *outline,
const GdkColor *color,
const graphene_point_t *offset,
float spread,
float blur_radius);
void gtk_snapshot_push_shadow2 (GtkSnapshot *snapshot,
const GskShadow2 *shadow,
gsize n_shadows);
G_END_DECLS
+2
View File
@@ -28,6 +28,8 @@
G_BEGIN_DECLS
#define GTK_STYLE_PROVIDER_PRIORITY_INSPECTOR 1000
#define GTK_STYLE_PROVIDER_GET_INTERFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GTK_TYPE_STYLE_PROVIDER, GtkStyleProviderInterface))
typedef struct _GtkStyleProviderInterface GtkStyleProviderInterface;
-42
View File
@@ -470,8 +470,6 @@ static void gtk_window_activate_close (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_window_css_changed (GtkWidget *widget,
GtkCssStyleChange *change);
static void _gtk_window_set_is_active (GtkWindow *window,
gboolean is_active);
static void gtk_window_present_toplevel (GtkWindow *window);
@@ -782,7 +780,6 @@ gtk_window_class_init (GtkWindowClass *klass)
widget_class->focus = gtk_window_focus;
widget_class->move_focus = gtk_window_move_focus;
widget_class->measure = gtk_window_measure;
widget_class->css_changed = gtk_window_css_changed;
klass->activate_default = gtk_window_real_activate_default;
klass->activate_focus = gtk_window_real_activate_focus;
@@ -4059,30 +4056,6 @@ out:
*shadow_width = (GtkBorder) {0, 0, 0, 0};
}
static void
update_opaque_region (GtkWindow *window)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
gboolean subtract_decoration_corners;
gboolean subtract_shadow;
subtract_decoration_corners = (priv->client_decorated &&
priv->decorated &&
!priv->fullscreen &&
!priv->maximized);
subtract_shadow = (priv->client_decorated &&
priv->decorated &&
priv->use_client_shadow &&
!priv->maximized &&
!priv->fullscreen);
gtk_native_update_opaque_region (GTK_NATIVE (window),
NULL,
subtract_decoration_corners,
subtract_shadow,
RESIZE_HANDLE_SIZE);
}
static void
update_realized_window_properties (GtkWindow *window)
{
@@ -4092,8 +4065,6 @@ update_realized_window_properties (GtkWindow *window)
const graphene_rect_t *border_rect;
double native_x, native_y;
update_opaque_region (window);
if (!priv->client_decorated || !priv->use_client_shadow)
return;
@@ -5200,19 +5171,6 @@ gtk_window_set_focus (GtkWindow *window,
gtk_window_root_set_focus (GTK_ROOT (window), NULL);
}
static void
gtk_window_css_changed (GtkWidget *widget,
GtkCssStyleChange *change)
{
GtkWindow *window = GTK_WINDOW (widget);
GTK_WIDGET_CLASS (gtk_window_parent_class)->css_changed (widget, change);
if (!_gtk_widget_get_alloc_needed (widget) &&
(change == NULL || gtk_css_style_change_changes_property (change, GTK_CSS_PROPERTY_BACKGROUND_COLOR)))
update_opaque_region (window);
}
/*
* _gtk_window_unset_focus_and_default:
* @window: a `GtkWindow`
+6 -6
View File
@@ -26,15 +26,15 @@
#include "window.h"
#include "css-editor.h"
#include "gtkcssprovider.h"
#include "gtkstyleprovider.h"
#include "gtktextview.h"
#include "gtkalertdialog.h"
#include "gtkcssprovider.h"
#include "gtkfiledialog.h"
#include "gtktogglebutton.h"
#include "gtklabel.h"
#include "gtktooltip.h"
#include "gtkstyleproviderprivate.h"
#include "gtktextiter.h"
#include "gtktextview.h"
#include "gtktogglebutton.h"
#include "gtktooltip.h"
#include "gtk/css/gtkcss.h"
@@ -174,7 +174,7 @@ disable_toggled (GtkToggleButton *button,
else
gtk_style_context_add_provider_for_display (ce->priv->display,
GTK_STYLE_PROVIDER (ce->priv->provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
GTK_STYLE_PROVIDER_PRIORITY_INSPECTOR);
}
static void
+29 -15
View File
@@ -1033,7 +1033,7 @@ static void
populate_render_node_properties (GListStore *store,
GskRenderNode *node)
{
graphene_rect_t bounds;
graphene_rect_t bounds, opaque;
g_list_store_remove_all (store);
@@ -1042,11 +1042,25 @@ populate_render_node_properties (GListStore *store,
add_text_row (store, "Type", "%s", node_type_name (gsk_render_node_get_node_type (node)));
add_text_row (store, "Bounds",
"%.2f x %.2f + %.2f + %.2f",
bounds.size.width,
bounds.size.height,
"(%.2f, %.2f) to (%.2f, %.2f) - %.2f x %.2f",
bounds.origin.x,
bounds.origin.y);
bounds.origin.y,
bounds.origin.x + bounds.size.width,
bounds.origin.y + bounds.size.height,
bounds.size.width,
bounds.size.height);
if (gsk_render_node_get_opaque_rect (node, &opaque))
add_text_row (store, "Opaque",
"(%.2f, %.2f) to (%.2f, %.2f) - %.2f x %.2f",
opaque.origin.x,
opaque.origin.y,
opaque.origin.x + opaque.size.width,
opaque.origin.y + opaque.size.height,
opaque.size.width,
opaque.size.height);
else
add_text_row (store, "Opaque", "no");
switch (gsk_render_node_get_node_type (node))
{
@@ -1223,7 +1237,7 @@ populate_render_node_properties (GListStore *store,
{
const char *name[4] = { "Top", "Right", "Bottom", "Left" };
const float *widths = gsk_border_node_get_widths (node);
const GdkRGBA *colors = gsk_border_node_get_colors (node);
const GdkColor *colors = gsk_border_node_get_colors2 (node);
int i;
for (i = 0; i < 4; i++)
@@ -1231,9 +1245,9 @@ populate_render_node_properties (GListStore *store,
GdkTexture *texture;
char *text, *tmp;
text = gdk_rgba_to_string (&colors[i]);
text = gdk_color_to_string (&colors[i]);
tmp = g_strdup_printf ("%.2f, %s", widths[i], text);
texture = get_color_texture (&colors[i]);
texture = get_color2_texture (&colors[i]);
list_store_add_object_property (store, name[i], tmp, texture);
g_object_unref (texture);
@@ -1355,13 +1369,13 @@ G_GNUC_END_IGNORE_DEPRECATIONS
case GSK_INSET_SHADOW_NODE:
{
const GdkRGBA *color = gsk_inset_shadow_node_get_color (node);
const GdkColor *color = gsk_inset_shadow_node_get_color2 (node);
float dx = gsk_inset_shadow_node_get_dx (node);
float dy = gsk_inset_shadow_node_get_dy (node);
float spread = gsk_inset_shadow_node_get_spread (node);
float radius = gsk_inset_shadow_node_get_blur_radius (node);
add_color_row (store, "Color", color);
add_color2_row (store, "Color", color);
add_text_row (store, "Offset", "%.2f %.2f", dx, dy);
@@ -1373,7 +1387,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
case GSK_OUTSET_SHADOW_NODE:
{
const GskRoundedRect *outline = gsk_outset_shadow_node_get_outline (node);
const GdkRGBA *color = gsk_outset_shadow_node_get_color (node);
const GdkColor *color = gsk_outset_shadow_node_get_color2 (node);
float dx = gsk_outset_shadow_node_get_dx (node);
float dy = gsk_outset_shadow_node_get_dy (node);
float spread = gsk_outset_shadow_node_get_spread (node);
@@ -1385,7 +1399,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
"%.2f x %.2f + %.2f + %.2f",
rect[2], rect[3], rect[0], rect[1]);
add_color_row (store, "Color", color);
add_color2_row (store, "Color", color);
add_text_row (store, "Offset", "%.2f %.2f", dx, dy);
@@ -1518,14 +1532,14 @@ G_GNUC_END_IGNORE_DEPRECATIONS
for (i = 0; i < gsk_shadow_node_get_n_shadows (node); i++)
{
char *label;
const GskShadow *shadow = gsk_shadow_node_get_shadow (node, i);
const GskShadow2 *shadow = gsk_shadow_node_get_shadow2 (node, i);
label = g_strdup_printf ("Color %d", i);
add_color_row (store, label, &shadow->color);
add_color2_row (store, label, &shadow->color);
g_free (label);
label = g_strdup_printf ("Offset %d", i);
add_text_row (store, label, "%.2f %.2f", shadow->dx, shadow->dy);
add_text_row (store, label, "%.2f %.2f", shadow->offset.x, shadow->offset.y);
g_free (label);
label = g_strdup_printf ("Radius %d", i);
+25 -14
View File
@@ -26,6 +26,7 @@ cloudproviders_req = '>= 0.3.1'
xkbcommon_req = '>= 0.2.0'
sysprof_req = '>= 3.38.0'
vulkan_req = '>= 1.3'
gstreamer_req = '>= 1.24.0'
fs = import('fs')
gnome = import('gnome')
@@ -410,21 +411,30 @@ if win32_enabled
pangowin32_dep = dependency('pangowin32')
endif
pangocairo_dep = dependency('pangocairo', version: pango_req)
pixbuf_dep = dependency('gdk-pixbuf-2.0', version: gdk_pixbuf_req,
default_options: ['png=enabled', 'jpeg=enabled', 'builtin_loaders=png,jpeg', 'man=false'])
png_dep = dependency('libpng', 'png')
tiff_dep = dependency('libtiff-4', 'tiff')
jpeg_dep = dependency('libjpeg', 'jpeg')
pangocairo_dep = dependency('pangocairo', version: pango_req)
pixbuf_dep = dependency('gdk-pixbuf-2.0', version: gdk_pixbuf_req,
default_options: ['png=enabled', 'jpeg=enabled', 'builtin_loaders=png,jpeg', 'man=false'])
png_dep = dependency('libpng', 'png')
tiff_dep = dependency('libtiff-4', 'tiff')
jpeg_dep = dependency('libjpeg', 'jpeg')
avif_dep = dependency('libavif', required: get_option('avif'))
epoxy_dep = dependency('epoxy', version: epoxy_req)
xkbdep = dependency('xkbcommon', version: xkbcommon_req, required: wayland_enabled)
graphene_dep = dependency('graphene-gobject-1.0', version: graphene_req,
default_options: ['tests=false', 'gobject_types=true'])
iso_codes_dep = dependency('iso-codes', required: false)
gi_dep = dependency('gobject-introspection-1.0', version: introspection_req,
required: get_option('introspection').enabled() and
get_option('build-tests'))
cdata.set('HAVE_AVIF', avif_dep.found())
epoxy_dep = dependency('epoxy', version: epoxy_req)
xkbdep = dependency('xkbcommon', version: xkbcommon_req, required: wayland_enabled)
graphene_dep = dependency('graphene-gobject-1.0', version: graphene_req,
default_options: ['tests=false', 'gobject_types=true'])
iso_codes_dep = dependency('iso-codes', required: false)
gi_dep = dependency('gobject-introspection-1.0', version: introspection_req,
required: get_option('introspection').enabled() and
get_option('build-tests'))
gstplayer_dep = dependency('gstreamer-player-1.0', version: gstreamer_req,
required: get_option('media-gstreamer'))
gstgl_dep = dependency('gstreamer-gl-1.0', version: gstreamer_req,
required: get_option('media-gstreamer'))
gstallocators_dep = dependency('gstreamer-allocators-1.0', version: gstreamer_req,
required: get_option('media-gstreamer'))
fontconfig_dep = [] # only used in x11 backend
@@ -948,6 +958,7 @@ summary('Cloud support', cloudproviders_dep.found(), section: 'Features')
summary('Sysprof support', libsysprof_capture_dep.found(), section: 'Features')
summary('Colord support', colord_dep.found(), section: 'Features')
summary('Tracker support', tracker3_dep.found(), section: 'Features')
summary('AVIF support', avif_dep.found(), section: 'Features')
summary('Compiler', cc.get_id(), section: 'Toolchain')
summary('Linker', cc.get_linker_id(), section: 'Toolchain')
+5
View File
@@ -52,6 +52,11 @@ option('print-cups',
# Optional features
option('avif',
type: 'feature',
value: 'disabled',
description: 'Enable support for AVIF images, for GTK development')
option('vulkan',
type: 'feature',
value: 'enabled',
+124 -62
View File
@@ -24,6 +24,8 @@
#include "gtkgstpaintableprivate.h"
#include "gdk/gdkdmabuffourccprivate.h"
#if GST_GL_HAVE_WINDOW_X11 && (GST_GL_HAVE_PLATFORM_GLX || GST_GL_HAVE_PLATFORM_EGL) && defined (GDK_WINDOWING_X11)
#define HAVE_GST_X11_SUPPORT
#include <gdk/x11/gdkx.h>
@@ -52,10 +54,8 @@
#include <gst/gl/gstglfuncs.h>
#ifdef HAVE_GSTREAMER_DRM
#include <gdk/gdkdmabuffourccprivate.h>
#include <gst/allocators/gstdmabuf.h>
#endif
enum {
PROP_0,
@@ -72,17 +72,11 @@ GST_DEBUG_CATEGORY (gtk_debug_gst_sink);
#define NOGL_CAPS GST_VIDEO_CAPS_MAKE (FORMATS)
#ifdef HAVE_GSTREAMER_DRM
# define GST_VIDEO_DMA_DRM_CAPS_MAKE_STR GST_VIDEO_DMA_DRM_CAPS_MAKE "; "
#else
# define GST_VIDEO_DMA_DRM_CAPS_MAKE_STR
#endif
static GstStaticPadTemplate gtk_gst_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_DMA_DRM_CAPS_MAKE_STR
GST_STATIC_CAPS (GST_VIDEO_DMA_DRM_CAPS_MAKE "; "
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), "
"format = (string) RGBA, "
"width = " GST_VIDEO_SIZE_RANGE ", "
@@ -130,7 +124,6 @@ gtk_gst_sink_get_times (GstBaseSink *bsink,
}
}
#ifdef HAVE_GSTREAMER_DRM
static void
add_drm_formats_and_modifiers (GstCaps *caps,
GdkDmabufFormats *dmabuf_formats)
@@ -164,11 +157,73 @@ add_drm_formats_and_modifiers (GstCaps *caps,
gst_structure_take_value (gst_caps_get_structure (caps, 0), "drm-format",
&dmabuf_list);
}
#ifdef HAVE_GSTREAMER_DRM
static inline gboolean
dmabuf_fourcc_is_yuv (guint32 fourcc)
{
switch (fourcc)
{
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_VYUY:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_AYUV:
case DRM_FORMAT_AVUY8888:
case DRM_FORMAT_XYUV8888:
case DRM_FORMAT_XVUY8888:
case DRM_FORMAT_VUY888:
case DRM_FORMAT_VUY101010:
case DRM_FORMAT_Y210:
case DRM_FORMAT_Y212:
case DRM_FORMAT_Y216:
case DRM_FORMAT_Y410:
case DRM_FORMAT_Y412:
case DRM_FORMAT_Y416:
case DRM_FORMAT_XVYU2101010:
case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616:
case DRM_FORMAT_Y0L0:
case DRM_FORMAT_X0L0:
case DRM_FORMAT_Y0L2:
case DRM_FORMAT_X0L2:
case DRM_FORMAT_YUV420_8BIT:
case DRM_FORMAT_YUV420_10BIT:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
case DRM_FORMAT_NV24:
case DRM_FORMAT_NV42:
case DRM_FORMAT_NV15:
case DRM_FORMAT_P210:
case DRM_FORMAT_P010:
case DRM_FORMAT_P012:
case DRM_FORMAT_P016:
case DRM_FORMAT_P030:
case DRM_FORMAT_Q410:
case DRM_FORMAT_Q401:
case DRM_FORMAT_YUV410:
case DRM_FORMAT_YVU410:
case DRM_FORMAT_YUV411:
case DRM_FORMAT_YVU411:
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422:
case DRM_FORMAT_YUV444:
case DRM_FORMAT_YVU444:
return TRUE;
default:
return FALSE;
}
}
#endif
static GdkColorState *
gtk_gst_color_state_from_colorimetry (GtkGstSink *self,
const GstVideoColorimetry *colorimetry)
const GstVideoColorimetry *colorimetry,
gconstpointer drm)
{
GdkCicpParams *params;
GdkColorState *color_state;
@@ -186,18 +241,40 @@ gtk_gst_color_state_from_colorimetry (GtkGstSink *self,
else
gdk_cicp_params_set_transfer_function (params, gst_video_transfer_function_to_iso (colorimetry->transfer));
#if 0
gdk_cicp_params_set_range (params, colorimetry->range == GST_VIDEO_COLOR_RANGE_16_235 ? GDK_CICP_RANGE_NARROW : GDK_CICP_RANGE_FULL);
if (colorimetry->matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN)
gdk_cicp_params_set_matrix_coefficients (params, 6);
{
gdk_cicp_params_set_matrix_coefficients (params, 0);
#ifdef HAVE_GSTREAMER_DRM
const GstVideoInfoDmaDrm *drm_info = drm;
if (drm_info)
{
if (dmabuf_fourcc_is_yuv (drm_info->drm_fourcc))
{
GST_DEBUG_OBJECT (self, "Assuming fourcc %.*s is yuv", 4, (char *)&drm_info->drm_fourcc);
gdk_cicp_params_set_matrix_coefficients (params, 6);
gdk_cicp_params_set_range (params, GDK_CICP_RANGE_NARROW);
}
}
#endif
}
else
gdk_cicp_params_set_matrix_coefficients (params, gst_video_color_matrix_to_iso (colorimetry->matrix));
gdk_cicp_params_set_range (params, colorimetry->range == GST_VIDEO_COLOR_RANGE_0_255 ? GDK_CICP_RANGE_FULL : GDK_CICP_RANGE_NARROW);
#else
gdk_cicp_params_set_matrix_coefficients (params, 0);
gdk_cicp_params_set_range (params, GDK_CICP_RANGE_FULL);
#endif
color_state = gdk_cicp_params_build_color_state (params, &error);
GST_DEBUG_OBJECT (self, "cicp received: %u/%u/%u/%u",
gst_video_color_primaries_to_iso (colorimetry->primaries),
gst_video_transfer_function_to_iso (colorimetry->transfer),
gst_video_color_matrix_to_iso (colorimetry->matrix),
colorimetry->range == GST_VIDEO_COLOR_RANGE_0_255);
GST_DEBUG_OBJECT (self, "cicp used: %u/%u/%u/%u",
gdk_cicp_params_get_color_primaries (params),
gdk_cicp_params_get_transfer_function (params),
gdk_cicp_params_get_matrix_coefficients (params),
gdk_cicp_params_get_range (params));
g_object_unref (params);
if (color_state == NULL)
@@ -219,16 +296,12 @@ gtk_gst_sink_get_caps (GstBaseSink *bsink,
if (self->gst_context)
{
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
#ifdef HAVE_GSTREAMER_DRM
{
GdkDisplay *display = gdk_gl_context_get_display (self->gdk_context);
GdkDmabufFormats *formats = gdk_display_get_dmabuf_formats (display);
GdkDisplay *display = gdk_gl_context_get_display (self->gdk_context);
GdkDmabufFormats *formats = gdk_display_get_dmabuf_formats (display);
tmp = gst_caps_make_writable (tmp);
add_drm_formats_and_modifiers (tmp, formats);
}
#endif
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
tmp = gst_caps_make_writable (tmp);
add_drm_formats_and_modifiers (tmp, formats);
}
else
{
@@ -261,27 +334,33 @@ gtk_gst_sink_set_caps (GstBaseSink *bsink,
GST_DEBUG_OBJECT (self, "set caps with %" GST_PTR_FORMAT, caps);
#ifdef HAVE_GSTREAMER_DRM
if (gst_video_is_dma_drm_caps (caps)) {
if (!gst_video_info_dma_drm_from_caps (&self->drm_info, caps))
return FALSE;
if (gst_video_is_dma_drm_caps (caps))
{
if (!gst_video_info_dma_drm_from_caps (&self->drm_info, caps))
return FALSE;
if (!gst_video_info_dma_drm_to_video_info (&self->drm_info, &self->v_info))
return FALSE;
if (!gst_video_info_dma_drm_to_video_info (&self->drm_info, &self->v_info))
return FALSE;
GST_INFO_OBJECT (self, "using DMABuf, passthrough possible");
} else {
gst_video_info_dma_drm_init (&self->drm_info);
#endif
GST_INFO_OBJECT (self, "using DMABuf, passthrough possible");
}
else
{
gst_video_info_dma_drm_init (&self->drm_info);
if (!gst_video_info_from_caps (&self->v_info, caps))
return FALSE;
#ifdef HAVE_GSTREAMER_DRM
}
#endif
if (!gst_video_info_from_caps (&self->v_info, caps))
return FALSE;
}
g_clear_pointer (&self->color_state, gdk_color_state_unref);
self->color_state = gtk_gst_color_state_from_colorimetry (self, &self->v_info.colorimetry);
self->color_state = gtk_gst_color_state_from_colorimetry (self,
&self->v_info.colorimetry,
#ifdef HAVE_GSTREAMER_DRM
&self->drm_info
#else
NULL
#endif
);
if (self->color_state == NULL)
return FALSE;
@@ -325,13 +404,11 @@ gtk_gst_sink_propose_allocation (GstBaseSink *bsink,
return FALSE;
}
#ifdef HAVE_GSTREAMER_DRM
if (gst_caps_features_contains (gst_caps_get_features (caps, 0), GST_CAPS_FEATURE_MEMORY_DMABUF))
{
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
return TRUE;
}
#endif
if (!gst_caps_features_contains (gst_caps_get_features (caps, 0), GST_CAPS_FEATURE_MEMORY_GL_MEMORY))
return FALSE;
@@ -424,7 +501,6 @@ gtk_gst_sink_texture_from_buffer (GtkGstSink *self,
viewport->size.width = GST_VIDEO_INFO_WIDTH (&self->v_info);
viewport->size.height = GST_VIDEO_INFO_HEIGHT (&self->v_info);
#ifdef HAVE_GSTREAMER_DRM
if (gst_is_dmabuf_memory (gst_buffer_peek_memory (buffer, 0)))
{
GdkDmabufTextureBuilder *builder = NULL;
@@ -483,10 +559,8 @@ gtk_gst_sink_texture_from_buffer (GtkGstSink *self,
*pixel_aspect_ratio = ((double) GST_VIDEO_INFO_PAR_N (&self->v_info) /
(double) GST_VIDEO_INFO_PAR_D (&self->v_info));
}
else
#endif
if (self->gdk_context &&
gst_video_frame_map (frame, &self->v_info, buffer, GST_MAP_READ | GST_MAP_GL))
else if (self->gdk_context &&
gst_video_frame_map (frame, &self->v_info, buffer, GST_MAP_READ | GST_MAP_GL))
{
GstGLSyncMeta *sync_meta;
GdkGLTextureBuilder *builder;
@@ -705,20 +779,8 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
if (gl_api & (GST_GL_API_OPENGL3 | GST_GL_API_OPENGL))
{
#ifdef HAVE_GST_GL_DISPLAY_NEW_WITH_TYPE
self->gst_display = gst_gl_display_new_with_type (GST_GL_DISPLAY_TYPE_WIN32);
#else
#if GST_GL_HAVE_PLATFORM_EGL
g_message ("If media fails to play, set the envvar `GST_DEBUG=1`, and if GstGL context creation fails");
g_message ("due to \"Couldn't create GL context: Cannot share context with non-EGL context\",");
g_message ("set in the environment `GST_GL_PLATFORM=wgl` and `GST_GL_WINDOW=win32`,");
g_message ("and restart the GTK application");
#endif
self->gst_display = gst_gl_display_new ();
#endif
}
#if GST_GL_HAVE_PLATFORM_EGL
else
{
-2
View File
@@ -47,9 +47,7 @@ struct _GtkGstSink
GstVideoSink parent;
GstVideoInfo v_info;
#ifdef HAVE_GSTREAMER_DRM
GstVideoInfoDmaDrm drm_info;
#endif
GtkGstPaintable * paintable;
GdkGLContext * gdk_context;

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