1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Test cases for the drm_plane_helper functions 4 * 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 14 static void set_src(struct drm_plane_state *plane_state, 15 unsigned int src_x, unsigned int src_y, 16 unsigned int src_w, unsigned int src_h) 17 { 18 plane_state->src_x = src_x; 19 plane_state->src_y = src_y; 20 plane_state->src_w = src_w; 21 plane_state->src_h = src_h; 22 } 23 24 static bool check_src_eq(struct drm_plane_state *plane_state, 25 unsigned int src_x, unsigned int src_y, 26 unsigned int src_w, unsigned int src_h) 27 { 28 if (plane_state->src.x1 < 0) { 29 pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1); 30 drm_rect_debug_print("src: ", &plane_state->src, true); 31 return false; 32 } 33 if (plane_state->src.y1 < 0) { 34 pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1); 35 drm_rect_debug_print("src: ", &plane_state->src, true); 36 return false; 37 } 38 39 if (plane_state->src.x1 != src_x || 40 plane_state->src.y1 != src_y || 41 drm_rect_width(&plane_state->src) != src_w || 42 drm_rect_height(&plane_state->src) != src_h) { 43 drm_rect_debug_print("src: ", &plane_state->src, true); 44 return false; 45 } 46 47 return true; 48 } 49 50 static void set_crtc(struct drm_plane_state *plane_state, 51 int crtc_x, int crtc_y, 52 unsigned int crtc_w, unsigned int crtc_h) 53 { 54 plane_state->crtc_x = crtc_x; 55 plane_state->crtc_y = crtc_y; 56 plane_state->crtc_w = crtc_w; 57 plane_state->crtc_h = crtc_h; 58 } 59 60 static bool check_crtc_eq(struct drm_plane_state *plane_state, 61 int crtc_x, int crtc_y, 62 unsigned int crtc_w, unsigned int crtc_h) 63 { 64 if (plane_state->dst.x1 != crtc_x || 65 plane_state->dst.y1 != crtc_y || 66 drm_rect_width(&plane_state->dst) != crtc_w || 67 drm_rect_height(&plane_state->dst) != crtc_h) { 68 drm_rect_debug_print("dst: ", &plane_state->dst, false); 69 70 return false; 71 } 72 73 return true; 74 } 75 76 static void drm_test_check_plane_state(struct kunit *test) 77 { 78 int ret; 79 80 static const struct drm_crtc_state crtc_state = { 81 .crtc = ZERO_SIZE_PTR, 82 .enable = true, 83 .active = true, 84 .mode = { 85 DRM_MODE("1024x768", 0, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 86 777, 806, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) 87 }, 88 }; 89 static struct drm_plane plane = { 90 .dev = NULL 91 }; 92 static struct drm_framebuffer fb = { 93 .width = 2048, 94 .height = 2048 95 }; 96 static struct drm_plane_state plane_state = { 97 .plane = &plane, 98 .crtc = ZERO_SIZE_PTR, 99 .fb = &fb, 100 .rotation = DRM_MODE_ROTATE_0 101 }; 102 103 /* Simple clipping, no scaling. */ 104 set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16); 105 set_crtc(&plane_state, 0, 0, fb.width, fb.height); 106 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 107 DRM_PLANE_NO_SCALING, 108 DRM_PLANE_NO_SCALING, 109 false, false); 110 KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple clipping check should pass\n"); 111 KUNIT_EXPECT_TRUE(test, plane_state.visible); 112 KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16)); 113 KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 114 115 /* Rotated clipping + reflection, no scaling. */ 116 plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X; 117 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 118 DRM_PLANE_NO_SCALING, 119 DRM_PLANE_NO_SCALING, 120 false, false); 121 KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Rotated clipping check should pass\n"); 122 KUNIT_EXPECT_TRUE(test, plane_state.visible); 123 KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16)); 124 KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 125 plane_state.rotation = DRM_MODE_ROTATE_0; 126 127 /* Check whether positioning works correctly. */ 128 set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16); 129 set_crtc(&plane_state, 0, 0, 1023, 767); 130 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 131 DRM_PLANE_NO_SCALING, 132 DRM_PLANE_NO_SCALING, 133 false, false); 134 KUNIT_EXPECT_TRUE_MSG(test, ret, 135 "Should not be able to position on the crtc with can_position=false\n"); 136 137 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 138 DRM_PLANE_NO_SCALING, 139 DRM_PLANE_NO_SCALING, 140 true, false); 141 KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple positioning should work\n"); 142 KUNIT_EXPECT_TRUE(test, plane_state.visible); 143 KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16)); 144 KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1023, 767)); 145 146 /* Simple scaling tests. */ 147 set_src(&plane_state, 0, 0, 512 << 16, 384 << 16); 148 set_crtc(&plane_state, 0, 0, 1024, 768); 149 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 150 0x8001, 151 DRM_PLANE_NO_SCALING, 152 false, false); 153 KUNIT_EXPECT_TRUE_MSG(test, ret, "Upscaling out of range should fail.\n"); 154 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 155 0x8000, 156 DRM_PLANE_NO_SCALING, 157 false, false); 158 KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Upscaling exactly 2x should work\n"); 159 KUNIT_EXPECT_TRUE(test, plane_state.visible); 160 KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16)); 161 KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 162 163 set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16); 164 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 165 DRM_PLANE_NO_SCALING, 166 0x1ffff, false, false); 167 KUNIT_EXPECT_TRUE_MSG(test, ret, "Downscaling out of range should fail.\n"); 168 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 169 DRM_PLANE_NO_SCALING, 170 0x20000, false, false); 171 KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed with exact scaling limit\n"); 172 KUNIT_EXPECT_TRUE(test, plane_state.visible); 173 KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16)); 174 KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 175 176 /* Testing rounding errors. */ 177 set_src(&plane_state, 0, 0, 0x40001, 0x40001); 178 set_crtc(&plane_state, 1022, 766, 4, 4); 179 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 180 DRM_PLANE_NO_SCALING, 181 0x10001, 182 true, false); 183 KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); 184 KUNIT_EXPECT_TRUE(test, plane_state.visible); 185 KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); 186 KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2)); 187 188 set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001); 189 set_crtc(&plane_state, -2, -2, 1028, 772); 190 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 191 DRM_PLANE_NO_SCALING, 192 0x10001, 193 false, false); 194 KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); 195 KUNIT_EXPECT_TRUE(test, plane_state.visible); 196 KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x40002, 0x40002, 197 1024 << 16, 768 << 16)); 198 KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 199 200 set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff); 201 set_crtc(&plane_state, 1022, 766, 4, 4); 202 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 203 0xffff, 204 DRM_PLANE_NO_SCALING, 205 true, false); 206 KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); 207 KUNIT_EXPECT_TRUE(test, plane_state.visible); 208 /* Should not be rounded to 0x20001, which would be upscaling. */ 209 KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); 210 KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2)); 211 212 set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff); 213 set_crtc(&plane_state, -2, -2, 1028, 772); 214 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 215 0xffff, 216 DRM_PLANE_NO_SCALING, 217 false, false); 218 KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); 219 KUNIT_EXPECT_TRUE(test, plane_state.visible); 220 KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 221 1024 << 16, 768 << 16)); 222 KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 223 } 224 225 static struct kunit_case drm_plane_helper_test[] = { 226 KUNIT_CASE(drm_test_check_plane_state), 227 {} 228 }; 229 230 static struct kunit_suite drm_plane_helper_test_suite = { 231 .name = "drm_plane_helper", 232 .test_cases = drm_plane_helper_test, 233 }; 234 235 kunit_test_suite(drm_plane_helper_test_suite); 236 237 MODULE_LICENSE("GPL"); 238