1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Test cases for the drm_plane_helper functions 4 */ 5 6#define pr_fmt(fmt) "drm_plane_helper: " fmt 7 8#include <drm/drm_atomic_helper.h> 9#include <drm/drm_plane_helper.h> 10#include <drm/drm_modes.h> 11 12#include "test-drm_modeset_common.h" 13 14static void set_src(struct drm_plane_state *plane_state, 15 unsigned src_x, unsigned src_y, 16 unsigned src_w, unsigned 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 24static bool check_src_eq(struct drm_plane_state *plane_state, 25 unsigned src_x, unsigned src_y, 26 unsigned src_w, unsigned 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 50static void set_crtc(struct drm_plane_state *plane_state, 51 int crtc_x, int crtc_y, 52 unsigned crtc_w, unsigned 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 60static bool check_crtc_eq(struct drm_plane_state *plane_state, 61 int crtc_x, int crtc_y, 62 unsigned crtc_w, unsigned 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 76int igt_check_plane_state(void *ignored) 77{ 78 int ret; 79 80 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, 86 1184, 1344, 0, 768, 771, 777, 806, 0, 87 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) 88 }, 89 }; 90 struct drm_framebuffer fb = { 91 .width = 2048, 92 .height = 2048 93 }; 94 struct drm_plane_state plane_state = { 95 .crtc = ZERO_SIZE_PTR, 96 .fb = &fb, 97 .rotation = DRM_MODE_ROTATE_0 98 }; 99 100 /* Simple clipping, no scaling. */ 101 set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16); 102 set_crtc(&plane_state, 0, 0, fb.width, fb.height); 103 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 104 DRM_PLANE_HELPER_NO_SCALING, 105 DRM_PLANE_HELPER_NO_SCALING, 106 false, false); 107 FAIL(ret < 0, "Simple clipping check should pass\n"); 108 FAIL_ON(!plane_state.visible); 109 FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16)); 110 FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 111 112 /* Rotated clipping + reflection, no scaling. */ 113 plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X; 114 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 115 DRM_PLANE_HELPER_NO_SCALING, 116 DRM_PLANE_HELPER_NO_SCALING, 117 false, false); 118 FAIL(ret < 0, "Rotated clipping check should pass\n"); 119 FAIL_ON(!plane_state.visible); 120 FAIL_ON(!check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16)); 121 FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 122 plane_state.rotation = DRM_MODE_ROTATE_0; 123 124 /* Check whether positioning works correctly. */ 125 set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16); 126 set_crtc(&plane_state, 0, 0, 1023, 767); 127 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 128 DRM_PLANE_HELPER_NO_SCALING, 129 DRM_PLANE_HELPER_NO_SCALING, 130 false, false); 131 FAIL(!ret, "Should not be able to position on the crtc with can_position=false\n"); 132 133 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 134 DRM_PLANE_HELPER_NO_SCALING, 135 DRM_PLANE_HELPER_NO_SCALING, 136 true, false); 137 FAIL(ret < 0, "Simple positioning should work\n"); 138 FAIL_ON(!plane_state.visible); 139 FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16)); 140 FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1023, 767)); 141 142 /* Simple scaling tests. */ 143 set_src(&plane_state, 0, 0, 512 << 16, 384 << 16); 144 set_crtc(&plane_state, 0, 0, 1024, 768); 145 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 146 0x8001, 147 DRM_PLANE_HELPER_NO_SCALING, 148 false, false); 149 FAIL(!ret, "Upscaling out of range should fail.\n"); 150 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 151 0x8000, 152 DRM_PLANE_HELPER_NO_SCALING, 153 false, false); 154 FAIL(ret < 0, "Upscaling exactly 2x should work\n"); 155 FAIL_ON(!plane_state.visible); 156 FAIL_ON(!check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16)); 157 FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 158 159 set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16); 160 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 161 DRM_PLANE_HELPER_NO_SCALING, 162 0x1ffff, false, false); 163 FAIL(!ret, "Downscaling out of range should fail.\n"); 164 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 165 DRM_PLANE_HELPER_NO_SCALING, 166 0x20000, false, false); 167 FAIL(ret < 0, "Should succeed with exact scaling limit\n"); 168 FAIL_ON(!plane_state.visible); 169 FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16)); 170 FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 171 172 /* Testing rounding errors. */ 173 set_src(&plane_state, 0, 0, 0x40001, 0x40001); 174 set_crtc(&plane_state, 1022, 766, 4, 4); 175 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 176 DRM_PLANE_HELPER_NO_SCALING, 177 0x10001, 178 true, false); 179 FAIL(ret < 0, "Should succeed by clipping to exact multiple"); 180 FAIL_ON(!plane_state.visible); 181 FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); 182 FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2)); 183 184 set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001); 185 set_crtc(&plane_state, -2, -2, 1028, 772); 186 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 187 DRM_PLANE_HELPER_NO_SCALING, 188 0x10001, 189 false, false); 190 FAIL(ret < 0, "Should succeed by clipping to exact multiple"); 191 FAIL_ON(!plane_state.visible); 192 FAIL_ON(!check_src_eq(&plane_state, 0x40002, 0x40002, 1024 << 16, 768 << 16)); 193 FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 194 195 set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff); 196 set_crtc(&plane_state, 1022, 766, 4, 4); 197 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 198 0xffff, 199 DRM_PLANE_HELPER_NO_SCALING, 200 true, false); 201 FAIL(ret < 0, "Should succeed by clipping to exact multiple"); 202 FAIL_ON(!plane_state.visible); 203 /* Should not be rounded to 0x20001, which would be upscaling. */ 204 FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); 205 FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2)); 206 207 set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff); 208 set_crtc(&plane_state, -2, -2, 1028, 772); 209 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 210 0xffff, 211 DRM_PLANE_HELPER_NO_SCALING, 212 false, false); 213 FAIL(ret < 0, "Should succeed by clipping to exact multiple"); 214 FAIL_ON(!plane_state.visible); 215 FAIL_ON(!check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16)); 216 FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 217 218 return 0; 219} 220