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