The first argument is the framebuffer operated on, so in order to stay
consistest, rename 'src' to 'framebuffer'. The second is the
destination. The destination is commonly referred to as 'dst' elsewhere,
so rename 'dest' to 'dst'.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1496
This one is a bit tricky. The tl;dr; is that switching from right-hand
multiplication to left-hand multiplication required applying the stack
from left to root. This actually allowed simplifying the code a bit,
since CoglMatrixEntry only stores a pointer to its parent, and that's
all we need to know for left-hand multiplication.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
CoglMatrix already is a typedef to graphene_matrix_t. This commit
simply drops the CoglMatrix type, and align parameters. There is
no functional change here, it's simply a find-and-replace commit.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
Ideally, we would use Graphene to do that, however as of now Graphene
lacks these APIs so we still need these helpers. Since we're preparing
to get rid of CoglMatrix, move them to a separate file, and rename them
with the 'cogl_graphene' prefix.
Since I'm already touching the world with this change, I'm also renaming
cogl_matrix_transform_point() to cogl_graphene_matrix_project_point(),
as per XXX comment, to make it consistent with the transform/projection
semantics in place.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
Given that CoglMatrix is simply a typedef to graphene_matrix_t, we can
remove all the GType machinery and reuse Graphene's.
Also remove the clutter-cogl helper, and cogl_matrix_to_graphene_matrix()
which is now unused.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
After the previous commit, the only field in the CoglMatrix structure is
a graphene_matrix_t. That means that CoglMatrix is effectively a graphene
matrix now, and the CoglMatrix struct isn't that much useful anymore.
Remove the CoglMatrix structure and make the CoglMatrix type a typedef to
graphene_matrix_t.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
Remove the cached inverse, and dirty flags, and typedef CoglMatrix to
graphene_matrix_t itself. I preverved the type for this commit to help
reducing the commit size, next commits will remove the CoglMatrix type.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
CoglMatrix doesn't have a 1:1 mapping of graphene functions, and
sometimes it's just not worth adding wrappers over it. It is easier
to expose the internal graphene_matrix_t and let callers use it
directly.
Add new cogl_matrix_get_graphene_matrix() helper function, and
simplify Clutter's matrix progress function.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
Instead of listing all matrix cells as floats, and the inverse
as a 16-length float array, use graphene_matrix_t in the structure
itself.
With this commit, all from/to CoglMatrix conversions are gone. It
is also not possible to initialize a CoglMatrix using the macro
anymore.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
Rename cogl_matrix_get_array() to cogl_matrix_to_float(), and
make it copy the floats to an out argument instead of returning
a pointer to the casted CoglMatrix struct.
The naming change is specifically made to match graphene's,
and ease the transition.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
Internally, a graphene_matrix_t representing the same transform that
of a CoglMatrix is the same matrix but transposed, so in order to get
the same element given a column and row for a matrix as if it would
be located in Cogl, it is necessary to swap the row and column when
retrieving it from the graphene matrix.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
Turns out inverting a matrix was the largest chunk of the CoglMatrix
code. By switching to Graphene, a lot of it can go away. The inverse
is still cached in the CoglMatrix struct itself, to preserve the
optimization.
However, switching to graphene_matrix_t to calculate the inverse has
a challenge: float precision. We had to work around it here, and it
needs an explanation.
The way to detect whether a matrix is invertible or not (i.e.
whether it's not a "singular" matrix, or not) is by checking
if the determinant equals 0. So far, so good.
Both graphene_matrix_t and CoglMatrix use single-precision
floats to store their 4x4 matrices. Graphene uses vectorized
operations to optimize determinant calculation, while Cogl
tries to keep track of the matrix type and has special-purpose
determinant functions for different matrix types (the most
common one being a 3D matrix).
Cogl, however, has a fundamentally flawed check for whether
the matrix is invertible or not. Have a look:
```
float det;
…
if (det*det < 1e-25)
return FALSE;
```
Notice that 1e-25 is *way* smaller than FLT_EPSILON. This
check is fundamentally flawed.
"In practice, what does it break?", the reader might ask.
Well, in this case, the answer is opposite of that: Cogl
inverts matrices that should not be invertible. Let's see
an example: the model-view-projection of a 4K monitor. It
looks like this:
```
| +0,002693 +0,000000 +0,000000 +0,000000 |
| +0,000000 -0,002693 +0,000000 +0,000000 |
| +0,000000 +0,000000 +0,002693 +0,000000 |
| -5,169809 +2,908017 -5,036834 +1,000000 |
```
The determinant of this matrix is -0.000000019530306557.
It evidently is smaller than FLT_EPSILON. In this situation,
Cogl would happily calculate the inverse matrix, whereas
Graphene (correctly) bails out and thinks it's a singular
matrix.
This commit works around that by exploiting the maths around
it. The basis of it is:
inverse(scalar * M) = (1/scalar) * M'
which can be extrapolated to:
inverse(M) = scalar * inverse(scalar * M) = M'
In other words, scaling the to-be-inversed matrix, then
scaling the inverse matrix by the same factor, gives us
the desired inverse. In this commit, the scale is calculated
as 1 / (smallest value in the diagonal).
I'm sorry for everyone that has to read through this :(
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
Use dot products to simplify calculations. Because the 'w' column of
the matrix is always summed, use 1.f in the 'w' component of the point
vector.
Because CoglMatrix is column-major and graphene_matrix_t is row-major,
it is necessary to transpose the matrix before retrieving the rows.
When we switch CoglMatrix to be row-major, this transposition will
go away.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
This is pretty similar to the other conversions, except we need to
store the matrix flags before operating on it, and update it using
this old value after. That's because cogl_matrix_init_from_array()
marks the matrix as entirely dirty, and we don't want that.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
At this point, we are still only changing CoglMatrix APIs internally, and
it should still produce the same output as before.
To achieve this, using graphens matrix implementation, we need to exploit
some knowledge about conventions used in Cogl and graphene respectively.
In Cogl, transformation matrices are equivalent to those of affine
transformation matrices. The convention used by graphene, however, is to
operate on matrices that are transposed compared to their affine
counterparts.
So for example, let's say we want to multiply the affine matrices A and B,
to get C.
A × B = C
The first step is to convert A and B to graphene matrices. We do this by
importing the floating point array, importing it directly using graphene.
Cogl exports its matrix to a column major floating point array. When we
import this in graphene, being row major, we end up with the same matrix,
only transposed.
Cogl Graphene
A <===> Aᵀ
B <===> Bᵀ
We then multiply these imported matrices in reverse
Bᵀ × Aᵀ
which in turn, due to ABᵀ = BᵀAᵀ, gives us
Bᵀ × Aᵀ = (A × B)ᵀ
Our original goal was to find C, thus we know that
A × B = C
That means we can shuffle things around a bit.
A × B = C
Bᵀ × Aᵀ = (A × B)ᵀ
Bᵀ × Aᵀ = Cᵀ
With the same conversion as done when going from Cogl to graphene, only
the other way around, we still end up effectively transposing the matrix
during the conversion.
Graphene Cogl
Cᵀ <===> C
Thus when converting Cᵀ to Cogl, we in fact end up with C.
(Explanation authored by Jonas Ådahl)
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
Graphene provides skewing as part of graphene_matrix_t API, and it'll
be easier for the transition to just expose similar API surfaces.
Move the matrix skew methods to CoglMatrix.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1439
This resolves a couple of FIXMEs. The FIXME comments were right in
stating that not *all* journals needed flushing, only the one we
are trying to put on screen needs flushing.
However we can't eliminate all flushes because the winsys swap calls
that follow go directly into OpenGL which knows nothing about cogl
journalling. So the journal *must* be flushed before the swap, to give
OpenGL the correct state.
P.S. If this turns out to cause any bugs then the next best answer is
to just remove the FIXME comments. Because flushing is still the right
thing to do.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1362
Even when a direct client buffer has a compatible format, stride and
modifier for direct scanout, drmModePageFlip() may still fail sometimes.
From testing, it has been observed that it may seemingly randomly fail
with ENOSPC, where all subsequent attempts later on the same CRTC
failing with EBUSY.
Handle this by falling back to flipping after having composited a full
frame again.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1410
When the CoglRenderer didn't set the DMA buffer constructor vfunc, we
return NULL. What we didn't do was set the error, meaning the caller
would crash if it tried to look up why DMA buffer construction failed.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1430
This will be used when screencasting monitors so that if
there's scanout in place, it'll still be possible to blit
it to a PipeWire-owned framebuffer, and stream it.
Add a new 'blit_to_framebuffer' vfunc to CoglScanout, and
implement it in MetaDrmBufferGbm.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1421
In certain situations it's desirable to keep pipelines around for
the whole lifetime of the session. In order to not leak them and
properly clean them up on shutdown, introduce a new mechanism to
create named pipelines that are bound to their correstponding
context and may be used across file boundries.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1372
In order to support the DRM formats DRM_FORMAT_ABGR16161616F and
friends, as well as the wl_shm formats WL_SHM_FORMAT_ABGR16161616F and
friends, cogl needs to have knowledge about said formats too.
We don't have a software implementation of the half point data types
however, so the pack/unpack methods remain unimplemented. We don't need
them for now, so it's not crucial that we add them.
For the GLES2 driver, currently only two formats are supported, and
since we don't currently have pack/unpack implementations, the other
formats will for now remain unsupported, until we have a half float
implementation.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/804
In the case of indirect rendering like the first frame to use mutter's
background wallpaper:
Texture_A -> FBO_B (Texture_B) -> FBO_C (screen)
we would be trying to render the contents of both FBO_B and FBO_C in
the same flush, before the contents of Texture_A had made it to FBO_B.
So when FBO_C wants to use mipmaps of Texture_B they didn't exist yet
and appeared all black. And the blackness would remain for subsequent
frames as cogl has now decided the mipmaps of FBO_B are no longer
"dirty" and don't need refreshing:
FBO_B (Texture_B) (mipmaps_dirty==FALSE but black) -> FBO_C (screen)
We must flush FBO_B before referencing Texture_B for use in rendering
FBO_C. This only happens when Texture_A changes (e.g. when the user
changes their background wallpaper) so there's no ongoing performance
penalty from this flush.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1347
The native backend had a plain counter, and the X11 backend used the
CoglOnscreen of the screen; change it into a plain counter in
ClutterStageCogl. This also moves the global frame count setting to the
frame info constuctor.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285
We currently have mutter set a global frame counter on the frame info in
the native backend, but in order to do this from clutter, change the
frame info construction from being implicitly done so when swapping
buffers to having the caller create the frame info and passing that to
the swap buffers call.
While this commit doesn't introduce any other changes than the API, the
intention is later to have the caller be able to pass it's own state
(e.g. the global frame count) along with the frame info.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285
_cogl_shader_set_source_with_boilerplate and _cogl_shader_compile_real
have enough GL assumptions that it makes sense to push them into the
backend. Taken together their only callers are under driver/gl, so.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1194
This had been an entirely-too-GL-aware collection of renderer queries,
mostly to work around driver bugs and handle software drivers
intelligently. The driver workarounds have been removed (fix your
driver, and if you can't because it's closed-source, fix that first),
and we now delegate the am-i-software-or-not logic to the backend, so
this can all go
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1194
We delegate the answer through CoglDriverVtable::is_hardware_accelerated
since this is properly a property of the renderer, and not something the
cogl core should know about. The answer given for the nop driver is
admittedly arbitrary, yes it's infinitely fast but no there's not any
"hardware" making it so.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1194
Make it possible to cause the next frame to scan out directly from the
passed CoglScannout. This makes it possible to completely bypass
compositing for the following frame.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
Instead of always swapping buffers and flipping the back buffer, make it
possible to scan out a provided buffer directly without swapping any EGL
buffers.
A buffer is passed as an object implementing the empty CoglScanout
interface. It is only possible to do this in the native backend; and the
interface is implemented by MetaDrmBufferGbm. When directly scanned out,
instead of calling gbm_surface_lock_front_buffer() to get the gbm_bo and
fbid, get it directly from the MetaDrmBufferGbm, and use that to create
the page flip KMS update.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
It isn't immediately obvious that this is impossible, because there's some
"action at a distance" going on with framebuffers that have their size
set lazily, after their textures get allocated; so let's make this a
critical warning rather than crashing.
In particular, this works around a crash when gnome-shell tries to blur a
background that hasn't yet had any space allocated for it - which it seems
is really an actor layout bug, but more robustness seems good to have.
Workaround for <https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2538>.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1172
Signed-off-by: Simon McVittie <smcv@debian.org>
A texture with no pixels isn't a useful thing to have, and breaks
assumptions elsewhere. For example, CoglFramebuffer assumes that after
a texture has been allocated, it will have width and height both greater
than 0.
In particular, this works around a crash when gnome-shell tries to blur a
background that hasn't yet had any space allocated for it - which it seems
is really an actor layout bug, but more robustness seems good to have.
Workaround for <https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2538>.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1172
Signed-off-by: Simon McVittie <smcv@debian.org>
cogl_object_[get|set]_value_object() are annotated as [get|set]-value-func
for objects and primitives, so they must be visible for any derived types
to be usable from introspection.
https://gitlab.gnome.org/GNOME/mutter/-/issues/1146
Cogl shares some GL functions between the GLES and the big
GL drivers. Namely, it shares _cogl_driver_gl_context_init
and _cogl_driver_gl_context_deinit between these two drivers.
The plot twist is: even though these functions are shared and
their prototypes are in cogl-util-gl-private.h, they're actually
implemented inside cogl-driver-gl.c, which is strictly only
about the big GL driver.
This is problematic when building Mutter on ARM v7, where we
need to disable OpenGL, but keep GLES enabled.
Fix this by moving the shared GL functions to a shared GL file.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1151
Just like libmutter-clutter, and libmutter, mark exported symbols with
an COGL_EXPORT macro. This removes the .map and .map.in files previously
used, containing a list of semi private symbols. This symbol was out of
date, i.e. pointed to non-existing symbols, and was also replaced with
COGL_EXPORT macros.
unit_test_* symbols are exported by the help of the unit test defining
macro. test_* symbols are no longer supported as it proved unnecessary.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1059
This is so that cogl-trace.h can start using things from cogl-macros.h,
and so that it doesn't leak cogl-config.h into the world, while exposing
it to e.g. gnome-shell so that it can make use of it as well. There is
no practical reason why we shouldn't just include cogl-trace.h via
cogl.h as we do with everything else.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1059
We need the stencil buffer to consist of binary values of 0 and 1
because we're doing additions and subtractions on the buffer, so even
though this is the default, explicitely set the stencil mask to 0x1.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1096
When using a region clip and something has a rectangle clip pushed, a
special drawing method for ClutterTexts (emit_vertex_buffer_geometry()
in cogl-pango-display-list.c) starts to fail and clipping issues with
long texts (because emit_vertex_buffer_geometry() is only used for texts
longer than 25 characters) start to appear. This specifically happened
in Looking Glass, where the StViewport of the ScrollView sets a
rectangle clips and the texts are usually longer than 25 characters.
This is caused by the changing of the perspective and modelview matrix
when drawing to the stencil buffer and started happening when
region-clipping was introduced with commit 8598b654. Even though the
changing of the matrices was done before that, too, the issue probably
didn't happen because `rect->can_be_scissor` was TRUE and no stencil
buffer clipping was used at all.
To fix this, temporarily save the old matrices, then set the new ones
and restore the old ones when we're done drawing to the stencil buffer.
Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/2246https://gitlab.gnome.org/GNOME/mutter/merge_requests/1096
This is a winsys-specific API that allows exporting a DMA buffer fd.
The CoglDmaBufHandle structure allows passing the ownership of the
DMA buffer to whoever is using it, so the winsys doesn't need to
manually track it.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086
In future patches, we'll create additional CoglFramebuffers that
will be shared via DMA-Buf with PipeWire. When recording frames,
we'll blit the current onscreen framebuffer into the shared one.
However, that presents a problem: cogl_framebuffer_blit() mimics
glBlitFramebuffer() semantics, and doesn't do an implicit flush
of the GPU command stream. As a consequence, clients may receive
unblitted or incomplete framebuffers.
We could use cogl_framebuffer_finish() to ensure the commands were
submitted to the GPU, but it is too harsh -- it blocks the CPU
completely until the commands are finished!
Add cogl_framebuffer_flush(), which ensures the command stream is
submitted to the GPU without blocking the CPU. Even though we don't
use the framebuffer specifically, it may be useful in the future
for e.g. a potential Vulkan backend to have access to the framebuffer.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1086
Just pass it in to the vertex shader like in GLES, it's one less thing
to vary between drivers. mutter is, shall we say, not a heavy user of
point primitives, so any performance impact (it might be measurable, who
knows) is not an issue. Again, the feature flag remains to be cleaned up
in a future commit.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/995
We're always running through the GLSL pipeline so the fixed-function
alpha test is never invoked. This change does not yet remove the
alpha-test feture bit from the context because this bit of uniform
handling is going to be simplified in a future commit.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/995
At this point only the gl driver is at all aware of the difference
between core and compat contexts. COGL_PRIVATE_FEATURE_GL_FIXED is also
now quite misnamed, since we're using the GLSL pipeline even for pre-GL3
contexts. Remove the private feature and handle the few remaining
differences by checking the driver class inside the gl driver.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/973
There's quite a bit of CoglContext that properly belongs to the driver.
Add some hooks to allow the context to create/destroy such state. We
don't have driver-private storage in the CoglContext yet, though we
probably should.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/973