18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Test cases for the drm_plane_helper functions 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "drm_plane_helper: " fmt 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 98c2ecf20Sopenharmony_ci#include <drm/drm_plane_helper.h> 108c2ecf20Sopenharmony_ci#include <drm/drm_modes.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "test-drm_modeset_common.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic void set_src(struct drm_plane_state *plane_state, 158c2ecf20Sopenharmony_ci unsigned src_x, unsigned src_y, 168c2ecf20Sopenharmony_ci unsigned src_w, unsigned src_h) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci plane_state->src_x = src_x; 198c2ecf20Sopenharmony_ci plane_state->src_y = src_y; 208c2ecf20Sopenharmony_ci plane_state->src_w = src_w; 218c2ecf20Sopenharmony_ci plane_state->src_h = src_h; 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic bool check_src_eq(struct drm_plane_state *plane_state, 258c2ecf20Sopenharmony_ci unsigned src_x, unsigned src_y, 268c2ecf20Sopenharmony_ci unsigned src_w, unsigned src_h) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci if (plane_state->src.x1 < 0) { 298c2ecf20Sopenharmony_ci pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1); 308c2ecf20Sopenharmony_ci drm_rect_debug_print("src: ", &plane_state->src, true); 318c2ecf20Sopenharmony_ci return false; 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci if (plane_state->src.y1 < 0) { 348c2ecf20Sopenharmony_ci pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1); 358c2ecf20Sopenharmony_ci drm_rect_debug_print("src: ", &plane_state->src, true); 368c2ecf20Sopenharmony_ci return false; 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (plane_state->src.x1 != src_x || 408c2ecf20Sopenharmony_ci plane_state->src.y1 != src_y || 418c2ecf20Sopenharmony_ci drm_rect_width(&plane_state->src) != src_w || 428c2ecf20Sopenharmony_ci drm_rect_height(&plane_state->src) != src_h) { 438c2ecf20Sopenharmony_ci drm_rect_debug_print("src: ", &plane_state->src, true); 448c2ecf20Sopenharmony_ci return false; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return true; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void set_crtc(struct drm_plane_state *plane_state, 518c2ecf20Sopenharmony_ci int crtc_x, int crtc_y, 528c2ecf20Sopenharmony_ci unsigned crtc_w, unsigned crtc_h) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci plane_state->crtc_x = crtc_x; 558c2ecf20Sopenharmony_ci plane_state->crtc_y = crtc_y; 568c2ecf20Sopenharmony_ci plane_state->crtc_w = crtc_w; 578c2ecf20Sopenharmony_ci plane_state->crtc_h = crtc_h; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic bool check_crtc_eq(struct drm_plane_state *plane_state, 618c2ecf20Sopenharmony_ci int crtc_x, int crtc_y, 628c2ecf20Sopenharmony_ci unsigned crtc_w, unsigned crtc_h) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci if (plane_state->dst.x1 != crtc_x || 658c2ecf20Sopenharmony_ci plane_state->dst.y1 != crtc_y || 668c2ecf20Sopenharmony_ci drm_rect_width(&plane_state->dst) != crtc_w || 678c2ecf20Sopenharmony_ci drm_rect_height(&plane_state->dst) != crtc_h) { 688c2ecf20Sopenharmony_ci drm_rect_debug_print("dst: ", &plane_state->dst, false); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return false; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return true; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciint igt_check_plane_state(void *ignored) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci int ret; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci const struct drm_crtc_state crtc_state = { 818c2ecf20Sopenharmony_ci .crtc = ZERO_SIZE_PTR, 828c2ecf20Sopenharmony_ci .enable = true, 838c2ecf20Sopenharmony_ci .active = true, 848c2ecf20Sopenharmony_ci .mode = { 858c2ecf20Sopenharmony_ci DRM_MODE("1024x768", 0, 65000, 1024, 1048, 868c2ecf20Sopenharmony_ci 1184, 1344, 0, 768, 771, 777, 806, 0, 878c2ecf20Sopenharmony_ci DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) 888c2ecf20Sopenharmony_ci }, 898c2ecf20Sopenharmony_ci }; 908c2ecf20Sopenharmony_ci struct drm_framebuffer fb = { 918c2ecf20Sopenharmony_ci .width = 2048, 928c2ecf20Sopenharmony_ci .height = 2048 938c2ecf20Sopenharmony_ci }; 948c2ecf20Sopenharmony_ci struct drm_plane_state plane_state = { 958c2ecf20Sopenharmony_ci .crtc = ZERO_SIZE_PTR, 968c2ecf20Sopenharmony_ci .fb = &fb, 978c2ecf20Sopenharmony_ci .rotation = DRM_MODE_ROTATE_0 988c2ecf20Sopenharmony_ci }; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Simple clipping, no scaling. */ 1018c2ecf20Sopenharmony_ci set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16); 1028c2ecf20Sopenharmony_ci set_crtc(&plane_state, 0, 0, fb.width, fb.height); 1038c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1048c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1058c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1068c2ecf20Sopenharmony_ci false, false); 1078c2ecf20Sopenharmony_ci FAIL(ret < 0, "Simple clipping check should pass\n"); 1088c2ecf20Sopenharmony_ci FAIL_ON(!plane_state.visible); 1098c2ecf20Sopenharmony_ci FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16)); 1108c2ecf20Sopenharmony_ci FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Rotated clipping + reflection, no scaling. */ 1138c2ecf20Sopenharmony_ci plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X; 1148c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1158c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1168c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1178c2ecf20Sopenharmony_ci false, false); 1188c2ecf20Sopenharmony_ci FAIL(ret < 0, "Rotated clipping check should pass\n"); 1198c2ecf20Sopenharmony_ci FAIL_ON(!plane_state.visible); 1208c2ecf20Sopenharmony_ci FAIL_ON(!check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16)); 1218c2ecf20Sopenharmony_ci FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 1228c2ecf20Sopenharmony_ci plane_state.rotation = DRM_MODE_ROTATE_0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Check whether positioning works correctly. */ 1258c2ecf20Sopenharmony_ci set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16); 1268c2ecf20Sopenharmony_ci set_crtc(&plane_state, 0, 0, 1023, 767); 1278c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1288c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1298c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1308c2ecf20Sopenharmony_ci false, false); 1318c2ecf20Sopenharmony_ci FAIL(!ret, "Should not be able to position on the crtc with can_position=false\n"); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1348c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1358c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1368c2ecf20Sopenharmony_ci true, false); 1378c2ecf20Sopenharmony_ci FAIL(ret < 0, "Simple positioning should work\n"); 1388c2ecf20Sopenharmony_ci FAIL_ON(!plane_state.visible); 1398c2ecf20Sopenharmony_ci FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16)); 1408c2ecf20Sopenharmony_ci FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1023, 767)); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* Simple scaling tests. */ 1438c2ecf20Sopenharmony_ci set_src(&plane_state, 0, 0, 512 << 16, 384 << 16); 1448c2ecf20Sopenharmony_ci set_crtc(&plane_state, 0, 0, 1024, 768); 1458c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1468c2ecf20Sopenharmony_ci 0x8001, 1478c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1488c2ecf20Sopenharmony_ci false, false); 1498c2ecf20Sopenharmony_ci FAIL(!ret, "Upscaling out of range should fail.\n"); 1508c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1518c2ecf20Sopenharmony_ci 0x8000, 1528c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1538c2ecf20Sopenharmony_ci false, false); 1548c2ecf20Sopenharmony_ci FAIL(ret < 0, "Upscaling exactly 2x should work\n"); 1558c2ecf20Sopenharmony_ci FAIL_ON(!plane_state.visible); 1568c2ecf20Sopenharmony_ci FAIL_ON(!check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16)); 1578c2ecf20Sopenharmony_ci FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16); 1608c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1618c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1628c2ecf20Sopenharmony_ci 0x1ffff, false, false); 1638c2ecf20Sopenharmony_ci FAIL(!ret, "Downscaling out of range should fail.\n"); 1648c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1658c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1668c2ecf20Sopenharmony_ci 0x20000, false, false); 1678c2ecf20Sopenharmony_ci FAIL(ret < 0, "Should succeed with exact scaling limit\n"); 1688c2ecf20Sopenharmony_ci FAIL_ON(!plane_state.visible); 1698c2ecf20Sopenharmony_ci FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16)); 1708c2ecf20Sopenharmony_ci FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* Testing rounding errors. */ 1738c2ecf20Sopenharmony_ci set_src(&plane_state, 0, 0, 0x40001, 0x40001); 1748c2ecf20Sopenharmony_ci set_crtc(&plane_state, 1022, 766, 4, 4); 1758c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1768c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1778c2ecf20Sopenharmony_ci 0x10001, 1788c2ecf20Sopenharmony_ci true, false); 1798c2ecf20Sopenharmony_ci FAIL(ret < 0, "Should succeed by clipping to exact multiple"); 1808c2ecf20Sopenharmony_ci FAIL_ON(!plane_state.visible); 1818c2ecf20Sopenharmony_ci FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); 1828c2ecf20Sopenharmony_ci FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2)); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001); 1858c2ecf20Sopenharmony_ci set_crtc(&plane_state, -2, -2, 1028, 772); 1868c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1878c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 1888c2ecf20Sopenharmony_ci 0x10001, 1898c2ecf20Sopenharmony_ci false, false); 1908c2ecf20Sopenharmony_ci FAIL(ret < 0, "Should succeed by clipping to exact multiple"); 1918c2ecf20Sopenharmony_ci FAIL_ON(!plane_state.visible); 1928c2ecf20Sopenharmony_ci FAIL_ON(!check_src_eq(&plane_state, 0x40002, 0x40002, 1024 << 16, 768 << 16)); 1938c2ecf20Sopenharmony_ci FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff); 1968c2ecf20Sopenharmony_ci set_crtc(&plane_state, 1022, 766, 4, 4); 1978c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 1988c2ecf20Sopenharmony_ci 0xffff, 1998c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 2008c2ecf20Sopenharmony_ci true, false); 2018c2ecf20Sopenharmony_ci FAIL(ret < 0, "Should succeed by clipping to exact multiple"); 2028c2ecf20Sopenharmony_ci FAIL_ON(!plane_state.visible); 2038c2ecf20Sopenharmony_ci /* Should not be rounded to 0x20001, which would be upscaling. */ 2048c2ecf20Sopenharmony_ci FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); 2058c2ecf20Sopenharmony_ci FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2)); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff); 2088c2ecf20Sopenharmony_ci set_crtc(&plane_state, -2, -2, 1028, 772); 2098c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 2108c2ecf20Sopenharmony_ci 0xffff, 2118c2ecf20Sopenharmony_ci DRM_PLANE_HELPER_NO_SCALING, 2128c2ecf20Sopenharmony_ci false, false); 2138c2ecf20Sopenharmony_ci FAIL(ret < 0, "Should succeed by clipping to exact multiple"); 2148c2ecf20Sopenharmony_ci FAIL_ON(!plane_state.visible); 2158c2ecf20Sopenharmony_ci FAIL_ON(!check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16)); 2168c2ecf20Sopenharmony_ci FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 220