diff options
author | Derek Foreman <derek.foreman@collabora.com> | 2022-01-27 11:20:34 -0600 |
---|---|---|
committer | Derek Foreman <derek.foreman@collabora.com> | 2022-11-25 08:29:05 -0600 |
commit | 92a9860e1d3e601e440e349508ff4ec864b95b65 (patch) | |
tree | 8b872f701a7b75e6bba2b4285b3509b6f62ea295 /shared | |
parent | 0e2136df7bf39b4b612f158130e5258b8cd87fbd (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.c | 121 |
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; +} |