We pulled out the bounds calculation for performance reasons, but the
caller can't know how to properly compute them. Inside gtk+, we can do
that but it's not good enough for public API.
When the max cost for finding a path gets to high, the diff can now be
aborted.
Because render nodes have a fallback method (by just marking the whole
bounds of the nodes as different), we use this to improve performance
of diffs.
This brings fishbowl (which is basically a container node with N images
that change every frame) back to close to previous performance.
Now that we have the full render nodes available, there is not much
benefit in fine-grained control over multiple rectangles.
In particular, it's causing pain with complex regions.
There might be a benefit in clipping to the region's rectangles in cases
like widget-factory where the whole diff is made up of the 2 rectangles
of spinner and the pulsing progress bar, but it needs a good heuristic
for where this is useful.
... and diff the previous node with the current one to determine the
clip region.
This doubles the work necessary to track clip regions, but the following
commits will clean that up.
It doesn't need to be exported anymore.
As a side effect, the inspector no longer has any information about the
render region, so remove the code that was taking care of that.
This includes a copy of the diff(1) algorithm used by git diff by Davide
Libenzi.
It's used for the common case ofcontainer nodes having only very few
changes for the few nodes of child widgets that changed (like a button
lighting up when hilighted or a spinning spinner).
... and gsk_render_node_can_diff(). Those are vfuncs to compute a region
containing all the pixels that differ between the two nodes.
This is just the plumbing that chains into node classes. No node
implements it yet.
Adding the offset node broke serialization in 2 ways:
1. We store the enum value in the node, so make sure to not change it
for existing values
2. The offset node was missing in the deserialization lookup table
This is a special case of the transform node that does a 2D translation.
The implementation in the Vulkan and GL renderers is crude and just does
the same as the transform node.
Nothing uses that node yet.
This way, we can postpone the actual rendeing of the node until the
renderer. This allows the renderer to choose the right scale to
render at, so it can decide to use 2x scale for hidpi on its own.
Last but not least, it makes all nodes independent of the context they
are created in, because they do not need to know at snapshot time what
they will ultimately be rendered into.
This is an automatic rename of various things related
to the window->surface rename.
Public symbols changed by this is:
GDK_MODE_WINDOW
gdk_device_get_window_at_position
gdk_device_get_window_at_position_double
gdk_device_get_last_event_window
gdk_display_get_monitor_at_window
gdk_drag_context_get_source_window
gdk_drag_context_get_dest_window
gdk_drag_context_get_drag_window
gdk_draw_context_get_window
gdk_drawing_context_get_window
gdk_gl_context_get_window
gdk_synthesize_window_state
gdk_surface_get_window_type
gdk_x11_display_set_window_scale
gsk_renderer_new_for_window
gsk_renderer_get_window
gtk_text_view_buffer_to_window_coords
gtk_tree_view_convert_widget_to_bin_window_coords
gtk_tree_view_convert_tree_to_bin_window_coords
The commands that generated this are:
git sed -f g "GDK window" "GDK surface"
git sed -f g window_impl surface_impl
(cd gdk; git sed -f g impl_window impl_surface)
git sed -f g WINDOW_IMPL SURFACE_IMPL
git sed -f g GDK_MODE_WINDOW GDK_MODE_SURFACE
git sed -f g gdk_draw_context_get_window gdk_draw_context_get_surface
git sed -f g gdk_drawing_context_get_window gdk_drawing_context_get_surface
git sed -f g gdk_gl_context_get_window gdk_gl_context_get_surface
git sed -f g gsk_renderer_get_window gsk_renderer_get_surface
git sed -f g gsk_renderer_new_for_window gsk_renderer_new_for_surface
(cd gdk; git sed -f g window_type surface_type)
git sed -f g gdk_surface_get_window_type gdk_surface_get_surface_type
git sed -f g window_at_position surface_at_position
git sed -f g event_window event_surface
git sed -f g window_coord surface_coord
git sed -f g window_state surface_state
git sed -f g window_cursor surface_cursor
git sed -f g window_scale surface_scale
git sed -f g window_events surface_events
git sed -f g monitor_at_window monitor_at_surface
git sed -f g window_under_pointer surface_under_pointer
(cd gdk; git sed -f g for_window for_surface)
git sed -f g window_anchor surface_anchor
git sed -f g WINDOW_IS_TOPLEVEL SURFACE_IS_TOPLEVEL
git sed -f g native_window native_surface
git sed -f g source_window source_surface
git sed -f g dest_window dest_surface
git sed -f g drag_window drag_surface
git sed -f g input_window input_surface
git checkout NEWS* po-properties po docs/reference/gtk/migrating-3to4.xml
This renames the GdkWindow class and related classes (impl, backend
subclasses) to surface. Additionally it renames related types:
GdkWindowAttr, GdkWindowPaint, GdkWindowWindowClass, GdkWindowType,
GdkWindowTypeHint, GdkWindowHints, GdkWindowState, GdkWindowEdge
This is an automatic conversion using the below commands:
git sed -f g GdkWindowWindowClass GdkSurfaceSurfaceClass
git sed -f g GdkWindow GdkSurface
git sed -f g "gdk_window\([ _\(\),;]\|$\)" "gdk_surface\1" # Avoid hitting gdk_windowing
git sed -f g "GDK_WINDOW\([ _\(]\|$\)" "GDK_SURFACE\1" # Avoid hitting GDK_WINDOWING
git sed "GDK_\([A-Z]*\)IS_WINDOW\([_ (]\|$\)" "GDK_\1IS_SURFACE\2"
git sed GDK_TYPE_WINDOW GDK_TYPE_SURFACE
git sed -f g GdkPointerWindowInfo GdkPointerSurfaceInfo
git sed -f g "BROADWAY_WINDOW" "BROADWAY_SURFACE"
git sed -f g "broadway_window" "broadway_surface"
git sed -f g "BroadwayWindow" "BroadwaySurface"
git sed -f g "WAYLAND_WINDOW" "WAYLAND_SURFACE"
git sed -f g "wayland_window" "wayland_surface"
git sed -f g "WaylandWindow" "WaylandSurface"
git sed -f g "X11_WINDOW" "X11_SURFACE"
git sed -f g "x11_window" "x11_surface"
git sed -f g "X11Window" "X11Surface"
git sed -f g "WIN32_WINDOW" "WIN32_SURFACE"
git sed -f g "win32_window" "win32_surface"
git sed -f g "Win32Window" "Win32Surface"
git sed -f g "QUARTZ_WINDOW" "QUARTZ_SURFACE"
git sed -f g "quartz_window" "quartz_surface"
git sed -f g "QuartzWindow" "QuartzSurface"
git checkout NEWS* po-properties
And then clip the texture using the current (maybe also rounded) clip.
This way, the result is correct. We don't necessarily have to do the
offscreen drawing in any case, but got the safe route for now.
Put GdkGLTexture into its own file and rename the API to
gdk_gl_texture_foo() instead of gdk_texture_foo_for_gl().
Apart from naming, no actual code changes.
An alternative GskTextNode constructor that does no text measuring. That
way, we can measure the text before and check if the node will be
outside of the current clip anyway.
Remove all the old 2.x and 3.x version annotations.
GTK+ 4 is a new start, and from the perspective of a
GTK+ 4 developer all these APIs have been around since
the beginning.
This happens when deserializing testcases and it really confuses
valgrind into thinking we're longjmp()ing.
And deserializing rendernodes is slow anyway, so who cares about a few
more malloc()s.
We can't just unconditionally create a larger texture here, since the
incoming cairo surface might have a device scale that doesn't fit our
scale_factor. Instead, look up the surface device scale and use that.
Add a setter for per-renderer debug flags, and use
them where possible. Some places don't have easy access
to a renderer, so this is not complete.
Also, use g_message instead of g_print throughout.
We already ceil() the given float texture sizes here, so if they are
valid, the result should definitely be > 0. Textures with size 0 can't
be properly used, especially not as render targets, where they will
trigger an assertion failure later in a glCheckFramebuffer call.
Text nodes will almost always end up using the exact same texture and
the same program. So, in that case we can simply add vertex data for all
the characters we need to draw and use just one draw call.
Render nodes can end up with bounds < 1 since they are floats, and the
implicit cast to int ends up creating a texture with 0 width or height.
Use ceil() instead in create_texture so we don't have to do that on the
caller side everywhere.
VkImage contains a reference to the VkDeviceMemory and, because
the current code frees the VkDeviceMemory before destroying the
VkImage that references it, a warning is triggered by the validation
layers.
This is not critical, since we release both resources at the same
place. But the warning triggered by the validation layers sums up
adding 1 MB per second of extra debug logging, making the debugging
process much more painful.
This commit simply swaps the destruction order, and destroys the
VkImage first, then the now unused VkDeviceMemory.
This means we can directly upload these as textures, rather than
create a new surface and draw it into that. We still have to upload,
but there isn't a lot we can do about this as for these nodes
we generally redraw everything each time.
We cannot unrealize a renderer in the dispose function, because that
would cause this chain to happen:
gsk_gl_renderer_dispose
gsk_renderer_dispose
gsk_renderer_unrealize
gsk_gl_renderer_unrealize
So we would call into thje GL renderers unrealize when it has already
(partially) disposed itself and ause accesses to dead variables.
This fixes blurry text and icons whenever we apply shadows
in a hidpi window. Shadow nodes are the last ones that we
still use fallback for, and this was causing us to render
the text blurry.
Pass a scale factor when caching glyphs or looking them
up in the cache. The glyphs in the cache are rendered
with subpixel precision determined by the scale. Update
all callers to pass a scale factor according to the window
scale. This lets us render crisp glyphs on hidpi systems.
The copy of the PangoGlyphString we do here was showing up
in some profiles. To avoid it, allocate the PangoGlyphInfo array
as part of the node itself. Update all callers to deal with
the slight api change required for this.
Rename the surface getter to peek, following other render
node getters, and make the surface-based constructor private,
since it is not something we want to encourage.
Update all callers.
The color-matrix shader was creating pixels with r,g,b > a in
some cases, which leads to unexpected test failures. In particular
this as visible the opacity render node test for opacity 0.
We were node handling coordinates correctly when dealing
with differently sized child nodes in a blendmode node.
This was showing up in the gtk4-demo css blendmode example,
for blendmodes other than normal.
This patch makes that work using 1 of 2 options:
1. Add all missing enums to the switch statement
or
2. Cast the switch argument to a uint to avoid having to do that (mostly
for GdkEventType).
I even found a bug while doing that: clearing a GtkImage with a surface
did not notify thae surface property.
The reason for enabling this flag even though it is tedious at times is
that it is very useful when adding values to an enum, because it makes
GTK immediately warn about all the switch statements where this enum is
relevant.
And I expect changes to enums to be frequent during the GTK4 development
cycle.
-Wint-conversion is important because it checks casts from ints to
pointers.
-Wdiscarded-qualifiers is important to catch cases where we don't
strings when we should.
In some cases, we were creating gigantic intermediate textures
only to clip out a small section afterwards (e.g. in the listbox
example in gtk4-demo). This is wasteful if we apply effects on
the texture, such as blur or color-matrix. So, clip the dimensions
of the intermediate texture with the current clip. To make this
feasible, we move the texture coordinate computation out of the
pipeline setup functions into the node_as_texture function where
this clipping happens.
One extra complication we encounter is that the node might get
clipped away completely. Since Vulkan does not allow to create
empty images, we bail out in this case and not draw anything.
With these changes, the listbox example in gtk4-demo goes from
32M pixels of intermediate texture to 320000.
Instead of having a function with lots of arguments in
GskVulkanRender that we call from GskVulkanRenderPass which
then just calls back into GskVulkanRenderPass, just create
the new render pass object locally, and an api to add it
to the list that GskVulkanRender keeps. This makes it
a lot easier to preserve all the relevant parameters from
the parent render pass.
Move away from the idea of intra-frame sampling, since we only
push samples once per frame, anyway. Instead, make the profiler
keep a rolling average of the last n frames.
Whenever we need a node as a texture, we now start a new render
pass that renders the node into a new intermediate texture, and
set up a semaphore to make the current render pass wait for it.
As part of this reorganization, much of the setup and drawing
code moved from gskvulkanrender.c to gskvulkanrenderpass.c.
Allow to pass in semaphores to wait for before executing
and to signal after executing the command buffer. This
just exposes the capabilities of the underlying Vulkan
api. Update all callers to pass no semaphores, for now.
We will use this in the future.
I've finally figured out the right combination of src and dest
stage and access flags to make all validation warnings go away.
This commit only fixes the direct upload code.
This is another example for a 2-texture shader.
So far, only separable blend modes are implemented.
The implementation is not optimized, with an
if-else cascade in the shader.
We were looking at uninitialized memory here, instead
of the type of the source clip, as we should.
This showed up as mispositioned clip in the first frame
of a crossfade stack transition, and also as overdraw in
sliding stack transitions.