drm_plane_helper_test.c 9.5 KB

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