xref: /aosp_15_r20/external/igt-gpu-tools/tests/kms_getfb.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2013 Intel Corporation
3  * Copyright © 2018 Collabora, Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Daniel Vetter <[email protected]>
26  *    Daniel Stone <[email protected]>
27  *
28  */
29 
30 #include "igt.h"
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <inttypes.h>
37 #include <errno.h>
38 #include <sys/stat.h>
39 #include <sys/ioctl.h>
40 #include "drm.h"
41 #include "drm_fourcc.h"
42 
has_getfb_iface(int fd)43 static bool has_getfb_iface(int fd)
44 {
45 	struct drm_mode_fb_cmd arg = { };
46 	int err;
47 
48 	err = 0;
49 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETFB, &arg))
50 		err = -errno;
51 	switch (err) {
52 	case -ENOTTY: /* ioctl unrecognised (kernel too old) */
53 	case -ENOTSUP: /* driver doesn't support KMS */
54 		return false;
55 	default:
56 		return true;
57 	}
58 }
59 
has_addfb2_iface(int fd)60 static bool has_addfb2_iface(int fd)
61 {
62 	struct drm_mode_fb_cmd2 arg = { };
63 	int err;
64 
65 	err = 0;
66 	if (drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &arg))
67 		err = -errno;
68 	switch (err) {
69 	case -ENOTTY: /* ioctl unrecognised (kernel too old) */
70 	case -ENOTSUP: /* driver doesn't support KMS */
71 		return false;
72 	default:
73 		return true;
74 	}
75 }
76 
get_ccs_fb(int fd,struct drm_mode_fb_cmd2 * ret)77 static void get_ccs_fb(int fd, struct drm_mode_fb_cmd2 *ret)
78 {
79 	struct drm_mode_fb_cmd2 add = {
80 		.width = 1024,
81 		.height = 1024,
82 		.pixel_format = DRM_FORMAT_XRGB8888,
83 		.flags = DRM_MODE_FB_MODIFIERS,
84 		.modifier = {
85 			I915_FORMAT_MOD_Y_TILED_CCS,
86 			I915_FORMAT_MOD_Y_TILED_CCS,
87 		},
88 	};
89 	int size;
90 
91 	igt_require(has_addfb2_iface(fd));
92 	igt_require_intel(fd);
93 
94 	/* An explanation of the magic numbers can be found in kms_ccs.c. */
95 	add.pitches[0] = ALIGN(add.width * 4, 128);
96 	add.offsets[1] = add.pitches[0] * ALIGN(add.height, 32);
97 	add.pitches[1] = ALIGN(ALIGN(add.width * 4, 32) / 32, 128);
98 
99 	size = add.offsets[1];
100 	size += add.pitches[1] * ALIGN(ALIGN(add.height, 16) / 16, 32);
101 
102 	add.handles[0] = gem_create(fd, size);
103 	igt_require(add.handles[0] != 0);
104 	add.handles[1] = add.handles[0];
105 
106 	if (drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &add) == 0)
107 		*ret = add;
108 	else
109 		gem_close(fd, add.handles[0]);
110 }
111 
112 /**
113  * Find and return an arbitrary valid property ID.
114  */
get_any_prop_id(int fd)115 static uint32_t get_any_prop_id(int fd)
116 {
117 	igt_display_t display;
118 
119 	igt_display_require(&display, fd);
120 	for (int i = 0; i < display.n_outputs; i++) {
121 		igt_output_t *output = &display.outputs[i];
122 		if (output->props[IGT_CONNECTOR_DPMS] != 0)
123 			return output->props[IGT_CONNECTOR_DPMS];
124 	}
125 
126 	return 0;
127 }
128 
test_handle_input(int fd)129 static void test_handle_input(int fd)
130 {
131 	struct drm_mode_fb_cmd2 add = {};
132 
133 	igt_fixture {
134 		add.width = 1024;
135 		add.height = 1024;
136 		add.pixel_format = DRM_FORMAT_XRGB8888;
137 		add.pitches[0] = 1024*4;
138 		add.handles[0] = igt_create_bo_with_dimensions(fd, 1024, 1024,
139 			DRM_FORMAT_XRGB8888, 0, 0, NULL, NULL, NULL);
140 		igt_require(add.handles[0] != 0);
141 		do_ioctl(fd, DRM_IOCTL_MODE_ADDFB2, &add);
142 	}
143 
144 	igt_subtest("getfb-handle-zero") {
145 		struct drm_mode_fb_cmd get = { .fb_id = 0 };
146 		do_ioctl_err(fd, DRM_IOCTL_MODE_GETFB, &get, ENOENT);
147 	}
148 
149 	igt_subtest("getfb-handle-valid") {
150 		struct drm_mode_fb_cmd get = { .fb_id = add.fb_id };
151 		do_ioctl(fd, DRM_IOCTL_MODE_GETFB, &get);
152 		igt_assert_neq_u32(get.handle, 0);
153 		igt_assert_eq_u32(get.width, add.width);
154 		igt_assert_eq_u32(get.height, add.height);
155 		igt_assert_eq_u32(get.pitch, add.pitches[0]);
156 		igt_assert_eq_u32(get.depth, 24);
157 		igt_assert_eq_u32(get.bpp, 32);
158 		gem_close(fd, get.handle);
159 	}
160 
161 	igt_subtest("getfb-handle-closed") {
162 		struct drm_mode_fb_cmd get = { .fb_id = add.fb_id };
163 		do_ioctl(fd, DRM_IOCTL_MODE_RMFB, &add.fb_id);
164 		do_ioctl_err(fd, DRM_IOCTL_MODE_GETFB, &get, ENOENT);
165 	}
166 
167 	igt_subtest("getfb-handle-not-fb") {
168 		struct drm_mode_fb_cmd get = { .fb_id = get_any_prop_id(fd) };
169 		igt_require(get.fb_id > 0);
170 		do_ioctl_err(fd, DRM_IOCTL_MODE_GETFB, &get, ENOENT);
171 	}
172 
173 	igt_fixture
174 		gem_close(fd, add.handles[0]);
175 }
176 
test_duplicate_handles(int fd)177 static void test_duplicate_handles(int fd)
178 {
179 	struct drm_mode_fb_cmd2 add = {};
180 
181 	igt_fixture {
182 		add.width = 1024;
183 		add.height = 1024;
184 		add.pixel_format = DRM_FORMAT_XRGB8888;
185 		add.pitches[0] = 1024*4;
186 		add.handles[0] = igt_create_bo_with_dimensions(fd, 1024, 1024,
187 			DRM_FORMAT_XRGB8888, 0, 0, NULL, NULL, NULL);
188 		igt_assert(add.handles[0]);
189 		do_ioctl(fd, DRM_IOCTL_MODE_ADDFB2, &add);
190 	}
191 
192 	igt_subtest("getfb-addfb-different-handles") {
193 		struct drm_mode_fb_cmd get = { .fb_id = add.fb_id };
194 
195 		do_ioctl(fd, DRM_IOCTL_MODE_GETFB, &get);
196 		igt_assert_neq_u32(get.handle, add.handles[0]);
197 		gem_close(fd, get.handle);
198 	}
199 
200 	igt_subtest("getfb-repeated-different-handles") {
201 		struct drm_mode_fb_cmd get1 = { .fb_id = add.fb_id };
202 		struct drm_mode_fb_cmd get2 = { .fb_id = add.fb_id };
203 
204 		do_ioctl(fd, DRM_IOCTL_MODE_GETFB, &get1);
205 		do_ioctl(fd, DRM_IOCTL_MODE_GETFB, &get2);
206 		igt_assert_neq_u32(get1.handle, get2.handle);
207 
208 		gem_close(fd, get1.handle);
209 		gem_close(fd, get2.handle);
210 	}
211 
212 	igt_subtest("getfb-reject-ccs") {
213 		struct drm_mode_fb_cmd2 add_ccs = { };
214 		struct drm_mode_fb_cmd get = { };
215 
216 		get_ccs_fb(fd, &add_ccs);
217 		igt_require(add_ccs.handles[0] != 0);
218 		get.fb_id = add_ccs.fb_id;
219 		do_ioctl_err(fd, DRM_IOCTL_MODE_GETFB, &get, EINVAL);
220 
221 		do_ioctl(fd, DRM_IOCTL_MODE_RMFB, &add_ccs.fb_id);
222 		gem_close(fd, add_ccs.handles[0]);
223 	}
224 
225 	igt_fixture {
226 		do_ioctl(fd, DRM_IOCTL_MODE_RMFB, &add.fb_id);
227 		gem_close(fd, add.handles[0]);
228 	}
229 }
230 
231 igt_main
232 {
233 	int fd;
234 
235 	igt_fixture {
236 		fd = drm_open_driver_master(DRIVER_ANY);
237 		igt_require(has_getfb_iface(fd));
238 	}
239 
240 	igt_subtest_group
241 		test_handle_input(fd);
242 
243 	igt_subtest_group
244 		test_duplicate_handles(fd);
245 
246 	igt_fixture
247 		close(fd);
248 }
249