320 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Test cases for the drm_plane_helper functions4 *5 * Copyright (c) 2022 Maíra Canal <mairacanal@riseup.net>6 */7 8#include <kunit/test.h>9 10#include <drm/drm_atomic_helper.h>11#include <drm/drm_framebuffer.h>12#include <drm/drm_modes.h>13#include <drm/drm_rect.h>14 15static const struct drm_crtc_state crtc_state = {16 .crtc = ZERO_SIZE_PTR,17 .enable = true,18 .active = true,19 .mode = {20 DRM_MODE("1024x768", 0, 65000, 1024, 1048,21 1184, 1344, 0, 768, 771, 777, 806, 0,22 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)23 },24};25 26struct drm_check_plane_state_test {27 const char *name;28 const char *msg;29 struct {30 unsigned int x;31 unsigned int y;32 unsigned int w;33 unsigned int h;34 } src, src_expected;35 struct {36 int x;37 int y;38 unsigned int w;39 unsigned int h;40 } crtc, crtc_expected;41 unsigned int rotation;42 int min_scale;43 int max_scale;44 bool can_position;45};46 47static int drm_plane_helper_init(struct kunit *test)48{49 const struct drm_check_plane_state_test *params = test->param_value;50 struct drm_plane *plane;51 struct drm_framebuffer *fb;52 struct drm_plane_state *mock;53 54 plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);55 KUNIT_ASSERT_NOT_NULL(test, plane);56 57 fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);58 KUNIT_ASSERT_NOT_NULL(test, fb);59 fb->width = 2048;60 fb->height = 2048;61 62 mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);63 KUNIT_ASSERT_NOT_NULL(test, mock);64 mock->plane = plane;65 mock->crtc = ZERO_SIZE_PTR;66 mock->fb = fb;67 mock->rotation = params->rotation;68 mock->src_x = params->src.x;69 mock->src_y = params->src.y;70 mock->src_w = params->src.w;71 mock->src_h = params->src.h;72 mock->crtc_x = params->crtc.x;73 mock->crtc_y = params->crtc.y;74 mock->crtc_w = params->crtc.w;75 mock->crtc_h = params->crtc.h;76 77 test->priv = mock;78 79 return 0;80}81 82static void check_src_eq(struct kunit *test, struct drm_plane_state *plane_state,83 unsigned int src_x, unsigned int src_y,84 unsigned int src_w, unsigned int src_h)85{86 struct drm_rect expected = DRM_RECT_INIT(src_x, src_y, src_w, src_h);87 88 KUNIT_ASSERT_GE_MSG(test, plane_state->src.x1, 0,89 "src x coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,90 plane_state->src.x1, DRM_RECT_FP_ARG(&plane_state->src));91 92 KUNIT_ASSERT_GE_MSG(test, plane_state->src.y1, 0,93 "src y coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,94 plane_state->src.y1, DRM_RECT_FP_ARG(&plane_state->src));95 96 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->src, &expected),97 "dst: " DRM_RECT_FP_FMT ", expected: " DRM_RECT_FP_FMT,98 DRM_RECT_FP_ARG(&plane_state->src), DRM_RECT_FP_ARG(&expected));99}100 101static void check_crtc_eq(struct kunit *test, struct drm_plane_state *plane_state,102 int crtc_x, int crtc_y,103 unsigned int crtc_w, unsigned int crtc_h)104{105 struct drm_rect expected = DRM_RECT_INIT(crtc_x, crtc_y, crtc_w, crtc_h);106 107 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->dst, &expected),108 "dst: " DRM_RECT_FMT ", expected: " DRM_RECT_FMT,109 DRM_RECT_ARG(&plane_state->dst), DRM_RECT_ARG(&expected));110}111 112static void drm_test_check_plane_state(struct kunit *test)113{114 const struct drm_check_plane_state_test *params = test->param_value;115 struct drm_plane_state *plane_state = test->priv;116 117 KUNIT_ASSERT_EQ_MSG(test,118 drm_atomic_helper_check_plane_state(plane_state, &crtc_state,119 params->min_scale,120 params->max_scale,121 params->can_position, false),122 0, params->msg);123 KUNIT_EXPECT_TRUE(test, plane_state->visible);124 check_src_eq(test, plane_state, params->src_expected.x, params->src_expected.y,125 params->src_expected.w, params->src_expected.h);126 check_crtc_eq(test, plane_state, params->crtc_expected.x, params->crtc_expected.y,127 params->crtc_expected.w, params->crtc_expected.h);128}129 130static void drm_check_plane_state_desc(const struct drm_check_plane_state_test *t,131 char *desc)132{133 sprintf(desc, "%s", t->name);134}135 136static const struct drm_check_plane_state_test drm_check_plane_state_tests[] = {137 {138 .name = "clipping_simple",139 .msg = "Simple clipping check should pass",140 .src = { 0, 0,141 2048 << 16,142 2048 << 16 },143 .crtc = { 0, 0, 2048, 2048 },144 .rotation = DRM_MODE_ROTATE_0,145 .min_scale = DRM_PLANE_NO_SCALING,146 .max_scale = DRM_PLANE_NO_SCALING,147 .can_position = false,148 .src_expected = { 0, 0, 1024 << 16, 768 << 16 },149 .crtc_expected = { 0, 0, 1024, 768 },150 },151 {152 .name = "clipping_rotate_reflect",153 .msg = "Rotated clipping check should pass",154 .src = { 0, 0,155 2048 << 16,156 2048 << 16 },157 .crtc = { 0, 0, 2048, 2048 },158 .rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X,159 .min_scale = DRM_PLANE_NO_SCALING,160 .max_scale = DRM_PLANE_NO_SCALING,161 .can_position = false,162 .src_expected = { 0, 0, 768 << 16, 1024 << 16 },163 .crtc_expected = { 0, 0, 1024, 768 },164 },165 {166 .name = "positioning_simple",167 .msg = "Simple positioning should work",168 .src = { 0, 0, 1023 << 16, 767 << 16 },169 .crtc = { 0, 0, 1023, 767 },170 .rotation = DRM_MODE_ROTATE_0,171 .min_scale = DRM_PLANE_NO_SCALING,172 .max_scale = DRM_PLANE_NO_SCALING,173 .can_position = true,174 .src_expected = { 0, 0, 1023 << 16, 767 << 16 },175 .crtc_expected = { 0, 0, 1023, 767 },176 },177 {178 .name = "upscaling",179 .msg = "Upscaling exactly 2x should work",180 .src = { 0, 0, 512 << 16, 384 << 16 },181 .crtc = { 0, 0, 1024, 768 },182 .rotation = DRM_MODE_ROTATE_0,183 .min_scale = 0x8000,184 .max_scale = DRM_PLANE_NO_SCALING,185 .can_position = false,186 .src_expected = { 0, 0, 512 << 16, 384 << 16 },187 .crtc_expected = { 0, 0, 1024, 768 },188 },189 {190 .name = "downscaling",191 .msg = "Should succeed with exact scaling limit",192 .src = { 0, 0, 2048 << 16, 1536 << 16 },193 .crtc = { 0, 0, 1024, 768 },194 .rotation = DRM_MODE_ROTATE_0,195 .min_scale = DRM_PLANE_NO_SCALING,196 .max_scale = 0x20000,197 .can_position = false,198 .src_expected = { 0, 0, 2048 << 16, 1536 << 16 },199 .crtc_expected = { 0, 0, 1024, 768 },200 },201 {202 .name = "rounding1",203 .msg = "Should succeed by clipping to exact multiple",204 .src = { 0, 0, 0x40001, 0x40001 },205 .crtc = { 1022, 766, 4, 4 },206 .rotation = DRM_MODE_ROTATE_0,207 .min_scale = DRM_PLANE_NO_SCALING,208 .max_scale = 0x10001,209 .can_position = true,210 .src_expected = { 0, 0, 2 << 16, 2 << 16 },211 .crtc_expected = { 1022, 766, 2, 2 },212 },213 {214 .name = "rounding2",215 .msg = "Should succeed by clipping to exact multiple",216 .src = { 0x20001, 0x20001, 0x4040001, 0x3040001 },217 .crtc = { -2, -2, 1028, 772 },218 .rotation = DRM_MODE_ROTATE_0,219 .min_scale = DRM_PLANE_NO_SCALING,220 .max_scale = 0x10001,221 .can_position = false,222 .src_expected = { 0x40002, 0x40002, 1024 << 16, 768 << 16 },223 .crtc_expected = { 0, 0, 1024, 768 },224 },225 {226 .name = "rounding3",227 .msg = "Should succeed by clipping to exact multiple",228 .src = { 0, 0, 0x3ffff, 0x3ffff },229 .crtc = { 1022, 766, 4, 4 },230 .rotation = DRM_MODE_ROTATE_0,231 .min_scale = 0xffff,232 .max_scale = DRM_PLANE_NO_SCALING,233 .can_position = true,234 /* Should not be rounded to 0x20001, which would be upscaling. */235 .src_expected = { 0, 0, 2 << 16, 2 << 16 },236 .crtc_expected = { 1022, 766, 2, 2 },237 },238 {239 .name = "rounding4",240 .msg = "Should succeed by clipping to exact multiple",241 .src = { 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff },242 .crtc = { -2, -2, 1028, 772 },243 .rotation = DRM_MODE_ROTATE_0,244 .min_scale = 0xffff,245 .max_scale = DRM_PLANE_NO_SCALING,246 .can_position = false,247 .src_expected = { 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16 },248 .crtc_expected = { 0, 0, 1024, 768 },249 },250};251 252KUNIT_ARRAY_PARAM(drm_check_plane_state, drm_check_plane_state_tests, drm_check_plane_state_desc);253 254static void drm_test_check_invalid_plane_state(struct kunit *test)255{256 const struct drm_check_plane_state_test *params = test->param_value;257 struct drm_plane_state *plane_state = test->priv;258 259 KUNIT_ASSERT_LT_MSG(test,260 drm_atomic_helper_check_plane_state(plane_state, &crtc_state,261 params->min_scale,262 params->max_scale,263 params->can_position, false),264 0, params->msg);265}266 267static const struct drm_check_plane_state_test drm_check_invalid_plane_state_tests[] = {268 {269 .name = "positioning_invalid",270 .msg = "Should not be able to position on the crtc with can_position=false",271 .src = { 0, 0, 1023 << 16, 767 << 16 },272 .crtc = { 0, 0, 1023, 767 },273 .rotation = DRM_MODE_ROTATE_0,274 .min_scale = DRM_PLANE_NO_SCALING,275 .max_scale = DRM_PLANE_NO_SCALING,276 .can_position = false,277 },278 {279 .name = "upscaling_invalid",280 .msg = "Upscaling out of range should fail",281 .src = { 0, 0, 512 << 16, 384 << 16 },282 .crtc = { 0, 0, 1024, 768 },283 .rotation = DRM_MODE_ROTATE_0,284 .min_scale = 0x8001,285 .max_scale = DRM_PLANE_NO_SCALING,286 .can_position = false,287 },288 {289 .name = "downscaling_invalid",290 .msg = "Downscaling out of range should fail",291 .src = { 0, 0, 2048 << 16, 1536 << 16 },292 .crtc = { 0, 0, 1024, 768 },293 .rotation = DRM_MODE_ROTATE_0,294 .min_scale = DRM_PLANE_NO_SCALING,295 .max_scale = 0x1ffff,296 .can_position = false,297 },298};299 300KUNIT_ARRAY_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_tests,301 drm_check_plane_state_desc);302 303static struct kunit_case drm_plane_helper_test[] = {304 KUNIT_CASE_PARAM(drm_test_check_plane_state, drm_check_plane_state_gen_params),305 KUNIT_CASE_PARAM(drm_test_check_invalid_plane_state,306 drm_check_invalid_plane_state_gen_params),307 {}308};309 310static struct kunit_suite drm_plane_helper_test_suite = {311 .name = "drm_plane_helper",312 .init = drm_plane_helper_init,313 .test_cases = drm_plane_helper_test,314};315 316kunit_test_suite(drm_plane_helper_test_suite);317 318MODULE_DESCRIPTION("Test cases for the drm_plane_helper functions");319MODULE_LICENSE("GPL");320