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.
... 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.
These are just factoring out gdk_draw_context_begin/end_frame() so I can
add one tiny thing there later.
And I did both even though I only need one, because it felt wrong to
just do one.
Make the function look like that:
1. handle special case
2. maybe GC
3. draw
4. queue next gc
5. cleanup
This seems like the sanest approach to avoid gc() collecting things
necessary for drawing in the future.
And I need to refactor stuff, so having it out of the way is a good
idea.
... and plumb the color state through the downloading machinery, where
no matter what path it takes it ends up in
gdk_memory_convert_color_state() or gdk_memory_convert().
The 2nd of those has been expanded to optionally do colorstate
conversion when the 2 colorstates are different.
When we draw large images, we absolutely do not want to keep memory that
we do not need. So do a GC run after every tile. That otentially slows
down things, but it also improves the chances of not running out of
memory.
Here's the node for the image I managed to create after I applied this
patch:
repeat {
bounds: 0 0 50000 50000;
child: text {
font: "Noto Color Emoji 10000px";
glyphs: 661 0 0 0 color;
offset: 0 10000;
hint-style: none;
}
}
Make the node processor and the pattern writer track the current
compositing color state. Color state nodes change it. We pass
the surface color state down via the frame apis.
The name of the variable is "ccs" for "compositing color space". It's an
unused variable name and it's common enough to deserve a short and sweet
name.
This uses offscreens for every call to get_node_as_image().
This is useful both for benchmarking benefits of those implementations
as well as checking that the node-specific paths produce identical
results.
It didn't bring any noticable benefits and it isn't compatible with the
way we intend to do colorstate support.
And nobody seems to want to spend time on it, so let's get rid of it.
We can bring it back later if someone wants to work on it.
Instead of having renderer API to wait for any number of frames, just
have gsk_gpu_frame_wait() to wait for a single frame.
This unifies behavior on Vulkan and GL, because unlike Vulkan, GL does
not allow waiting for multiple fences.
To make up for it, we replace waiting for multiple frames with finding
the frame with the earliest timestamp and waiting for that one.
Also implement wait() for GL.
We want to use a viewport that gives us the right scale back.
This fixes problems where glyph lookups were inefficient because
the scale part of the key would fluctuate ever so slightly.
Instead of forever running a timeout to do gc, ensure the timeout
is scheduled whenever we render a frame (this is done by calling
gsk_gpu_device_maybe_gc () before gsk_gpu_frame_render (), and
gsk_gpu_device_queue_gc () after).
Add GSK_GPU_SKIP=glyph-align to turn off the glyph aligning.
FIXME: Should this be handled by the renderer at all or should we rely
on higher rendering layers to align glyphs properly?
This is kind of a tricky question just like with texture-scale nodes and
NEAREST filtering, because rendernodes can be embedded in other nodes
that disturb the pixel grid.
When downscaling more than 2x in either dimension, force mipmap use for
the texture in a texture node.
It improves the quality of textures but takes extra work.
The GL renderer does this, too (for textures that aren't in the icon cache).
This can be disabled via GSK_GPU_SKIP=mipmap.
Fixes the big-checkerboard-scaled-down2 test.
Unless GSK_GPU_SKIP=gradients is given, we sample every point 4x instead
of 1x. That makes the shader run slower (by roughly a factor of 2.5x)
but it improves quality quite a bit.
The GL branch should eventually call into gdk_gl_context_get_scale(),
which is what checks for GDK_DEBUG=gl-fractional; whereas the Vulkan
branch needs no change.
This adds GSK_GPU_IMAGE_CAN_MIPMAP and GSK_GPU_IMAGE_MIPMAP flags and
support to ensure_image() and image creation functions for creating a
mipmapped image.
Mipmaps are created using the new mipmap op that uses
glGenerateMipmap() on GL and equivalent blit ops on Vulkan.
This is then used to ensure the image is mipmapped when rendering it
with a texture-scale node.
Use glDrawArraysInstancedBaseInstance() to draw. (Yay for GL naming.)
That allows setting up the offset in the vertex array without having to
glVertexAttribPointer() everything again.
However, this is only supported since GL 4.2 and not at all in stock GLES,
so we need to have code that can work without it.
Fortunately, it is mandatory in Vulkan, so every recent GPU supports it.
And if that GPU has a proper driver, it will also expose the GL extension
for it.
(Hint: You can check https://opengles.gpuinfo.org/listextensions.php for
how many proper drivers exist outside of Mesa.)
The env var allows skipping various optimizations in the GPU shader.
This is useful for testing during development when trying to figure
out how to make a renderer as fast as possible.
We could also use it to enable/disable optimizations depending on GL
version or so, but I didn't think about that too much yet.
Frames now carry a timestamp for when they are used.
This is mainly intended to attach timestamps to cached items (textures
or glyphs), but it could in theory also be used when profiling.
We use wallclock time here, not server time, because it's cheaper and
because we're more intereseted in the local machine we're rendering on.
For now, it just renders using cairo, uploads the result to the GPU,
blits it onto the framebuffer and then is happy.
But it can do that using Vulkan and using GL (no idea which version).
The most important thing still missing is shaders.
It also has a bunch of copy/paste from the Vulkan renderer that isn't
used yet.
But I didn't want to rip it out and then try to copy it back later