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