[PATCH i-g-t v3 4/5] tests/kms_atomic: Add solid fill plane subtest
Jessica Zhang
quic_jesszhan at quicinc.com
Fri Mar 1 20:47:33 UTC 2024
Add a basic test for solid fill planes.
This test will first commit a single-color framebuffer plane then
a solid fill plane with the same contents. It then validates the solid
fill plane by comparing the resulting CRC with the CRC of the reference
framebuffer commit.
Signed-off-by: Jessica Zhang <quic_jesszhan at quicinc.com>
---
tests/kms_atomic.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 191 insertions(+), 18 deletions(-)
diff --git a/tests/kms_atomic.c b/tests/kms_atomic.c
old mode 100644
new mode 100755
index 2b6e9a8f0383..0598c5d71a85
--- a/tests/kms_atomic.c
+++ b/tests/kms_atomic.c
@@ -43,6 +43,7 @@
#include <stdint.h>
#include <string.h>
#include <errno.h>
+#include <math.h>
#include <xf86drmMode.h>
#include <cairo.h>
#include "drm.h"
@@ -101,6 +102,15 @@
* @params-fence: fence parameters
*/
+/**
+ * SUBTEST: plane-%s-solid-fill
+ * Description: Test atomic modesetting on %arg[1] using solid fill property.
+ *
+ * arg[1]:
+ *
+ * @primary: Primary plane
+ */
+
#ifndef DRM_CAP_CURSOR_WIDTH
#define DRM_CAP_CURSOR_WIDTH 0x8
#endif
@@ -122,18 +132,45 @@ typedef struct {
igt_fb_t fb;
} data_t;
+static struct {
+ uint32_t r, g, b;
+} colors[8] = {
+ /* Basic Colors */
+ { .r = 0x00000000, .g = 0x00000000, .b = 0x00000000 },
+ { .r = 0xffffffff, .g = 0x00000000, .b = 0x00000000 },
+ { .r = 0x00000000, .g = 0xffffffff, .b = 0x00000000 },
+ { .r = 0x00000000, .g = 0x00000000, .b = 0xffffffff },
+ { .r = 0xffffffff, .g = 0xffffffff, .b = 0xffffffff },
+
+ /* Mid-grays */
+ { .r = 0x40000000, .g = 0x40000000, .b = 0x40000000 },
+ { .r = 0x80000000, .g = 0x80000000, .b = 0x80000000 },
+ { .r = 0xcccccccc, .g = 0xcccccccc, .b = 0xcccccccc },
+};
+
enum kms_atomic_check_relax {
ATOMIC_RELAX_NONE = 0,
CRTC_RELAX_MODE = (1 << 0),
PLANE_RELAX_FB = (1 << 1)
};
-static inline int damage_rect_width(struct drm_mode_rect *r)
+/*
+ * Fixed point uint to floating point conversion based on
+ * Vulkan's UNORM conversion:
+ *
+ * https://registry.khronos.org/vulkan/specs/1.3/html/chap3.html#fundamentals-fixedconv
+ */
+static inline double unorm_to_float(uint32_t x)
+{
+ return x / (pow(2, 32) - 1);
+}
+
+static inline int rect_width(struct drm_mode_rect *r)
{
return r->x2 - r->x1;
}
-static inline int damage_rect_height(struct drm_mode_rect *r)
+static inline int rect_height(struct drm_mode_rect *r)
{
return r->y2 - r->y1;
}
@@ -1156,8 +1193,8 @@ static void atomic_plane_damage(data_t *data)
cr_1 = igt_get_cairo_ctx(data->drm_fd, &fb_1);
igt_paint_color(cr_1, damage[0].x1, damage[0].y1,
- damage_rect_width(&damage[0]),
- damage_rect_height(&damage[0]), 1.0, 0, 0);
+ rect_width(&damage[0]),
+ rect_height(&damage[0]), 1.0, 0, 0);
igt_put_cairo_ctx(cr_1);
igt_plane_set_fb(data->primary, &fb_1);
@@ -1183,8 +1220,8 @@ static void atomic_plane_damage(data_t *data)
cairo_set_source_surface(cr_2, fb_1.cairo_surface, 0, 0);
cairo_paint(cr_2);
igt_paint_color(cr_2, damage[0].x1, damage[0].y1,
- damage_rect_width(&damage[0]),
- damage_rect_height(&damage[0]), 0, 1.0, 0);
+ rect_width(&damage[0]),
+ rect_height(&damage[0]), 0, 1.0, 0);
igt_put_cairo_ctx(cr_1);
igt_put_cairo_ctx(cr_2);
igt_plane_set_fb(data->primary, &fb_2);
@@ -1213,8 +1250,8 @@ static void atomic_plane_damage(data_t *data)
cairo_set_source_surface(cr_1, fb_2.cairo_surface, 0, 0);
cairo_paint(cr_1);
igt_paint_color(cr_1, damage[0].x1, damage[0].y1,
- damage_rect_width(&damage[0]),
- damage_rect_height(&damage[0]), 0, 1.0, 0);
+ rect_width(&damage[0]),
+ rect_height(&damage[0]), 0, 1.0, 0);
igt_put_cairo_ctx(cr_2);
igt_put_cairo_ctx(cr_1);
igt_plane_set_fb(data->primary, &fb_1);
@@ -1238,8 +1275,8 @@ static void atomic_plane_damage(data_t *data)
cr_1 = igt_get_cairo_ctx(data->drm_fd, &fb_1);
igt_paint_color(cr_1, damage[0].x1, damage[0].y1,
- damage_rect_width(&damage[0]),
- damage_rect_height(&damage[0]), 1.0, 1.0, 0);
+ rect_width(&damage[0]),
+ rect_height(&damage[0]), 1.0, 1.0, 0);
igt_put_cairo_ctx(cr_1);
igt_plane_set_fb(data->primary, &fb_1);
igt_plane_set_size(data->primary, data->fb.width, data->fb.height);
@@ -1266,11 +1303,11 @@ static void atomic_plane_damage(data_t *data)
cr_1 = igt_get_cairo_ctx(data->drm_fd, &fb_1);
igt_paint_color(cr_1, damage[0].x1, damage[0].y1,
- damage_rect_width(&damage[0]),
- damage_rect_height(&damage[0]), 0, 1.0, 1.0);
+ rect_width(&damage[0]),
+ rect_height(&damage[0]), 0, 1.0, 1.0);
igt_paint_color(cr_1, damage[1].x1, damage[1].y1,
- damage_rect_width(&damage[1]),
- damage_rect_height(&damage[1]), 0, 1.0, 0);
+ rect_width(&damage[1]),
+ rect_height(&damage[1]), 0, 1.0, 0);
igt_put_cairo_ctx(cr_1);
igt_plane_set_fb(data->primary, &fb_1);
igt_plane_set_size(data->primary, data->fb.width, data->fb.height);
@@ -1299,11 +1336,11 @@ static void atomic_plane_damage(data_t *data)
cr_1 = igt_get_cairo_ctx(data->drm_fd, &fb_1);
igt_paint_color(cr_1, damage[0].x1, damage[0].y1,
- damage_rect_width(&damage[0]),
- damage_rect_height(&damage[0]), 1.0, 0, 0);
+ rect_width(&damage[0]),
+ rect_height(&damage[0]), 1.0, 0, 0);
igt_paint_color(cr_1, damage[1].x1, damage[1].y1,
- damage_rect_width(&damage[1]),
- damage_rect_height(&damage[1]), 1.0, 1.0, 1.0);
+ rect_width(&damage[1]),
+ rect_height(&damage[1]), 1.0, 1.0, 1.0);
igt_put_cairo_ctx(cr_1);
igt_plane_set_fb(data->primary, &fb_1);
igt_plane_set_size(data->primary, data->fb.width, data->fb.height);
@@ -1322,6 +1359,128 @@ static void atomic_plane_damage(data_t *data)
igt_remove_fb(data->drm_fd, &fb_2);
}
+static uint32_t to_argb(uint32_t r, uint32_t g, uint32_t b)
+{
+ uint32_t color = 0xff000000;
+ uint8_t temp_r = r >> 24;
+ uint8_t temp_g = g >> 24;
+ uint8_t temp_b = b >> 24;
+
+ color |= temp_r << 16;
+ color |= temp_g << 8;
+ color |= temp_b;
+
+ return color;
+}
+
+static void test_solid_fill_plane(data_t *data, igt_output_t *output, igt_plane_t *plane)
+{
+ drmModeModeInfo *mode = igt_output_get_mode(output);
+ struct drm_mode_rect rect = { 0 };
+ struct igt_fb ref_fb;
+ igt_pipe_crc_t *pipe_crc;
+ igt_crc_t ref_crc, new_crc;
+ enum pipe pipe = data->pipe->pipe;
+ int height, width, i;
+ int ret;
+
+ igt_require(igt_plane_has_prop(plane, IGT_PLANE_SOLID_FILL));
+ igt_require(igt_plane_has_prop(plane, IGT_PLANE_PIXEL_SOURCE));
+
+ rect.x1 = 0;
+ rect.x2 = mode->hdisplay;
+ rect.y1 = 0;
+ rect.y2 = mode->vdisplay;
+
+ width = rect_width(&rect);
+ height = rect_height(&rect);
+
+ igt_plane_set_position(plane, rect.x1, rect.y1);
+ pipe_crc = igt_pipe_crc_new(data->drm_fd, pipe,
+ IGT_PIPE_CRC_SOURCE_AUTO);
+
+
+ for (i = 0; i < ARRAY_SIZE(colors); i++) {
+ uint32_t r = colors[i].r;
+ uint32_t g = colors[i].g;
+ uint32_t b = colors[i].b;
+ cairo_format_t fmt;
+ uint32_t *fb_data;
+
+ struct drm_mode_create_blob c;
+ struct drm_mode_destroy_blob d;
+ struct drm_mode_solid_fill blob_data = {
+ .r = r,
+ .g = g,
+ .b = b,
+ .pad = 0x0,
+ };
+
+ c.data = (uintptr_t) &blob_data;
+ c.length = sizeof(blob_data);
+
+ igt_debug("Testing color r: 0x%x (%f), g: 0x%x (%f), b: 0x%x (%f)\n",
+ r, unorm_to_float(r),
+ g, unorm_to_float(g),
+ b, unorm_to_float(b));
+
+ /* get reference CRC */
+ igt_create_color_fb(data->drm_fd, width, height,
+ DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_LINEAR,
+ unorm_to_float(r),
+ unorm_to_float(g),
+ unorm_to_float(b),
+ &ref_fb);
+ igt_plane_set_fb(plane, &ref_fb);
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+ igt_get_cairo_ctx(ref_fb.fd, &ref_fb);
+ fb_data = (void *)cairo_image_surface_get_data(ref_fb.cairo_surface);
+ fmt = cairo_image_surface_get_format(ref_fb.cairo_surface);
+
+ /*
+ * Check to make sure Cairo float->u8 conversion matches
+ * expected ARGB8888 value
+ */
+ if (fmt == CAIRO_FORMAT_ARGB32 && fb_data[0] != to_argb(r, g, b)) {
+ igt_warn("Resulting framebuffer data doesn't match color!\n");
+ continue;
+ }
+
+ igt_pipe_crc_start(pipe_crc);
+ igt_pipe_crc_get_current(data->drm_fd, pipe_crc, &ref_crc);
+
+ ret = drmIoctl(data->display.drm_fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &c);
+ igt_assert(ret == 0);
+
+ /* test solid fill plane */
+ igt_plane_set_solid_fill(plane, &rect, c.blob_id);
+ igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_SOURCE, "SOLID_FILL");
+
+ igt_display_commit_atomic(&data->display,
+ DRM_MODE_ATOMIC_ALLOW_MODESET,
+ NULL);
+
+ igt_pipe_crc_get_current(data->drm_fd, pipe_crc, &new_crc);
+
+ igt_assert_crc_equal(&ref_crc, &new_crc);
+
+ /* Switch back to FB pixel source */
+ igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_SOURCE, "FB");
+
+ d.blob_id = c.blob_id;
+ ret = drmIoctl(data->drm_fd, DRM_IOCTL_MODE_DESTROYPROPBLOB, &d);
+ igt_assert(ret == 0);
+ }
+
+ igt_plane_set_prop_value(plane, IGT_PLANE_SOLID_FILL, 0);
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+ igt_pipe_crc_stop(pipe_crc);
+ igt_pipe_crc_free(pipe_crc);
+ igt_remove_fb(data->drm_fd, &ref_fb);
+}
+
static void atomic_setup(data_t *data, enum pipe pipe, igt_output_t *output)
{
drmModeModeInfo *mode;
@@ -1634,6 +1793,20 @@ igt_main_args("e", NULL, help_str, opt_handler, NULL)
}
}
+ igt_describe("Test case for solid fill primary planes");
+ igt_subtest_with_dynamic("plane-primary-solid-fill") {
+ for_each_pipe_with_single_output(&data.display, pipe, output) {
+ if (!pipe_output_combo_valid(&data.display, pipe, output))
+ continue;
+
+ igt_dynamic_f("pipe-%s-%s", kmstest_pipe_name(pipe), igt_output_name(output)) {
+ atomic_setup(&data, pipe, output);
+ test_solid_fill_plane(&data, output, data.primary);
+ atomic_clear(&data, pipe, output);
+ }
+ }
+ }
+
igt_fixture {
igt_display_fini(&data.display);
drm_close_driver(data.drm_fd);
--
2.43.2
More information about the igt-dev
mailing list