Home | History | Annotate | Download | only in vtest
      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;
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    443 int vtest_renderer_create_fence(void)
    444 {
    445   virgl_renderer_create_fence(fence_id++, ctx_id);
    446   return 0;
    447 }
    448 
    449 int vtest_poll(void)
    450 {
    451   virgl_renderer_poll();
    452   return 0;
    453 }
    454