libweston, clients, tests: implement weston_matrix in terms of weston_mat4f

This converts weston_matrix and weston_vector to use linalg-types
internally. All direct accesses to members had to be converted
everywhere, mostly in the simplest form possible which leaves some
trivially reducable code around.

The intention is that we can now gradually migrate away from
weston_matrix in the future.

Look like one trailing space got accidentally annihilated in
compositor.c.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
Pekka Paalanen 2025-03-24 17:56:34 +02:00
parent 92d7caa767
commit 3fefb5ba44
16 changed files with 164 additions and 340 deletions

View file

@ -117,11 +117,11 @@ finish_calibration (struct calibrator *calibrator)
*/
memset(&m, 0, sizeof(m));
for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) {
m.d[i] = calibrator->tests[i].clicked_x;
m.d[i + 4] = calibrator->tests[i].clicked_y;
m.d[i + 8] = 1;
m.M.col[0].el[i] = calibrator->tests[i].clicked_x;
m.M.col[1].el[i] = calibrator->tests[i].clicked_y;
m.M.col[2].el[i] = 1;
}
m.d[15] = 1;
m.M.col[3].el[3] = 1;
weston_matrix_invert(&inverse, &m);
@ -129,8 +129,8 @@ finish_calibration (struct calibrator *calibrator)
memset(&y_calib, 0, sizeof(y_calib));
for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) {
x_calib.f[i] = calibrator->tests[i].drawn_x;
y_calib.f[i] = calibrator->tests[i].drawn_y;
x_calib.v.el[i] = calibrator->tests[i].drawn_x;
y_calib.v.el[i] = calibrator->tests[i].drawn_y;
}
/* Multiples into the vector */
@ -138,8 +138,8 @@ finish_calibration (struct calibrator *calibrator)
weston_matrix_transform(&inverse, &y_calib);
printf ("Calibration values: %f %f %f %f %f %f\n",
x_calib.f[0], x_calib.f[1], x_calib.f[2],
y_calib.f[0], y_calib.f[1], y_calib.f[2]);
x_calib.v.el[0], x_calib.v.el[1], x_calib.v.el[2],
y_calib.v.el[0], y_calib.v.el[1], y_calib.v.el[2]);
exit(0);
}

View file

@ -815,7 +815,7 @@ render(struct window *window, struct buffer *buffer)
glUniform1f(window->gl.offset_uniform, offset);
glUniformMatrix4fv(window->gl.reflection_uniform, 1, GL_FALSE,
(GLfloat *) reflection.d);
(GLfloat *) reflection.M.colmaj);
glClearColor(0.0,0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
@ -864,7 +864,7 @@ render_mandelbrot(struct window *window, struct buffer *buffer)
glUniform1f(window->gl.offset_uniform, offset);
glUniformMatrix4fv(window->gl.reflection_uniform, 1, GL_FALSE,
(GLfloat *) reflection.d);
(GLfloat *) reflection.M.colmaj);
glClearColor(0.6, 0.6, 0.6, 1.0);
glClear(GL_COLOR_BUFFER_BIT);

View file

@ -940,10 +940,10 @@ redraw(struct window *window)
angle = ((time - window->initial_frame_time) / speed_div)
% 360 * M_PI / 180.0;
}
rotation.d[0] = cos(angle);
rotation.d[2] = sin(angle);
rotation.d[8] = -sin(angle);
rotation.d[10] = cos(angle);
rotation.M.col[0].el[0] = cos(angle);
rotation.M.col[0].el[2] = sin(angle);
rotation.M.col[2].el[0] = -sin(angle);
rotation.M.col[2].el[2] = cos(angle);
switch (window->buffer_transform) {
case WL_OUTPUT_TRANSFORM_FLIPPED:
@ -982,7 +982,7 @@ redraw(struct window *window)
glViewport(0, 0, window->buffer_size.width, window->buffer_size.height);
glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
(GLfloat *) rotation.d);
(GLfloat *) rotation.M.colmaj);
if (window->opaque || window->fullscreen)
glClearColor(0.0, 0.0, 0.0, 1);

View file

@ -330,9 +330,9 @@ compute_calibration(struct calibrator *cal, float *result)
*/
weston_matrix_init(&m);
for (i = 0; i < 3; i++) {
m.d[i + 0] = cal->samples[i].touched.x;
m.d[i + 4] = cal->samples[i].touched.y;
m.d[i + 8] = 1.0f;
m.M.col[0].el[i] = cal->samples[i].touched.x;
m.M.col[1].el[i] = cal->samples[i].touched.y;
m.M.col[2].el[i] = 1.0f;
}
m.type = WESTON_MATRIX_TRANSFORM_OTHER;
@ -342,20 +342,20 @@ compute_calibration(struct calibrator *cal, float *result)
}
for (i = 0; i < 3; i++) {
x_calib.f[i] = cal->samples[i].drawn_cal.x;
y_calib.f[i] = cal->samples[i].drawn_cal.y;
x_calib.v.el[i] = cal->samples[i].drawn_cal.x;
y_calib.v.el[i] = cal->samples[i].drawn_cal.y;
}
x_calib.f[3] = 0.0f;
y_calib.f[3] = 0.0f;
x_calib.v.el[3] = 0.0f;
y_calib.v.el[3] = 0.0f;
/* Multiples into the vector */
weston_matrix_transform(&inverse, &x_calib);
weston_matrix_transform(&inverse, &y_calib);
for (i = 0; i < 3; i++)
result[i] = x_calib.f[i];
result[i] = x_calib.v.el[i];
for (i = 0; i < 3; i++)
result[i + 3] = y_calib.f[i];
result[i + 3] = y_calib.v.el[i];
return 0;
}

View file

@ -1842,8 +1842,9 @@ widget_cairo_update_transform(struct widget *widget, cairo_t *cr)
surface->allocation.width,
surface->allocation.height,
surface->buffer_scale);
cairo_matrix_init(&m, matrix.d[0], matrix.d[1], matrix.d[4],
matrix.d[5], matrix.d[12], matrix.d[13]);
cairo_matrix_init(&m, matrix.M.col[0].x, matrix.M.col[0].y,
matrix.M.col[1].x, matrix.M.col[1].y,
matrix.M.col[3].x, matrix.M.col[3].y);
cairo_transform(cr, &m);
}

View file

@ -31,6 +31,7 @@
#include <stdbool.h>
#include <wayland-server-protocol.h>
#include <libweston/linalg-types.h>
#ifdef __cplusplus
extern "C" {
@ -44,12 +45,12 @@ enum weston_matrix_transform_type {
};
struct weston_matrix {
float d[16];
struct weston_mat4f M;
unsigned int type;
};
struct weston_vector {
float f[4];
struct weston_vec4f v;
};
/** Arbitrary coordinates in any space */

View file

@ -463,33 +463,33 @@ calc_inverse_matrix_transform(const struct weston_matrix *matrix,
}
/* The vectors and matrices involved will always produce f[3] == 1.0. */
top_left.f[0] = rect_input->x;
top_left.f[1] = rect_input->y;
top_left.f[2] = 0.0f;
top_left.f[3] = 1.0f;
top_left.v.el[0] = rect_input->x;
top_left.v.el[1] = rect_input->y;
top_left.v.el[2] = 0.0f;
top_left.v.el[3] = 1.0f;
bottom_right.f[0] = rect_input->x + rect_input->width;
bottom_right.f[1] = rect_input->y + rect_input->height;
bottom_right.f[2] = 0.0f;
bottom_right.f[3] = 1.0f;
bottom_right.v.el[0] = rect_input->x + rect_input->width;
bottom_right.v.el[1] = rect_input->y + rect_input->height;
bottom_right.v.el[2] = 0.0f;
bottom_right.v.el[3] = 1.0f;
weston_matrix_transform(&m, &top_left);
weston_matrix_transform(&m, &bottom_right);
if (top_left.f[0] < bottom_right.f[0]) {
rect_output->x = floorf(top_left.f[0]);
rect_output->width = ceilf(bottom_right.f[0] - rect_output->x);
if (top_left.v.el[0] < bottom_right.v.el[0]) {
rect_output->x = floor(top_left.v.el[0]);
rect_output->width = ceil(bottom_right.v.el[0] - rect_output->x);
} else {
rect_output->x = floorf(bottom_right.f[0]);
rect_output->width = ceilf(top_left.f[0] - rect_output->x);
rect_output->x = floor(bottom_right.v.el[0]);
rect_output->width = ceil(top_left.v.el[0] - rect_output->x);
}
if (top_left.f[1] < bottom_right.f[1]) {
rect_output->y = floorf(top_left.f[1]);
rect_output->height = ceilf(bottom_right.f[1] - rect_output->y);
if (top_left.v.el[1] < bottom_right.v.el[1]) {
rect_output->y = floor(top_left.v.el[1]);
rect_output->height = ceil(bottom_right.v.el[1] - rect_output->y);
} else {
rect_output->y = floorf(bottom_right.f[1]);
rect_output->height = ceilf(top_left.f[1] - rect_output->y);
rect_output->y = floor(bottom_right.v.el[1]);
rect_output->height = ceil(top_left.v.el[1] - rect_output->y);
}
ivi_rectangle_intersect(rect_output, boundingbox, rect_output);

View file

@ -1798,14 +1798,14 @@ weston_view_update_transform_disable(struct weston_view *view)
/* Otherwise identity matrix, but with x and y translation. */
view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
view->transform.position.matrix.d[12] = view->geometry.pos_offset.x;
view->transform.position.matrix.d[13] = view->geometry.pos_offset.y;
view->transform.position.matrix.M.col[3].x = view->geometry.pos_offset.x;
view->transform.position.matrix.M.col[3].y = view->geometry.pos_offset.y;
view->transform.matrix = view->transform.position.matrix;
view->transform.inverse = view->transform.position.matrix;
view->transform.inverse.d[12] = -view->geometry.pos_offset.x;
view->transform.inverse.d[13] = -view->geometry.pos_offset.y;
view->transform.inverse.M.col[3].x = -view->geometry.pos_offset.x;
view->transform.inverse.M.col[3].y = -view->geometry.pos_offset.y;
pixman_region32_init_rect(&view->transform.boundingbox,
0, 0,
@ -1850,8 +1850,8 @@ weston_view_update_transform_enable(struct weston_view *view)
/* Otherwise identity matrix, but with x and y translation. */
view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
view->transform.position.matrix.d[12] = view->geometry.pos_offset.x;
view->transform.position.matrix.d[13] = view->geometry.pos_offset.y;
view->transform.position.matrix.M.col[3].x = view->geometry.pos_offset.x;
view->transform.position.matrix.M.col[3].y = view->geometry.pos_offset.y;
weston_matrix_init(matrix);
wl_list_for_each(tform, &view->geometry.transformation_list, link)
@ -1889,8 +1889,8 @@ weston_view_update_transform_enable(struct weston_view *view)
&view->transform.opaque,
&view->geometry.scissor);
pixman_region32_translate(&view->transform.opaque,
matrix->d[12],
matrix->d[13]);
matrix->M.col[3].x,
matrix->M.col[3].y);
}
} else if (view->alpha == 1.0 &&
matrix->type < WESTON_MATRIX_TRANSFORM_ROTATE &&
@ -10751,7 +10751,7 @@ weston_output_finish_frame_from_timer(struct weston_output *output)
}
/** Retrieve the backend type of as described in enum
* weston_compositor_backend.
* weston_compositor_backend.
*
* Note that the backend must be loaded, with weston_compositor_load_backend
*

View file

@ -152,15 +152,15 @@ weston_matrix_to_pixman_transform(pixman_transform_t *pt,
{
/* Pixman supports only 2D transform matrix, but Weston uses 3D, *
* so we're omitting Z coordinate here. */
pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
pt->matrix[0][0] = pixman_double_to_fixed(wm->M.col[0].x);
pt->matrix[0][1] = pixman_double_to_fixed(wm->M.col[1].x);
pt->matrix[0][2] = pixman_double_to_fixed(wm->M.col[3].x);
pt->matrix[1][0] = pixman_double_to_fixed(wm->M.col[0].y);
pt->matrix[1][1] = pixman_double_to_fixed(wm->M.col[1].y);
pt->matrix[1][2] = pixman_double_to_fixed(wm->M.col[3].y);
pt->matrix[2][0] = pixman_double_to_fixed(wm->M.col[0].w);
pt->matrix[2][1] = pixman_double_to_fixed(wm->M.col[1].w);
pt->matrix[2][2] = pixman_double_to_fixed(wm->M.col[3].w);
}
static bool

View file

@ -43,6 +43,8 @@
#include <gbm.h>
#endif
#include <libweston/linalg-4.h>
#include "linux-sync-file.h"
#include "timeline.h"
@ -2343,12 +2345,12 @@ blit_shadow_to_output(struct weston_output *output,
.input_is_premult = true,
},
.projection = {
.d = { /* transpose */
2.0f, 0.0f, 0.0f, 0.0f,
0.0f, go->y_flip * 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -go->y_flip, 0.0f, 1.0f
},
.M = WESTON_MAT4F(
2.0, 0.0, 0.0, -1.0,
0.0, go->y_flip * 2.0, 0.0, -go->y_flip,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
),
.type = WESTON_MATRIX_TRANSFORM_SCALE |
WESTON_MATRIX_TRANSFORM_TRANSLATE,
},
@ -3926,9 +3928,9 @@ gl_renderer_surface_copy_content(struct weston_surface *surface,
glViewport(0, 0, cw, ch);
set_blend_state(gr, false);
if (buffer->buffer_origin == ORIGIN_TOP_LEFT)
ARRAY_COPY(sconf.projection.d, projmat_normal);
ARRAY_COPY(sconf.projection.M.colmaj, projmat_normal);
else
ARRAY_COPY(sconf.projection.d, projmat_yinvert);
ARRAY_COPY(sconf.projection.M.colmaj, projmat_yinvert);
sconf.projection.type = WESTON_MATRIX_TRANSFORM_SCALE |
WESTON_MATRIX_TRANSFORM_TRANSLATE;

View file

@ -663,11 +663,11 @@ gl_shader_load_config(struct gl_renderer *gr,
int i, j;
glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, sconf->projection.d);
1, GL_FALSE, sconf->projection.M.colmaj);
if (shader->surface_to_buffer_uniform != -1)
glUniformMatrix4fv(shader->surface_to_buffer_uniform,
1, GL_FALSE, sconf->surface_to_buffer.d);
1, GL_FALSE, sconf->surface_to_buffer.M.colmaj);
if (shader->color_uniform != -1)
glUniform4fv(shader->color_uniform, 1, sconf->unicolor);

View file

@ -48,66 +48,37 @@
WL_EXPORT void
weston_matrix_init(struct weston_matrix *matrix)
{
static const struct weston_matrix identity = {
.d = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
.type = 0,
};
memcpy(matrix, &identity, sizeof identity);
matrix->M = WESTON_MAT4F_IDENTITY;
matrix->type = 0;
}
/* m <- n * m, that is, m is multiplied on the LEFT. */
WL_EXPORT void
weston_matrix_multiply(struct weston_matrix *m, const struct weston_matrix *n)
{
struct weston_matrix tmp;
const float *row, *column;
int i, j, k;
for (i = 0; i < 4; i++) {
row = m->d + i * 4;
for (j = 0; j < 4; j++) {
tmp.d[4 * i + j] = 0;
column = n->d + j;
for (k = 0; k < 4; k++)
tmp.d[4 * i + j] += row[k] * column[k * 4];
}
}
tmp.type = m->type | n->type;
memcpy(m, &tmp, sizeof tmp);
m->M = weston_m4f_mul_m4f(n->M, m->M);
m->type |= n->type;
}
WL_EXPORT void
weston_matrix_translate(struct weston_matrix *matrix, float x, float y, float z)
{
struct weston_matrix translate = {
.d = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 },
.type = WESTON_MATRIX_TRANSFORM_TRANSLATE,
};
weston_matrix_multiply(matrix, &translate);
matrix->M = weston_m4f_mul_m4f(weston_m4f_translation(x, y, z), matrix->M);
matrix->type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
}
WL_EXPORT void
weston_matrix_scale(struct weston_matrix *matrix, float x, float y,float z)
{
struct weston_matrix scale = {
.d = { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 },
.type = WESTON_MATRIX_TRANSFORM_SCALE,
};
weston_matrix_multiply(matrix, &scale);
matrix->M = weston_m4f_mul_m4f(weston_m4f_scaling(x, y, z), matrix->M);
matrix->type = WESTON_MATRIX_TRANSFORM_SCALE;
}
WL_EXPORT void
weston_matrix_rotate_xy(struct weston_matrix *matrix, float cos, float sin)
{
struct weston_matrix translate = {
.d = { cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
.type = WESTON_MATRIX_TRANSFORM_ROTATE,
};
weston_matrix_multiply(matrix, &translate);
matrix->M = weston_m4f_mul_m4f(weston_m4f_rotation_xy(cos, sin), matrix->M);
matrix->type = WESTON_MATRIX_TRANSFORM_ROTATE;
}
/* v <- m * v */
@ -115,16 +86,7 @@ WL_EXPORT void
weston_matrix_transform(const struct weston_matrix *matrix,
struct weston_vector *v)
{
int i, j;
struct weston_vector t;
for (i = 0; i < 4; i++) {
t.f[i] = 0;
for (j = 0; j < 4; j++)
t.f[i] += v->f[j] * matrix->d[i + j * 4];
}
*v = t;
v->v = weston_m4f_mul_v4f(matrix->M, v->v);
}
WL_EXPORT struct weston_coord
@ -132,17 +94,29 @@ weston_matrix_transform_coord(const struct weston_matrix *matrix,
struct weston_coord c)
{
struct weston_coord out;
struct weston_vector t = { { c.x, c.y, 0.0, 1.0 } };
struct weston_vector t = { .v.el = { c.x, c.y, 0.0, 1.0 } };
weston_matrix_transform(matrix, &t);
assert(fabsf(t.f[3]) > 1e-6);
assert(fabsf(t.v.el[3]) > 1e-6);
out.x = t.f[0] / t.f[3];
out.y = t.f[1] / t.f[3];
out.x = t.v.el[0] / t.v.el[3];
out.y = t.v.el[1] / t.v.el[3];
return out;
}
WL_EXPORT int
weston_matrix_invert(struct weston_matrix *inverse,
const struct weston_matrix *matrix)
{
if (weston_m4f_invert(&inverse->M, matrix->M)) {
inverse->type = matrix->type;
return 0;
}
return -1;
}
static inline void
swap_rows(double *a, double *b)
{
@ -177,118 +151,6 @@ find_pivot(double *column, unsigned k)
return p;
}
/*
* reference: Gene H. Golub and Charles F. van Loan. Matrix computations.
* 3rd ed. The Johns Hopkins University Press. 1996.
* LU decomposition, forward and back substitution: Chapter 3.
*/
static int
matrix_invert(double *A, unsigned *p, const struct weston_matrix *matrix)
{
unsigned i, j, k;
unsigned pivot;
double pv;
for (i = 0; i < 4; ++i)
p[i] = i;
for (i = 16; i--; )
A[i] = matrix->d[i];
/* LU decomposition with partial pivoting */
for (k = 0; k < 4; ++k) {
pivot = find_pivot(&A[k * 4], k);
if (pivot != k) {
swap_unsigned(&p[k], &p[pivot]);
swap_rows(&A[k], &A[pivot]);
}
pv = A[k * 4 + k];
if (fabs(pv) < 1e-9)
return -1; /* zero pivot, not invertible */
for (i = k + 1; i < 4; ++i) {
A[i + k * 4] /= pv;
for (j = k + 1; j < 4; ++j)
A[i + j * 4] -= A[i + k * 4] * A[k + j * 4];
}
}
return 0;
}
static void
inverse_transform(const double *LU, const unsigned *p, float *v)
{
/* Solve A * x = v, when we have P * A = L * U.
* P * A * x = P * v => L * U * x = P * v
* Let U * x = b, then L * b = P * v.
*/
double b[4];
unsigned j;
/* Forward substitution, column version, solves L * b = P * v */
/* The diagonal of L is all ones, and not explicitly stored. */
b[0] = v[p[0]];
b[1] = (double)v[p[1]] - b[0] * LU[1 + 0 * 4];
b[2] = (double)v[p[2]] - b[0] * LU[2 + 0 * 4];
b[3] = (double)v[p[3]] - b[0] * LU[3 + 0 * 4];
b[2] -= b[1] * LU[2 + 1 * 4];
b[3] -= b[1] * LU[3 + 1 * 4];
b[3] -= b[2] * LU[3 + 2 * 4];
/* backward substitution, column version, solves U * y = b */
#if 1
/* hand-unrolled, 25% faster for whole function */
b[3] /= LU[3 + 3 * 4];
b[0] -= b[3] * LU[0 + 3 * 4];
b[1] -= b[3] * LU[1 + 3 * 4];
b[2] -= b[3] * LU[2 + 3 * 4];
b[2] /= LU[2 + 2 * 4];
b[0] -= b[2] * LU[0 + 2 * 4];
b[1] -= b[2] * LU[1 + 2 * 4];
b[1] /= LU[1 + 1 * 4];
b[0] -= b[1] * LU[0 + 1 * 4];
b[0] /= LU[0 + 0 * 4];
#else
for (j = 3; j > 0; --j) {
unsigned k;
b[j] /= LU[j + j * 4];
for (k = 0; k < j; ++k)
b[k] -= b[j] * LU[k + j * 4];
}
b[0] /= LU[0 + 0 * 4];
#endif
/* the result */
for (j = 0; j < 4; ++j)
v[j] = b[j];
}
WL_EXPORT int
weston_matrix_invert(struct weston_matrix *inverse,
const struct weston_matrix *matrix)
{
double LU[16]; /* column-major */
unsigned perm[4]; /* permutation */
unsigned c;
if (matrix_invert(LU, perm, matrix) < 0)
return -1;
weston_matrix_init(inverse);
for (c = 0; c < 4; ++c)
inverse_transform(LU, perm, &inverse->d[c * 4]);
inverse->type = matrix->type;
return 0;
}
static bool
m4f_LU_decompose(double *restrict LU, unsigned *restrict p, struct weston_mat4f M)
{
@ -521,7 +383,7 @@ get_el(const struct weston_matrix *matrix, int row, int col)
assert(row >= 0 && row <= 3);
assert(col >= 0 && col <= 3);
return matrix->d[col * 4 + row];
return matrix->M.col[col].el[row];
}
static bool

View file

@ -366,7 +366,7 @@ weston_matrix_from_lcmsMAT3(struct weston_matrix *w, const struct lcmsMAT3 *m)
for (c = 0; c < 3; c++) {
for (r = 0; r < 3; r++)
w->d[c * 4 + r] = m->v[c].n[r];
w->M.col[c].el[r] = m->v[c].n[r];
}
}
@ -377,7 +377,7 @@ lcmsMAT3_from_weston_matrix(struct lcmsMAT3 *m, const struct weston_matrix *w)
for (c = 0; c < 3; c++) {
for (r = 0; r < 3; r++)
m->v[c].n[r] = w->d[c * 4 + r];
m->v[c].n[r] = w->M.col[c].el[r];
}
}

View file

@ -32,6 +32,7 @@
#include <stdlib.h>
#include <libweston/matrix.h>
#include <libweston/linalg-4.h>
#include "shared/helpers.h"
#include "color_util.h"
#include "lcms_util.h"
@ -281,11 +282,9 @@ roundtrip_verification(cmsPipeline *DToB, cmsPipeline *BToD, float tolerance)
test_assert_f32_lt(stat.two_norm.max, tolerance);
}
static const struct weston_vector ZEROS = {
.f = { 0.0, 0.0, 0.0, 1.0 }
};
static const struct weston_vector ZEROS = { .v = WESTON_VEC4F_ZERO };
static const struct weston_vector PCS_BLACK = {
.f = {
.v.el = {
cmsPERCEPTUAL_BLACK_X,
cmsPERCEPTUAL_BLACK_Y,
cmsPERCEPTUAL_BLACK_Z,
@ -310,19 +309,19 @@ static cmsInt32Number
transform_sampler(const float src[], float dst[], void *cargo)
{
const struct transform_sampler_context *tsc = cargo;
struct weston_vector stmp = { .f = { src[0], src[1], src[2], 1.0 } };
struct weston_vector dtmp = { .f = { 0.0, 0.0, 0.0, 1.0 } };
struct weston_vector stmp = { .v.el = { src[0], src[1], src[2], 1.0 } };
struct weston_vector dtmp = { .v.el = { 0.0, 0.0, 0.0, 1.0 } };
if (tsc->dir == BPC_DIR_BTOD)
weston_matrix_transform(&tsc->bpc, &stmp);
cmsDoTransform(tsc->t, stmp.f, dtmp.f, 1);
cmsDoTransform(tsc->t, stmp.v.el, dtmp.v.el, 1);
if (tsc->dir == BPC_DIR_DTOB)
weston_matrix_transform(&tsc->bpc, &dtmp);
for (int i = 0; i < 3; i++)
dst[i] = dtmp.f[i];
dst[i] = dtmp.v.el[i];
return 1; /* Success. */
}
@ -346,17 +345,17 @@ ComputeBlackPointCompensation(struct weston_matrix *m,
// a = (bpout - D50) / (bpin - D50)
// b = - D50* (bpout - bpin) / (bpin - D50)
tx = src_bp->f[0] - cmsD50_XYZ()->X;
ty = src_bp->f[1] - cmsD50_XYZ()->Y;
tz = src_bp->f[2] - cmsD50_XYZ()->Z;
tx = src_bp->v.x - cmsD50_XYZ()->X;
ty = src_bp->v.y - cmsD50_XYZ()->Y;
tz = src_bp->v.z - cmsD50_XYZ()->Z;
ax = (dst_bp->f[0] - cmsD50_XYZ()->X) / tx;
ay = (dst_bp->f[1] - cmsD50_XYZ()->Y) / ty;
az = (dst_bp->f[2] - cmsD50_XYZ()->Z) / tz;
ax = (dst_bp->v.x - cmsD50_XYZ()->X) / tx;
ay = (dst_bp->v.y - cmsD50_XYZ()->Y) / ty;
az = (dst_bp->v.z - cmsD50_XYZ()->Z) / tz;
bx = - cmsD50_XYZ()-> X * (dst_bp->f[0] - src_bp->f[0]) / tx;
by = - cmsD50_XYZ()-> Y * (dst_bp->f[1] - src_bp->f[1]) / ty;
bz = - cmsD50_XYZ()-> Z * (dst_bp->f[2] - src_bp->f[2]) / tz;
bx = - cmsD50_XYZ()-> X * (dst_bp->v.x - src_bp->v.x) / tx;
by = - cmsD50_XYZ()-> Y * (dst_bp->v.y - src_bp->v.y) / ty;
bz = - cmsD50_XYZ()-> Z * (dst_bp->v.z - src_bp->v.z) / tz;
/*
* [ax, 0, 0, bx ]

View file

@ -27,51 +27,16 @@
#include <math.h>
#include <libweston/matrix.h>
#include <libweston/linalg-4.h>
#include "weston-test-client-helper.h"
#include "weston-test-assert.h"
/*
* A helper to lay out a matrix in the natural writing order in code
* instead of needing to transpose in your mind every time you read it.
* The matrix is laid out as written:
* a11 a12 a13 a14
* a21 a22 a23 a24
* a31 a32 a33 a34
* a41 a42 a43 a44
* where the first digit is row and the second digit is column.
*
* The type field is set to the most pessimistic case possible so that if
* weston_matrix_invert() ever gets special-case code paths, we don't take
* them.
*/
#define MAT(a11, a12, a13, a14, \
a21, a22, a23, a24, \
a31, a32, a33, a34, \
a41, a42, a43, a44) ((struct weston_matrix) \
{ \
.d[0] = a11, .d[4] = a12, .d[ 8] = a13, .d[12] = a14, \
.d[1] = a21, .d[5] = a22, .d[ 9] = a23, .d[13] = a24, \
.d[2] = a31, .d[6] = a32, .d[10] = a33, .d[14] = a34, \
.d[3] = a41, .d[7] = a42, .d[11] = a43, .d[15] = a44, \
.type = WESTON_MATRIX_TRANSFORM_TRANSLATE | \
WESTON_MATRIX_TRANSFORM_SCALE | \
WESTON_MATRIX_TRANSFORM_ROTATE | \
WESTON_MATRIX_TRANSFORM_OTHER, \
})
static const struct weston_matrix IDENTITY =
MAT(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
static const struct weston_matrix IDENTITY = { .M = WESTON_MAT4F_IDENTITY };
static void
subtract_matrix(struct weston_matrix *from, const struct weston_matrix *what)
{
unsigned i;
for (i = 0; i < ARRAY_LENGTH(from->d); i++)
from->d[i] -= what->d[i];
from->M = weston_m4f_sub_m4f(from->M, what->M);
}
static void
@ -81,7 +46,7 @@ print_matrix(const struct weston_matrix *m)
for (r = 0; r < 4; ++r) {
for (c = 0; c < 4; ++c)
testlog(" %14.6e", m->d[r + c * 4]);
testlog(" %14.6e", m->M.col[c].el[r]);
testlog("\n");
}
}
@ -93,21 +58,7 @@ print_matrix(const struct weston_matrix *m)
static double
matrix_inf_norm(const struct weston_matrix *mat)
{
unsigned row;
double infnorm = -1.0;
for (row = 0; row < 4; row++) {
unsigned col;
double sum = 0.0;
for (col = 0; col < 4; col++)
sum += fabs(mat->d[col * 4 + row]);
if (infnorm < sum)
infnorm = sum;
}
return infnorm;
return weston_m4f_inf_norm(mat->M);
}
struct test_matrix {
@ -128,7 +79,8 @@ struct test_matrix {
static const struct test_matrix matrices[] = {
/* A very trivial case. */
{
.M = MAT(1, 0, 0, 0,
.M.M = WESTON_MAT4F(
1, 0, 0, 0,
0, 2, 0, 0,
0, 0, 3, 0,
0, 0, 0, 4),
@ -179,7 +131,8 @@ static const struct test_matrix matrices[] = {
* https://gitlab.freedesktop.org/pq/fourbyfour
*/
{
.M = MAT(1, 0, 0, 1980,
.M.M = WESTON_MAT4F(
1, 0, 0, 1980,
0, 1, 0, 1080,
0, 0, 1, 0,
0, 0, 0, 1),
@ -199,7 +152,8 @@ static const struct test_matrix matrices[] = {
/* cond = 1e3 */
{
.M = MAT(-4.12798022231678357619e-02, -7.93301899046665176529e-02, 2.49367040174418935772e-01, -2.22400462135059429070e-01,
.M.M = WESTON_MAT4F(
-4.12798022231678357619e-02, -7.93301899046665176529e-02, 2.49367040174418935772e-01, -2.22400462135059429070e-01,
2.02416121867255743849e-01, -2.25754422240346010187e-02, -2.91283152417864787953e-01, 1.49354988316431153139e-01,
6.18473094065821293874e-01, 5.81511312950217934548e-02, -1.18363610818063924590e+00, 8.00087538947595322547e-01,
1.25723127083294305972e-01, 7.72723720984487272290e-02, -3.76023220287807879991e-01, 2.82473279931768073148e-01),
@ -208,7 +162,8 @@ static const struct test_matrix matrices[] = {
/* cond = 1e3, abs det = 15 */
{
.M = MAT(6.84154939885726509630e+00, -6.87241565273813304060e+00, -2.56772939909334070308e+01, -2.52185055099662420730e+01,
.M.M = WESTON_MAT4F(
6.84154939885726509630e+00, -6.87241565273813304060e+00, -2.56772939909334070308e+01, -2.52185055099662420730e+01,
2.04511561406330022450e+00, -3.67551043874248994925e+00, -1.96421641406619129633e+00, -2.40644091603848320204e+00,
5.83631095663641819016e+00, -9.31051765621826277197e+00, -1.80402129629135217215e+01, -1.78475057662460052654e+01,
-9.88588496379959025262e+00, 1.49790516545410774540e+01, 2.64975800675967363418e+01, 2.65795891678410747261e+01),
@ -217,7 +172,8 @@ static const struct test_matrix matrices[] = {
/* cond = 700, abs det = 1e-6, invertible regardless of det */
{
.M = MAT(1.32125189257677579449e-03, -1.67411409720826992453e-01, 1.07940907587735196449e-01, -1.22163309792902186057e-01,
.M.M = WESTON_MAT4F(
1.32125189257677579449e-03, -1.67411409720826992453e-01, 1.07940907587735196449e-01, -1.22163309792902186057e-01,
-5.42113793774764013422e-02, 5.30455105336593901733e-01, -2.59607412684229155175e-01, 4.36480803188117993940e-01,
2.88175168292948129939e-03, -1.85262537685181277736e-01, 1.46265858042118279680e-01, -9.41398969709369287662e-02,
-2.88900393087768159184e-03, 1.57987202530630227448e-01, -1.20781192010860280450e-01, 8.95194304475115387731e-02),
@ -226,7 +182,8 @@ static const struct test_matrix matrices[] = {
/* cond = 1e6, this is a little more challenging */
{
.M = MAT(-4.41851445093878913983e-01, -5.16386185043831491548e-01, 2.86186055948129847160e-01, -5.79440137716940473211e-01,
.M.M = WESTON_MAT4F(
-4.41851445093878913983e-01, -5.16386185043831491548e-01, 2.86186055948129847160e-01, -5.79440137716940473211e-01,
2.49798696238173301154e-01, 2.84965614532234345901e-01, -1.65729639683955931595e-01, 3.12568045963485974248e-01,
3.15253213984537428161e-01, 3.71270066781250074328e-01, -2.02675623845341434937e-01, 4.19969870491003371971e-01,
5.60818677658178832424e-01, 6.45373659426444201692e-01, -3.68902466471524526082e-01, 7.13785795079988516498e-01),
@ -235,7 +192,8 @@ static const struct test_matrix matrices[] = {
/* cond = 15, abs det = 1e-9, should be well invertible */
{
.M = MAT(-5.37536200142514660589e-05, 7.92552373388843642288e-03, -3.90554524958281433500e-03, 2.68892064500873568395e-03,
.M.M = WESTON_MAT4F(
-5.37536200142514660589e-05, 7.92552373388843642288e-03, -3.90554524958281433500e-03, 2.68892064500873568395e-03,
-9.72329428437283989350e-03, 8.32075145342783470404e-03, 6.52648485926096092596e-03, 1.06707947887298994737e-03,
1.04453728969657322345e-02, -1.03627268579679666927e-02, -3.56835980207569763989e-03, -3.95935925157862422114e-03,
5.37160838929722633805e-03, 6.13466744624343262009e-05, -1.23695935407398946090e-04, 8.21231194921675112380e-04),

View file

@ -34,6 +34,7 @@
#include <wayland-client.h>
#include "libweston-internal.h"
#include "libweston/matrix.h"
#include <libweston/linalg-4.h>
#include "weston-test-client-helper.h"
#include "weston-test-assert.h"
@ -382,40 +383,40 @@ simple_transform_vector(struct weston_output *output, struct weston_vector in)
switch (output->transform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
out.f[0] = (-output->pos.c.x + in.f[0]) * scale;
out.f[1] = (-output->pos.c.y + in.f[1]) * scale;
out.v.el[0] = (-output->pos.c.x + in.v.el[0]) * scale;
out.v.el[1] = (-output->pos.c.y + in.v.el[1]) * scale;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED:
out.f[0] = (output->pos.c.x + output->width - in.f[0]) * scale;
out.f[1] = (-output->pos.c.y + in.f[1]) * scale;
out.v.el[0] = (output->pos.c.x + output->width - in.v.el[0]) * scale;
out.v.el[1] = (-output->pos.c.y + in.v.el[1]) * scale;
break;
case WL_OUTPUT_TRANSFORM_90:
out.f[0] = (-output->pos.c.y + in.f[1]) * scale;
out.f[1] = (output->pos.c.x + output->width - in.f[0]) * scale;
out.v.el[0] = (-output->pos.c.y + in.v.el[1]) * scale;
out.v.el[1] = (output->pos.c.x + output->width - in.v.el[0]) * scale;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
out.f[0] = (-output->pos.c.y + in.f[1]) * scale;
out.f[1] = (-output->pos.c.x + in.f[0]) * scale;
out.v.el[0] = (-output->pos.c.y + in.v.el[1]) * scale;
out.v.el[1] = (-output->pos.c.x + in.v.el[0]) * scale;
break;
case WL_OUTPUT_TRANSFORM_180:
out.f[0] = (output->pos.c.x + output->width - in.f[0]) * scale;
out.f[1] = (output->pos.c.y + output->height - in.f[1]) * scale;
out.v.el[0] = (output->pos.c.x + output->width - in.v.el[0]) * scale;
out.v.el[1] = (output->pos.c.y + output->height - in.v.el[1]) * scale;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
out.f[0] = (-output->pos.c.x + in.f[0]) * scale;
out.f[1] = (output->pos.c.y + output->height - in.f[1]) * scale;
out.v.el[0] = (-output->pos.c.x + in.v.el[0]) * scale;
out.v.el[1] = (output->pos.c.y + output->height - in.v.el[1]) * scale;
break;
case WL_OUTPUT_TRANSFORM_270:
out.f[0] = (output->pos.c.y + output->height - in.f[1]) * scale;
out.f[1] = (-output->pos.c.x + in.f[0]) * scale;
out.v.el[0] = (output->pos.c.y + output->height - in.v.el[1]) * scale;
out.v.el[1] = (-output->pos.c.x + in.v.el[0]) * scale;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
out.f[0] = (output->pos.c.y + output->height - in.f[1]) * scale;
out.f[1] = (output->pos.c.x + output->width - in.f[0]) * scale;
out.v.el[0] = (output->pos.c.y + output->height - in.v.el[1]) * scale;
out.v.el[1] = (output->pos.c.x + output->width - in.v.el[0]) * scale;
break;
}
out.f[2] = 0;
out.f[3] = 1;
out.v.el[2] = 0;
out.v.el[3] = 1;
return out;
}
@ -426,7 +427,7 @@ output_test_all_transforms(struct weston_output *output,
{
int i;
int transform;
struct weston_vector t = { { 7.0, 13.0, 0.0, 1.0 } };
struct weston_vector t = { .v = WESTON_VEC4F(7.0, 13.0, 0.0, 1.0) };
struct weston_vector v, sv;
for (transform = WL_OUTPUT_TRANSFORM_NORMAL;
@ -443,7 +444,7 @@ output_test_all_transforms(struct weston_output *output,
weston_matrix_transform(&output->matrix, &v);
sv = simple_transform_vector(output, t);
for (i = 0; i < 4; i++)
test_assert_f32_eq (sv.f[i], v.f[i]);
test_assert_f32_eq(sv.v.el[i], v.v.el[i]);
}
}