summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
authorDerek Foreman <derek.foreman@collabora.com>2022-01-27 11:20:34 -0600
committerDerek Foreman <derek.foreman@collabora.com>2022-11-25 08:29:05 -0600
commit92a9860e1d3e601e440e349508ff4ec864b95b65 (patch)
tree8b872f701a7b75e6bba2b4285b3509b6f62ea295 /shared
parent0e2136df7bf39b4b612f158130e5258b8cd87fbd (diff)
libweston: Add function to find the output transform of a matrix
When we build up a matrix from a series of operations, it's very useful to know if the combined operations still result in something that matches a wl_output_transform. This adds a function to test if a matrix leads to a standard output transform, and returns the transform if it does. Tests are provided that check if complex series of operations return expected results - the weston_matrix_needs_filtering function is tested at the same time. Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
Diffstat (limited to 'shared')
-rw-r--r--shared/matrix.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/shared/matrix.c b/shared/matrix.c
index 369765b2..f301c5fa 100644
--- a/shared/matrix.c
+++ b/shared/matrix.c
@@ -297,6 +297,12 @@ near_zero_at(const struct weston_matrix *matrix, int row, int col)
}
static bool
+near_one_at(const struct weston_matrix *matrix, int row, int col)
+{
+ return near_zero(get_el(matrix, row, col) - 1.0);
+}
+
+static bool
near_pm_one_at(const struct weston_matrix *matrix, int row, int col)
{
return near_zero(fabs(get_el(matrix, row, col)) - 1.0);
@@ -395,3 +401,118 @@ weston_matrix_needs_filtering(const struct weston_matrix *matrix)
* heuristics, so recommend filtering */
return true;
}
+
+/** Examine a matrix to see if it applies a standard output transform.
+ *
+ * \param mat matrix to examine
+ * \param[out] transform the transform, if applicable
+ * \return true if a standard transform is present
+
+ * Note that the check only considers rotations and flips.
+ * If any other scale or translation is present, those may have to
+ * be dealt with by the caller in some way.
+ */
+WL_EXPORT bool
+weston_matrix_to_transform(const struct weston_matrix *mat,
+ enum wl_output_transform *transform)
+{
+ /* As a first pass we can eliminate any matrix that doesn't have
+ * zeroes in these positions:
+ * [ ? ? 0 ? ]
+ * [ ? ? 0 ? ]
+ * [ 0 0 ? ? ]
+ * [ 0 0 0 ? ]
+ * As they will be non-affine, or rotations about axes
+ * other than Z.
+ */
+ if (!near_zero_at(mat, 2, 0) ||
+ !near_zero_at(mat, 3, 0) ||
+ !near_zero_at(mat, 2, 1) ||
+ !near_zero_at(mat, 3, 1) ||
+ !near_zero_at(mat, 0, 2) ||
+ !near_zero_at(mat, 1, 2) ||
+ !near_zero_at(mat, 3, 2))
+ return false;
+
+ /* Enforce the form:
+ * [ ? ? 0 ? ]
+ * [ ? ? 0 ? ]
+ * [ 0 0 ? ? ]
+ * [ 0 0 0 1 ]
+ * While we could scale all the elements by a constant to make
+ * 3,3 == 1, we choose to be lazy and not bother. A matrix
+ * that doesn't fit this form seems likely to be too complicated
+ * to pass the other checks.
+ */
+ if (!near_one_at(mat, 3, 3))
+ return false;
+
+ if (near_zero_at(mat, 0, 0)) {
+ if (!near_zero_at(mat, 1, 1))
+ return false;
+
+ /* We now have a matrix like:
+ * [ 0 A 0 ? ]
+ * [ B 0 0 ? ]
+ * [ 0 0 ? ? ]
+ * [ 0 0 0 1 ]
+ * When transforming a vector with a matrix of this form, the X
+ * and Y coordinates are effectively exchanged, so we have a
+ * 90 or 270 degree rotation (not 0 or 180), and could have
+ * a flip depending on the signs of A and B.
+ *
+ * We don't require A and B to have the same absolute value,
+ * so there may be independent scales in the X or Y dimensions.
+ */
+ if (get_el(mat, 0, 1) > 0) {
+ /* A is positive */
+
+ if (get_el(mat, 1, 0) > 0)
+ *transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
+ else
+ *transform = WL_OUTPUT_TRANSFORM_90;
+ } else {
+ /* A is negative */
+
+ if (get_el(mat, 1, 0) > 0)
+ *transform = WL_OUTPUT_TRANSFORM_270;
+ else
+ *transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
+ }
+ } else if (near_zero_at(mat, 1, 0)) {
+ if (!near_zero_at(mat, 0, 1))
+ return false;
+
+ /* We now have a matrix like:
+ * [ A 0 0 ? ]
+ * [ 0 B 0 ? ]
+ * [ 0 0 ? ? ]
+ * [ 0 0 0 1 ]
+ * This case won't exchange the X and Y inputs, so the
+ * transform is 0 or 180 degrees. We could have a flip
+ * depending on the signs of A and B.
+ *
+ * We don't require A and B to have the same absolute value,
+ * so there may be independent scales in the X or Y dimensions.
+ */
+ if (get_el(mat, 0, 0) > 0) {
+ /* A is positive */
+
+ if (get_el(mat, 1, 1) > 0)
+ *transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ else
+ *transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
+ } else {
+ /* A is negative */
+
+ if (get_el(mat, 1, 1) > 0)
+ *transform = WL_OUTPUT_TRANSFORM_FLIPPED;
+ else
+ *transform = WL_OUTPUT_TRANSFORM_180;
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}