1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Test cases for the drm_rect functions
4 */
5
6#define pr_fmt(fmt) "drm_rect: " fmt
7
8#include <linux/limits.h>
9
10#include <drm/drm_rect.h>
11
12#include "test-drm_modeset_common.h"
13
14int igt_drm_rect_clip_scaled_div_by_zero(void *ignored)
15{
16	struct drm_rect src, dst, clip;
17	bool visible;
18
19	/*
20	 * Make sure we don't divide by zero when dst
21	 * width/height is zero and dst and clip do not intersect.
22	 */
23	drm_rect_init(&src, 0, 0, 0, 0);
24	drm_rect_init(&dst, 0, 0, 0, 0);
25	drm_rect_init(&clip, 1, 1, 1, 1);
26	visible = drm_rect_clip_scaled(&src, &dst, &clip);
27	FAIL(visible, "Destination not be visible\n");
28	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
29
30	drm_rect_init(&src, 0, 0, 0, 0);
31	drm_rect_init(&dst, 3, 3, 0, 0);
32	drm_rect_init(&clip, 1, 1, 1, 1);
33	visible = drm_rect_clip_scaled(&src, &dst, &clip);
34	FAIL(visible, "Destination not be visible\n");
35	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
36
37	return 0;
38}
39
40int igt_drm_rect_clip_scaled_not_clipped(void *ignored)
41{
42	struct drm_rect src, dst, clip;
43	bool visible;
44
45	/* 1:1 scaling */
46	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
47	drm_rect_init(&dst, 0, 0, 1, 1);
48	drm_rect_init(&clip, 0, 0, 1, 1);
49
50	visible = drm_rect_clip_scaled(&src, &dst, &clip);
51
52	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
53	     src.y1 != 0 || src.y2 != 1 << 16,
54	     "Source badly clipped\n");
55	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
56	     dst.y1 != 0 || dst.y2 != 1,
57	     "Destination badly clipped\n");
58	FAIL(!visible, "Destination should be visible\n");
59	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
60
61	/* 2:1 scaling */
62	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
63	drm_rect_init(&dst, 0, 0, 1, 1);
64	drm_rect_init(&clip, 0, 0, 1, 1);
65
66	visible = drm_rect_clip_scaled(&src, &dst, &clip);
67
68	FAIL(src.x1 != 0 || src.x2 != 2 << 16 ||
69	     src.y1 != 0 || src.y2 != 2 << 16,
70	     "Source badly clipped\n");
71	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
72	     dst.y1 != 0 || dst.y2 != 1,
73	     "Destination badly clipped\n");
74	FAIL(!visible, "Destination should be visible\n");
75	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
76
77	/* 1:2 scaling */
78	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
79	drm_rect_init(&dst, 0, 0, 2, 2);
80	drm_rect_init(&clip, 0, 0, 2, 2);
81
82	visible = drm_rect_clip_scaled(&src, &dst, &clip);
83
84	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
85	     src.y1 != 0 || src.y2 != 1 << 16,
86	     "Source badly clipped\n");
87	FAIL(dst.x1 != 0 || dst.x2 != 2 ||
88	     dst.y1 != 0 || dst.y2 != 2,
89	     "Destination badly clipped\n");
90	FAIL(!visible, "Destination should be visible\n");
91	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
92
93	return 0;
94}
95
96int igt_drm_rect_clip_scaled_clipped(void *ignored)
97{
98	struct drm_rect src, dst, clip;
99	bool visible;
100
101	/* 1:1 scaling top/left clip */
102	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
103	drm_rect_init(&dst, 0, 0, 2, 2);
104	drm_rect_init(&clip, 0, 0, 1, 1);
105
106	visible = drm_rect_clip_scaled(&src, &dst, &clip);
107
108	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
109	     src.y1 != 0 || src.y2 != 1 << 16,
110	     "Source badly clipped\n");
111	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
112	     dst.y1 != 0 || dst.y2 != 1,
113	     "Destination badly clipped\n");
114	FAIL(!visible, "Destination should be visible\n");
115	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
116
117	/* 1:1 scaling bottom/right clip */
118	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
119	drm_rect_init(&dst, 0, 0, 2, 2);
120	drm_rect_init(&clip, 1, 1, 1, 1);
121
122	visible = drm_rect_clip_scaled(&src, &dst, &clip);
123
124	FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
125	     src.y1 != 1 << 16 || src.y2 != 2 << 16,
126	     "Source badly clipped\n");
127	FAIL(dst.x1 != 1 || dst.x2 != 2 ||
128	     dst.y1 != 1 || dst.y2 != 2,
129	     "Destination badly clipped\n");
130	FAIL(!visible, "Destination should be visible\n");
131	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
132
133	/* 2:1 scaling top/left clip */
134	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
135	drm_rect_init(&dst, 0, 0, 2, 2);
136	drm_rect_init(&clip, 0, 0, 1, 1);
137
138	visible = drm_rect_clip_scaled(&src, &dst, &clip);
139
140	FAIL(src.x1 != 0 || src.x2 != 2 << 16 ||
141	     src.y1 != 0 || src.y2 != 2 << 16,
142	     "Source badly clipped\n");
143	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
144	     dst.y1 != 0 || dst.y2 != 1,
145	     "Destination badly clipped\n");
146	FAIL(!visible, "Destination should be visible\n");
147	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
148
149	/* 2:1 scaling bottom/right clip */
150	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
151	drm_rect_init(&dst, 0, 0, 2, 2);
152	drm_rect_init(&clip, 1, 1, 1, 1);
153
154	visible = drm_rect_clip_scaled(&src, &dst, &clip);
155
156	FAIL(src.x1 != 2 << 16 || src.x2 != 4 << 16 ||
157	     src.y1 != 2 << 16 || src.y2 != 4 << 16,
158	     "Source badly clipped\n");
159	FAIL(dst.x1 != 1 || dst.x2 != 2 ||
160	     dst.y1 != 1 || dst.y2 != 2,
161	     "Destination badly clipped\n");
162	FAIL(!visible, "Destination should be visible\n");
163	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
164
165	/* 1:2 scaling top/left clip */
166	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
167	drm_rect_init(&dst, 0, 0, 4, 4);
168	drm_rect_init(&clip, 0, 0, 2, 2);
169
170	visible = drm_rect_clip_scaled(&src, &dst, &clip);
171
172	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
173	     src.y1 != 0 || src.y2 != 1 << 16,
174	     "Source badly clipped\n");
175	FAIL(dst.x1 != 0 || dst.x2 != 2 ||
176	     dst.y1 != 0 || dst.y2 != 2,
177	     "Destination badly clipped\n");
178	FAIL(!visible, "Destination should be visible\n");
179	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
180
181	/* 1:2 scaling bottom/right clip */
182	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
183	drm_rect_init(&dst, 0, 0, 4, 4);
184	drm_rect_init(&clip, 2, 2, 2, 2);
185
186	visible = drm_rect_clip_scaled(&src, &dst, &clip);
187
188	FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
189	     src.y1 != 1 << 16 || src.y2 != 2 << 16,
190	     "Source badly clipped\n");
191	FAIL(dst.x1 != 2 || dst.x2 != 4 ||
192	     dst.y1 != 2 || dst.y2 != 4,
193	     "Destination badly clipped\n");
194	FAIL(!visible, "Destination should be visible\n");
195	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
196
197	return 0;
198}
199
200int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored)
201{
202	struct drm_rect src, dst, clip;
203	bool visible;
204
205	/*
206	 * 'clip.x2 - dst.x1 >= dst width' could result a negative
207	 * src rectangle width which is no longer expected by the
208	 * code as it's using unsigned types. This could lead to
209	 * the clipped source rectangle appering visible when it
210	 * should have been fully clipped. Make sure both rectangles
211	 * end up invisible.
212	 */
213	drm_rect_init(&src, 0, 0, INT_MAX, INT_MAX);
214	drm_rect_init(&dst, 0, 0, 2, 2);
215	drm_rect_init(&clip, 3, 3, 1, 1);
216
217	visible = drm_rect_clip_scaled(&src, &dst, &clip);
218
219	FAIL(visible, "Destination should not be visible\n");
220	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
221
222	return 0;
223}
224