1 /**************************************************************************
2 *
3 * Copyright (C) 2015 Red Hat Inc.
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 shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <limits.h>
30
31 #include "virglrenderer.h"
32
33 #include <sys/uio.h>
34 #include "vtest.h"
35 #include "vtest_protocol.h"
36 #include "util.h"
37 #include "util/u_debug.h"
38
39 static int ctx_id = 1;
40 static int fence_id = 1;
41
42 static int last_fence;
vtest_write_fence(UNUSED void * cookie,uint32_t fence_id_in)43 static void vtest_write_fence(UNUSED void *cookie, uint32_t fence_id_in)
44 {
45 last_fence = fence_id_in;
46 }
47
48 struct virgl_renderer_callbacks vtest_cbs = {
49 .version = 1,
50 .write_fence = vtest_write_fence,
51 };
52
53 struct vtest_renderer {
54 int in_fd;
55 int out_fd;
56 };
57
58 struct vtest_renderer renderer;
59
60 struct virgl_box {
61 uint32_t x, y, z;
62 uint32_t w, h, d;
63 };
64
vtest_block_write(int fd,void * buf,int size)65 static int vtest_block_write(int fd, void *buf, int size)
66 {
67 void *ptr = buf;
68 int left;
69 int ret;
70 left = size;
71 do {
72 ret = write(fd, ptr, left);
73 if (ret < 0)
74 return -errno;
75 left -= ret;
76 ptr += ret;
77 } while (left);
78 return size;
79 }
80
vtest_block_read(int fd,void * buf,int size)81 int vtest_block_read(int fd, void *buf, int size)
82 {
83 void *ptr = buf;
84 int left;
85 int ret;
86 static int savefd = -1;
87
88 left = size;
89 do {
90 ret = read(fd, ptr, left);
91 if (ret <= 0)
92 return ret == -1 ? -errno : 0;
93 left -= ret;
94 ptr += ret;
95 } while (left);
96 if (getenv("VTEST_SAVE")) {
97 if (savefd == -1) {
98 savefd = open(getenv("VTEST_SAVE"),
99 O_CLOEXEC|O_CREAT|O_WRONLY|O_TRUNC|O_DSYNC, S_IRUSR|S_IWUSR);
100 if (savefd == -1) {
101 perror("error opening save file");
102 exit(1);
103 }
104 }
105 if (write(savefd, buf, size) != size) {
106 perror("failed to save");
107 exit(1);
108 }
109 }
110 return size;
111 }
112
vtest_create_renderer(int in_fd,int out_fd,uint32_t length)113 int vtest_create_renderer(int in_fd, int out_fd, uint32_t length)
114 {
115 char *vtestname;
116 int ret;
117 int ctx = VIRGL_RENDERER_USE_EGL;
118
119 renderer.in_fd = in_fd;
120 renderer.out_fd = out_fd;
121
122 if (getenv("VTEST_USE_GLX"))
123 ctx = VIRGL_RENDERER_USE_GLX;
124
125 if (getenv("VTEST_USE_EGL_SURFACELESS")) {
126 if (ctx & VIRGL_RENDERER_USE_GLX) {
127 fprintf(stderr, "Cannot use surfaceless with GLX.\n");
128 return -1;
129 }
130 ctx |= VIRGL_RENDERER_USE_SURFACELESS;
131 }
132
133 if (getenv("VTEST_USE_GLES")) {
134 if (ctx & VIRGL_RENDERER_USE_GLX) {
135 fprintf(stderr, "Cannot use GLES with GLX.\n");
136 return -1;
137 }
138 ctx |= VIRGL_RENDERER_USE_GLES;
139 }
140
141 ret = virgl_renderer_init(&renderer,
142 ctx | VIRGL_RENDERER_THREAD_SYNC, &vtest_cbs);
143 if (ret) {
144 fprintf(stderr, "failed to initialise renderer.\n");
145 return -1;
146 }
147
148 vtestname = calloc(1, length + 1);
149 if (!vtestname)
150 return -1;
151
152 ret = vtest_block_read(renderer.in_fd, vtestname, length);
153 if (ret != (int)length) {
154 ret = -1;
155 goto end;
156 }
157
158 ret = virgl_renderer_context_create(ctx_id, strlen(vtestname), vtestname);
159
160 end:
161 free(vtestname);
162 return ret;
163 }
164
vtest_destroy_renderer(void)165 void vtest_destroy_renderer(void)
166 {
167 virgl_renderer_context_destroy(ctx_id);
168 virgl_renderer_cleanup(&renderer);
169 renderer.in_fd = -1;
170 renderer.out_fd = -1;
171 }
172
vtest_send_caps2(void)173 int vtest_send_caps2(void)
174 {
175 uint32_t hdr_buf[2];
176 void *caps_buf;
177 int ret;
178 uint32_t max_ver, max_size;
179
180 virgl_renderer_get_cap_set(2, &max_ver, &max_size);
181
182 if (max_size == 0)
183 return -1;
184 caps_buf = malloc(max_size);
185 if (!caps_buf)
186 return -1;
187
188 virgl_renderer_fill_caps(2, 1, caps_buf);
189
190 hdr_buf[0] = max_size + 1;
191 hdr_buf[1] = 2;
192 ret = vtest_block_write(renderer.out_fd, hdr_buf, 8);
193 if (ret < 0)
194 goto end;
195 vtest_block_write(renderer.out_fd, caps_buf, max_size);
196 if (ret < 0)
197 goto end;
198
199 end:
200 free(caps_buf);
201 return 0;
202 }
203
vtest_send_caps(void)204 int vtest_send_caps(void)
205 {
206 uint32_t max_ver, max_size;
207 void *caps_buf;
208 uint32_t hdr_buf[2];
209 int ret;
210
211 virgl_renderer_get_cap_set(1, &max_ver, &max_size);
212
213 caps_buf = malloc(max_size);
214 if (!caps_buf)
215 return -1;
216
217 virgl_renderer_fill_caps(1, 1, caps_buf);
218
219 hdr_buf[0] = max_size + 1;
220 hdr_buf[1] = 1;
221 ret = vtest_block_write(renderer.out_fd, hdr_buf, 8);
222 if (ret < 0)
223 goto end;
224 vtest_block_write(renderer.out_fd, caps_buf, max_size);
225 if (ret < 0)
226 goto end;
227
228 end:
229 free(caps_buf);
230 return 0;
231 }
232
vtest_create_resource(void)233 int vtest_create_resource(void)
234 {
235 uint32_t res_create_buf[VCMD_RES_CREATE_SIZE];
236 struct virgl_renderer_resource_create_args args;
237 int ret;
238
239 ret = vtest_block_read(renderer.in_fd, &res_create_buf, sizeof(res_create_buf));
240 if (ret != sizeof(res_create_buf))
241 return -1;
242
243 args.handle = res_create_buf[VCMD_RES_CREATE_RES_HANDLE];
244 args.target = res_create_buf[VCMD_RES_CREATE_TARGET];
245 args.format = res_create_buf[VCMD_RES_CREATE_FORMAT];
246 args.bind = res_create_buf[VCMD_RES_CREATE_BIND];
247
248 args.width = res_create_buf[VCMD_RES_CREATE_WIDTH];
249 args.height = res_create_buf[VCMD_RES_CREATE_HEIGHT];
250 args.depth = res_create_buf[VCMD_RES_CREATE_DEPTH];
251 args.array_size = res_create_buf[VCMD_RES_CREATE_ARRAY_SIZE];
252 args.last_level = res_create_buf[VCMD_RES_CREATE_LAST_LEVEL];
253 args.nr_samples = res_create_buf[VCMD_RES_CREATE_NR_SAMPLES];
254 args.flags = 0;
255
256 ret = virgl_renderer_resource_create(&args, NULL, 0);
257
258 virgl_renderer_ctx_attach_resource(ctx_id, args.handle);
259 return ret;
260 }
261
vtest_resource_unref(void)262 int vtest_resource_unref(void)
263 {
264 uint32_t res_unref_buf[VCMD_RES_UNREF_SIZE];
265 int ret;
266 uint32_t handle;
267
268 ret = vtest_block_read(renderer.in_fd, &res_unref_buf, sizeof(res_unref_buf));
269 if (ret != sizeof(res_unref_buf))
270 return -1;
271
272 handle = res_unref_buf[VCMD_RES_UNREF_RES_HANDLE];
273 virgl_renderer_ctx_attach_resource(ctx_id, handle);
274 virgl_renderer_resource_unref(handle);
275 return 0;
276 }
277
vtest_submit_cmd(uint32_t length_dw)278 int vtest_submit_cmd(uint32_t length_dw)
279 {
280 uint32_t *cbuf;
281 int ret;
282
283 if (length_dw > UINT_MAX / 4)
284 return -1;
285
286 cbuf = malloc(length_dw * 4);
287 if (!cbuf)
288 return -1;
289
290 ret = vtest_block_read(renderer.in_fd, cbuf, length_dw * 4);
291 if (ret != (int)length_dw * 4) {
292 free(cbuf);
293 return -1;
294 }
295
296 virgl_renderer_submit_cmd(cbuf, ctx_id, length_dw);
297
298 free(cbuf);
299 return 0;
300 }
301
302 #define DECODE_TRANSFER \
303 do { \
304 handle = thdr_buf[VCMD_TRANSFER_RES_HANDLE]; \
305 level = thdr_buf[VCMD_TRANSFER_LEVEL]; \
306 stride = thdr_buf[VCMD_TRANSFER_STRIDE]; \
307 layer_stride = thdr_buf[VCMD_TRANSFER_LAYER_STRIDE]; \
308 box.x = thdr_buf[VCMD_TRANSFER_X]; \
309 box.y = thdr_buf[VCMD_TRANSFER_Y]; \
310 box.z = thdr_buf[VCMD_TRANSFER_Z]; \
311 box.w = thdr_buf[VCMD_TRANSFER_WIDTH]; \
312 box.h = thdr_buf[VCMD_TRANSFER_HEIGHT]; \
313 box.d = thdr_buf[VCMD_TRANSFER_DEPTH]; \
314 data_size = thdr_buf[VCMD_TRANSFER_DATA_SIZE]; \
315 } while(0)
316
317
vtest_transfer_get(UNUSED uint32_t length_dw)318 int vtest_transfer_get(UNUSED uint32_t length_dw)
319 {
320 uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
321 int ret;
322 int level;
323 uint32_t stride, layer_stride, handle;
324 struct virgl_box box;
325 uint32_t data_size;
326 void *ptr;
327 struct iovec iovec;
328
329 ret = vtest_block_read(renderer.in_fd, thdr_buf, VCMD_TRANSFER_HDR_SIZE * 4);
330 if (ret != VCMD_TRANSFER_HDR_SIZE * 4)
331 return ret;
332
333 DECODE_TRANSFER;
334
335 ptr = malloc(data_size);
336 if (!ptr)
337 return -ENOMEM;
338
339 iovec.iov_len = data_size;
340 iovec.iov_base = ptr;
341 ret = virgl_renderer_transfer_read_iov(handle,
342 ctx_id,
343 level,
344 stride,
345 layer_stride,
346 &box,
347 0,
348 &iovec, 1);
349 if (ret)
350 fprintf(stderr," transfer read failed %d\n", ret);
351 ret = vtest_block_write(renderer.out_fd, ptr, data_size);
352
353 free(ptr);
354 return ret < 0 ? ret : 0;
355 }
356
vtest_transfer_put(UNUSED uint32_t length_dw)357 int vtest_transfer_put(UNUSED uint32_t length_dw)
358 {
359 uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
360 int ret;
361 int level;
362 uint32_t stride, layer_stride, handle;
363 struct virgl_box box;
364 uint32_t data_size;
365 void *ptr;
366 struct iovec iovec;
367
368 ret = vtest_block_read(renderer.in_fd, thdr_buf, VCMD_TRANSFER_HDR_SIZE * 4);
369 if (ret != VCMD_TRANSFER_HDR_SIZE * 4)
370 return ret;
371
372 DECODE_TRANSFER;
373
374 ptr = malloc(data_size);
375 if (!ptr)
376 return -ENOMEM;
377
378 ret = vtest_block_read(renderer.in_fd, ptr, data_size);
379 if (ret < 0)
380 return ret;
381
382 iovec.iov_len = data_size;
383 iovec.iov_base = ptr;
384 ret = virgl_renderer_transfer_write_iov(handle,
385 ctx_id,
386 level,
387 stride,
388 layer_stride,
389 &box,
390 0,
391 &iovec, 1);
392 if (ret)
393 fprintf(stderr," transfer write failed %d\n", ret);
394 free(ptr);
395 return 0;
396 }
397
vtest_resource_busy_wait(void)398 int vtest_resource_busy_wait(void)
399 {
400 uint32_t bw_buf[VCMD_BUSY_WAIT_SIZE];
401 int ret, fd;
402 int flags;
403 uint32_t hdr_buf[VTEST_HDR_SIZE];
404 uint32_t reply_buf[1];
405 bool busy = false;
406 ret = vtest_block_read(renderer.in_fd, &bw_buf, sizeof(bw_buf));
407 if (ret != sizeof(bw_buf))
408 return -1;
409
410 /* handle = bw_buf[VCMD_BUSY_WAIT_HANDLE]; unused as of now */
411 flags = bw_buf[VCMD_BUSY_WAIT_FLAGS];
412
413 if (flags == VCMD_BUSY_WAIT_FLAG_WAIT) {
414 do {
415 if (last_fence == (fence_id - 1))
416 break;
417
418 fd = virgl_renderer_get_poll_fd();
419 if (fd != -1)
420 vtest_wait_for_fd_read(fd);
421 virgl_renderer_poll();
422 } while (1);
423 busy = false;
424 } else {
425 busy = last_fence != (fence_id - 1);
426 }
427
428 hdr_buf[VTEST_CMD_LEN] = 1;
429 hdr_buf[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;
430 reply_buf[0] = busy ? 1 : 0;
431
432 ret = vtest_block_write(renderer.out_fd, hdr_buf, sizeof(hdr_buf));
433 if (ret < 0)
434 return ret;
435
436 ret = vtest_block_write(renderer.out_fd, reply_buf, sizeof(reply_buf));
437 if (ret < 0)
438 return ret;
439
440 return 0;
441 }
442
vtest_renderer_create_fence(void)443 int vtest_renderer_create_fence(void)
444 {
445 virgl_renderer_create_fence(fence_id++, ctx_id);
446 return 0;
447 }
448
vtest_poll(void)449 int vtest_poll(void)
450 {
451 virgl_renderer_poll();
452 return 0;
453 }
454