vtest_renderer.c 23.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/**************************************************************************
 *
 * Copyright (C) 2015 Red Hat Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 **************************************************************************/
24

25
#include <stdlib.h>
26
#include <stdio.h>
Dave Airlie's avatar
Dave Airlie committed
27
#include <string.h>
28
#include <unistd.h>
29
#include <fcntl.h>
30
#include <limits.h>
31

32
#include "virgl_hw.h"
33 34
#include "virglrenderer.h"

35
#include <sys/uio.h>
36
#include <sys/socket.h>
37
#include <sys/mman.h>
38

39
#include "vtest.h"
40
#include "vtest_shm.h"
Dave Airlie's avatar
Dave Airlie committed
41
#include "vtest_protocol.h"
42

43
#include "util.h"
44
#include "util/u_debug.h"
45
#include "util/u_math.h"
46 47
#include "util/u_memory.h"
#include "util/u_hash_table.h"
Dave Airlie's avatar
Dave Airlie committed
48

49

Dave Airlie's avatar
Dave Airlie committed
50
static int ctx_id = 1;
51
static int fence_id = 1;
52
static uint32_t max_length = UINT_MAX;
53

54 55 56 57 58 59 60 61 62

struct vtest_renderer {
   struct vtest_input *input;
   int out_fd;
   unsigned protocol_version;
   struct util_hash_table *iovec_hash;
   const char *rendernode_name;
};

63
static int last_fence;
64
static void vtest_write_fence(UNUSED void *cookie, uint32_t fence_id_in)
65
{
66
   last_fence = fence_id_in;
67 68
}

69 70 71 72 73 74 75 76 77 78 79 80 81 82
static int last_fence;
static int vtest_get_drm_fd(void *cookie)
{
   int fd = -1;
   struct vtest_renderer *renderer = (struct vtest_renderer*)cookie;
   if (!renderer->rendernode_name)
      return -1;
   fd = open(renderer->rendernode_name, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
   if (fd == -1)
      fprintf(stderr, "Unable to open rendernode '%s' falling back to default search\n",
              renderer->rendernode_name);
   return fd;
}

83
struct virgl_renderer_callbacks vtest_cbs = {
84
   .version = 2,
85
   .write_fence = vtest_write_fence,
86
   .get_drm_fd = vtest_get_drm_fd
87 88 89 90 91
};


struct vtest_renderer renderer;

92 93 94 95 96 97 98 99 100 101
static unsigned
hash_func(void *key)
{
   intptr_t ip = pointer_to_intptr(key);
   return (unsigned)(ip & 0xffffffff);
}

static int
compare_iovecs(void *key1, void *key2)
{
102
   if (key1 < key2) {
103
      return -1;
104
   } else if (key1 > key2) {
105
      return 1;
106
   } else {
107
      return 0;
108
   }
109 110 111 112 113
}

static void free_iovec(void *value)
{
   struct iovec *iovec = value;
114 115
   if (iovec->iov_base)
      munmap(iovec->iov_base, iovec->iov_len);
116 117 118
   free(iovec);
}

119 120 121 122 123 124
static int vtest_block_write(int fd, void *buf, int size)
{
   void *ptr = buf;
   int left;
   int ret;
   left = size;
125

126 127
   do {
      ret = write(fd, ptr, left);
128
      if (ret < 0) {
129
         return -errno;
130 131
      }

132 133 134
      left -= ret;
      ptr += ret;
   } while (left);
135

136 137 138
   return size;
}

139
int vtest_block_read(struct vtest_input *input, void *buf, int size)
140
{
141
   int fd = input->data.fd;
142 143 144
   void *ptr = buf;
   int left;
   int ret;
145 146
   static int savefd = -1;

147 148 149
   left = size;
   do {
      ret = read(fd, ptr, left);
150 151 152 153
      if (ret <= 0) {
         return ret == -1 ? -errno : 0;
      }

154 155 156
      left -= ret;
      ptr += ret;
   } while (left);
157

158 159 160 161 162 163 164 165 166 167 168 169 170 171
   if (getenv("VTEST_SAVE")) {
      if (savefd == -1) {
         savefd = open(getenv("VTEST_SAVE"),
                       O_CLOEXEC|O_CREAT|O_WRONLY|O_TRUNC|O_DSYNC, S_IRUSR|S_IWUSR);
         if (savefd == -1) {
            perror("error opening save file");
            exit(1);
         }
      }
      if (write(savefd, buf, size) != size) {
         perror("failed to save");
         exit(1);
      }
   }
172

173 174 175
   return size;
}

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
static int vtest_send_fd(int socket_fd, int fd)
{
    struct iovec iovec;
    char buf[CMSG_SPACE(sizeof(int))], c;
    struct msghdr msgh = { 0 };
    memset(buf, 0, sizeof(buf));

    iovec.iov_base = &c;
    iovec.iov_len = sizeof(char);

    msgh.msg_name = NULL;
    msgh.msg_namelen = 0;
    msgh.msg_iov = &iovec;
    msgh.msg_iovlen = 1;
    msgh.msg_control = buf;
    msgh.msg_controllen = sizeof(buf);
    msgh.msg_flags = 0;

    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));

    *((int *) CMSG_DATA(cmsg)) = fd;

    int size = sendmsg(socket_fd, &msgh, 0);
    if (size < 0) {
      return report_failure("Failed to send fd", -EINVAL);
    }

    return 0;
}

209 210 211 212 213 214 215 216 217 218 219 220 221 222
int vtest_buf_read(struct vtest_input *input, void *buf, int size)
{
   struct vtest_buffer *inbuf = input->data.buffer;
   if (size > inbuf->size) {
      return 0;
   }

   memcpy(buf, inbuf->buffer, size);
   inbuf->buffer += size;
   inbuf->size -= size;

   return size;
}

223
int vtest_create_renderer(struct vtest_input *input, int out_fd, uint32_t length,
224
                          int ctx_flags, const char * render_device)
225
{
226 227 228 229
   char *vtestname;
   int ret;

   renderer.iovec_hash = util_hash_table_create(hash_func, compare_iovecs, free_iovec);
230
   renderer.input = input;
231
   renderer.out_fd = out_fd;
232
   renderer.rendernode_name = render_device;
233 234 235 236 237

   /* By default we support version 0 unless VCMD_PROTOCOL_VERSION is sent */
   renderer.protocol_version = 0;

   ret = virgl_renderer_init(&renderer,
238
         ctx_flags | VIRGL_RENDERER_THREAD_SYNC, &vtest_cbs);
239
   if (ret) {
240 241
      fprintf(stderr, "failed to initialise renderer.\n");
      return -1;
242
   }
Dave Airlie's avatar
Dave Airlie committed
243

244 245 246 247
   if (length > 1024 * 1024) {
      return -1;
   }

248 249
   vtestname = calloc(1, length + 1);
   if (!vtestname) {
250
      return -1;
251
   }
252

253
   ret = renderer.input->read(renderer.input, vtestname, length);
254 255 256 257
   if (ret != (int)length) {
      ret = -1;
      goto end;
   }
258

259
   ret = virgl_renderer_context_create(ctx_id, strlen(vtestname), vtestname);
260 261

end:
262 263
   free(vtestname);
   return ret;
264 265
}

Dave Airlie's avatar
Dave Airlie committed
266
int vtest_ping_protocol_version(UNUSED uint32_t length_dw)
267
{
268 269 270 271 272 273 274 275 276 277 278
   uint32_t hdr_buf[VTEST_HDR_SIZE];
   int ret;

   hdr_buf[VTEST_CMD_LEN] = VCMD_PING_PROTOCOL_VERSION_SIZE;
   hdr_buf[VTEST_CMD_ID] = VCMD_PING_PROTOCOL_VERSION;
   ret = vtest_block_write(renderer.out_fd, hdr_buf, sizeof(hdr_buf));
   if (ret < 0) {
      return ret;
   }

   return 0;
279 280
}

Dave Airlie's avatar
Dave Airlie committed
281
int vtest_protocol_version(UNUSED uint32_t length_dw)
282
{
283 284 285
   uint32_t hdr_buf[VTEST_HDR_SIZE];
   uint32_t version_buf[VCMD_PROTOCOL_VERSION_SIZE];
   int ret;
286

287
   ret = renderer.input->read(renderer.input, &version_buf, sizeof(version_buf));
288 289
   if (ret != sizeof(version_buf))
      return -1;
290

291 292
   renderer.protocol_version = MIN2(version_buf[VCMD_PROTOCOL_VERSION_VERSION],
                                    VTEST_PROTOCOL_VERSION);
293

294 295 296 297 298 299 300 301
   /*
    * We've deprecated protocol version 1. All of it's called sites are being
    * moved protocol version 2. If the server supports version 2 and the guest
    * supports verison 1, fall back to version 0.
    */
   if (renderer.protocol_version == 1) {
      printf("Older guest Mesa detected, fallbacking to protocol version 0\n");
      renderer.protocol_version = 0;
302 303 304 305 306 307
   }

   /* Protocol version 2 requires shm support. */
   if (!vtest_shm_check()) {
      printf("Shared memory not supported, fallbacking to protocol version 0\n");
      renderer.protocol_version = 0;
308 309
   }

310 311
   hdr_buf[VTEST_CMD_LEN] = VCMD_PROTOCOL_VERSION_SIZE;
   hdr_buf[VTEST_CMD_ID] = VCMD_PROTOCOL_VERSION;
312

313
   version_buf[VCMD_PROTOCOL_VERSION_VERSION] = renderer.protocol_version;
314

315 316
   ret = vtest_block_write(renderer.out_fd, hdr_buf, sizeof(hdr_buf));
   if (ret < 0) {
317
      return ret;
318
   }
319

320 321
   ret = vtest_block_write(renderer.out_fd, version_buf, sizeof(version_buf));
   if (ret < 0) {
322
      return ret;
323
   }
324

325
   return 0;
326 327
}

328 329
void vtest_destroy_renderer(void)
{
330 331
   virgl_renderer_context_destroy(ctx_id);
   virgl_renderer_cleanup(&renderer);
David Riley's avatar
David Riley committed
332 333
   util_hash_table_destroy(renderer.iovec_hash);
   renderer.iovec_hash = NULL;
334
   renderer.input = NULL;
335
   renderer.out_fd = -1;
336 337
}

338
int vtest_send_caps2(UNUSED uint32_t length_dw)
339
{
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
   uint32_t hdr_buf[2];
   void *caps_buf;
   int ret;
   uint32_t max_ver, max_size;

   virgl_renderer_get_cap_set(2, &max_ver, &max_size);

   if (max_size == 0) {
      return -1;
   }

   caps_buf = malloc(max_size);
   if (!caps_buf) {
      return -1;
   }

   virgl_renderer_fill_caps(2, 1, caps_buf);

   hdr_buf[0] = max_size + 1;
   hdr_buf[1] = 2;
   ret = vtest_block_write(renderer.out_fd, hdr_buf, 8);
   if (ret < 0) {
      goto end;
   }

   vtest_block_write(renderer.out_fd, caps_buf, max_size);
   if (ret < 0) {
      goto end;
   }
369 370

end:
371 372
   free(caps_buf);
   return 0;
373 374
}

375
int vtest_send_caps(UNUSED uint32_t length_dw)
376
{
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
   uint32_t  max_ver, max_size;
   void *caps_buf;
   uint32_t hdr_buf[2];
   int ret;

   virgl_renderer_get_cap_set(1, &max_ver, &max_size);

   caps_buf = malloc(max_size);
   if (!caps_buf) {
      return -1;
   }

   virgl_renderer_fill_caps(1, 1, caps_buf);

   hdr_buf[0] = max_size + 1;
   hdr_buf[1] = 1;
   ret = vtest_block_write(renderer.out_fd, hdr_buf, 8);
   if (ret < 0) {
      goto end;
   }

   vtest_block_write(renderer.out_fd, caps_buf, max_size);
   if (ret < 0) {
      goto end;
   }
402

403
end:
404 405
   free(caps_buf);
   return 0;
406
}
Dave Airlie's avatar
Dave Airlie committed
407

408
int vtest_create_resource(UNUSED uint32_t length_dw)
Dave Airlie's avatar
Dave Airlie committed
409
{
410 411 412 413
   uint32_t res_create_buf[VCMD_RES_CREATE_SIZE];
   struct virgl_renderer_resource_create_args args;
   int ret;

414 415
   ret = renderer.input->read(renderer.input, &res_create_buf,
                              sizeof(res_create_buf));
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
   if (ret != sizeof(res_create_buf)) {
      return -1;
   }

   args.handle = res_create_buf[VCMD_RES_CREATE_RES_HANDLE];
   args.target = res_create_buf[VCMD_RES_CREATE_TARGET];
   args.format = res_create_buf[VCMD_RES_CREATE_FORMAT];
   args.bind = res_create_buf[VCMD_RES_CREATE_BIND];

   args.width = res_create_buf[VCMD_RES_CREATE_WIDTH];
   args.height = res_create_buf[VCMD_RES_CREATE_HEIGHT];
   args.depth = res_create_buf[VCMD_RES_CREATE_DEPTH];
   args.array_size = res_create_buf[VCMD_RES_CREATE_ARRAY_SIZE];
   args.last_level = res_create_buf[VCMD_RES_CREATE_LAST_LEVEL];
   args.nr_samples = res_create_buf[VCMD_RES_CREATE_NR_SAMPLES];
   args.flags = 0;

   ret = virgl_renderer_resource_create(&args, NULL, 0);

   virgl_renderer_ctx_attach_resource(ctx_id, args.handle);
   return ret;
Dave Airlie's avatar
Dave Airlie committed
437 438
}

439
int vtest_create_resource2(UNUSED uint32_t length_dw)
440
{
441 442 443
   uint32_t res_create_buf[VCMD_RES_CREATE2_SIZE];
   struct virgl_renderer_resource_create_args args;
   struct iovec *iovec;
444
   int ret, fd;
445

446 447
   ret = renderer.input->read(renderer.input, &res_create_buf,
                              sizeof(res_create_buf));
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
   if (ret != sizeof(res_create_buf)) {
      return -1;
   }

   args.handle = res_create_buf[VCMD_RES_CREATE2_RES_HANDLE];
   args.target = res_create_buf[VCMD_RES_CREATE2_TARGET];
   args.format = res_create_buf[VCMD_RES_CREATE2_FORMAT];
   args.bind = res_create_buf[VCMD_RES_CREATE2_BIND];

   args.width = res_create_buf[VCMD_RES_CREATE2_WIDTH];
   args.height = res_create_buf[VCMD_RES_CREATE2_HEIGHT];
   args.depth = res_create_buf[VCMD_RES_CREATE2_DEPTH];
   args.array_size = res_create_buf[VCMD_RES_CREATE2_ARRAY_SIZE];
   args.last_level = res_create_buf[VCMD_RES_CREATE2_LAST_LEVEL];
   args.nr_samples = res_create_buf[VCMD_RES_CREATE2_NR_SAMPLES];
   args.flags = 0;

   // Check that the handle doesn't already exist.
   if (util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(args.handle))) {
467
      return -EEXIST;
468
   }
469

470
   ret = virgl_renderer_resource_create(&args, NULL, 0);
471 472
   if (ret)
      return report_failed_call("virgl_renderer_resource_create", ret);
473

474
   virgl_renderer_ctx_attach_resource(ctx_id, args.handle);
475

476 477
   iovec = CALLOC_STRUCT(iovec);
   if (!iovec) {
478
      return -ENOMEM;
479
   }
480

481
   iovec->iov_len = res_create_buf[VCMD_RES_CREATE2_DATA_SIZE];
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499

   /* Multi-sample textures have no backing store, but an associated GL resource. */
   if (iovec->iov_len == 0) {
      iovec->iov_base = NULL;
      goto out;
   }

   fd = vtest_new_shm(args.handle, iovec->iov_len);
   if (fd < 0) {
      FREE(iovec);
      return report_failed_call("vtest_new_shm", fd);
   }

   iovec->iov_base = mmap(NULL, iovec->iov_len, PROT_WRITE | PROT_READ,
                          MAP_SHARED, fd, 0);

   if (iovec->iov_base == MAP_FAILED) {
      close(fd);
500
      FREE(iovec);
501
      return -ENOMEM;
502
   }
503

504 505 506 507 508 509 510 511 512 513 514
   ret = vtest_send_fd(renderer.out_fd, fd);
   if (ret < 0) {
      close(fd);
      munmap(iovec->iov_base, iovec->iov_len);
      return report_failed_call("vtest_send_fd", ret);
   }

   /* Closing the file descriptor does not unmap the region. */
   close(fd);

out:
515 516
   virgl_renderer_resource_attach_iov(args.handle, iovec, 1);
   util_hash_table_set(renderer.iovec_hash, intptr_to_pointer(args.handle), iovec);
517
   return 0;
518 519
}

520
int vtest_resource_unref(UNUSED uint32_t length_dw)
Dave Airlie's avatar
Dave Airlie committed
521
{
522 523 524
   uint32_t res_unref_buf[VCMD_RES_UNREF_SIZE];
   int ret;
   uint32_t handle;
Dave Airlie's avatar
Dave Airlie committed
525

526 527
   ret = renderer.input->read(renderer.input, &res_unref_buf,
                              sizeof(res_unref_buf));
528
   if (ret != sizeof(res_unref_buf)) {
Dave Airlie's avatar
Dave Airlie committed
529
      return -1;
530
   }
Dave Airlie's avatar
Dave Airlie committed
531

532 533
   handle = res_unref_buf[VCMD_RES_UNREF_RES_HANDLE];
   virgl_renderer_ctx_attach_resource(ctx_id, handle);
534

535 536
   virgl_renderer_resource_detach_iov(handle, NULL, NULL);
   util_hash_table_remove(renderer.iovec_hash, intptr_to_pointer(handle));
537

538 539
   virgl_renderer_resource_unref(handle);
   return 0;
Dave Airlie's avatar
Dave Airlie committed
540
}
Dave Airlie's avatar
Dave Airlie committed
541 542 543

int vtest_submit_cmd(uint32_t length_dw)
{
544 545
   uint32_t *cbuf;
   int ret;
Dave Airlie's avatar
Dave Airlie committed
546

547
   if (length_dw > max_length / 4) {
548 549
      return -1;
   }
550

551 552 553 554
   cbuf = malloc(length_dw * 4);
   if (!cbuf) {
      return -1;
   }
Dave Airlie's avatar
Dave Airlie committed
555

556
   ret = renderer.input->read(renderer.input, cbuf, length_dw * 4);
557 558 559 560
   if (ret != (int)length_dw * 4) {
      free(cbuf);
      return -1;
   }
Dave Airlie's avatar
Dave Airlie committed
561

562
   virgl_renderer_submit_cmd(cbuf, ctx_id, length_dw);
Dave Airlie's avatar
Dave Airlie committed
563

564 565
   free(cbuf);
   return 0;
Dave Airlie's avatar
Dave Airlie committed
566
}
567 568

#define DECODE_TRANSFER \
569 570 571 572 573 574 575 576 577 578 579 580 581
   do {								\
      handle = thdr_buf[VCMD_TRANSFER_RES_HANDLE];		\
      level = thdr_buf[VCMD_TRANSFER_LEVEL];			\
      stride = thdr_buf[VCMD_TRANSFER_STRIDE];			\
      layer_stride = thdr_buf[VCMD_TRANSFER_LAYER_STRIDE];	\
      box.x = thdr_buf[VCMD_TRANSFER_X];			\
      box.y = thdr_buf[VCMD_TRANSFER_Y];			\
      box.z = thdr_buf[VCMD_TRANSFER_Z];			\
      box.w = thdr_buf[VCMD_TRANSFER_WIDTH];			\
      box.h = thdr_buf[VCMD_TRANSFER_HEIGHT];			\
      box.d = thdr_buf[VCMD_TRANSFER_DEPTH];			\
      data_size = thdr_buf[VCMD_TRANSFER_DATA_SIZE];		\
   } while(0)
582 583


584
int vtest_transfer_get(UNUSED uint32_t length_dw)
585
{
586 587 588 589 590 591 592 593 594
   uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
   int ret;
   int level;
   uint32_t stride, layer_stride, handle;
   struct virgl_box box;
   uint32_t data_size;
   void *ptr;
   struct iovec iovec;

595 596
   ret = renderer.input->read(renderer.input, thdr_buf,
                              VCMD_TRANSFER_HDR_SIZE * 4);
597
   if (ret != VCMD_TRANSFER_HDR_SIZE * 4) {
598
      return ret;
599
   }
600

601
   DECODE_TRANSFER;
602

603 604 605 606
   if (data_size > max_length) {
      return -ENOMEM;
   }

607 608
   ptr = malloc(data_size);
   if (!ptr) {
609
      return -ENOMEM;
610
   }
611

612 613 614 615 616 617 618 619 620 621 622
   iovec.iov_len = data_size;
   iovec.iov_base = ptr;
   ret = virgl_renderer_transfer_read_iov(handle,
         ctx_id,
         level,
         stride,
         layer_stride,
         &box,
         0,
         &iovec, 1);
   if (ret) {
623
      fprintf(stderr," transfer read failed %d\n", ret);
624 625 626
   }

   ret = vtest_block_write(renderer.out_fd, ptr, data_size);
627

628 629
   free(ptr);
   return ret < 0 ? ret : 0;
630 631
}

632 633 634 635
int vtest_transfer_get_nop(UNUSED uint32_t length_dw)
{
   uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
   int ret;
636 637 638
   UNUSED int level;
   UNUSED uint32_t stride, layer_stride, handle;
   UNUSED struct virgl_box box;
639 640 641 642 643 644 645 646 647 648 649
   uint32_t data_size;
   void *ptr;

   ret = renderer.input->read(renderer.input, thdr_buf,
                              VCMD_TRANSFER_HDR_SIZE * 4);
   if (ret != VCMD_TRANSFER_HDR_SIZE * 4) {
      return ret;
   }

   DECODE_TRANSFER;

650 651 652 653
   if (data_size > max_length) {
      return -ENOMEM;
   }

654 655 656 657 658 659 660 661 662 663 664 665 666
   ptr = malloc(data_size);
   if (!ptr) {
      return -ENOMEM;
   }

   memset(ptr, 0, data_size);

   ret = vtest_block_write(renderer.out_fd, ptr, data_size);

   free(ptr);
   return ret < 0 ? ret : 0;
}

667
int vtest_transfer_put(UNUSED uint32_t length_dw)
668
{
669 670 671 672 673 674 675 676 677
   uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
   int ret;
   int level;
   uint32_t stride, layer_stride, handle;
   struct virgl_box box;
   uint32_t data_size;
   void *ptr;
   struct iovec iovec;

678 679
   ret = renderer.input->read(renderer.input, thdr_buf,
                              VCMD_TRANSFER_HDR_SIZE * 4);
680
   if (ret != VCMD_TRANSFER_HDR_SIZE * 4) {
681
      return ret;
682
   }
683

684
   DECODE_TRANSFER;
685

686 687 688 689
   if (data_size > max_length) {
      return -ENOMEM;
   }

690 691
   ptr = malloc(data_size);
   if (!ptr) {
692
      return -ENOMEM;
693
   }
694

695
   ret = renderer.input->read(renderer.input, ptr, data_size);
696
   if (ret < 0) {
697
      return ret;
698
   }
699

700 701 702 703 704 705 706 707 708 709 710
   iovec.iov_len = data_size;
   iovec.iov_base = ptr;
   ret = virgl_renderer_transfer_write_iov(handle,
                                           ctx_id,
                                           level,
                                           stride,
                                           layer_stride,
                                           &box,
                                           0,
                                           &iovec, 1);
   if (ret) {
711
      fprintf(stderr," transfer write failed %d\n", ret);
712 713 714 715
   }

   free(ptr);
   return 0;
716 717
}

718 719 720 721
int vtest_transfer_put_nop(UNUSED uint32_t length_dw)
{
   uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
   int ret;
722 723 724
   UNUSED int level;
   UNUSED uint32_t stride, layer_stride, handle;
   UNUSED struct virgl_box box;
725 726 727 728 729 730 731 732 733 734 735
   uint32_t data_size;
   void *ptr;

   ret = renderer.input->read(renderer.input, thdr_buf,
                              VCMD_TRANSFER_HDR_SIZE * 4);
   if (ret != VCMD_TRANSFER_HDR_SIZE * 4) {
      return ret;
   }

   DECODE_TRANSFER;

736 737 738 739
   if (data_size > max_length) {
      return -ENOMEM;
   }

740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
   ptr = malloc(data_size);
   if (!ptr) {
      return -ENOMEM;
   }

   ret = renderer.input->read(renderer.input, ptr, data_size);
   if (ret < 0) {
      return ret;
   }

   free(ptr);
   return 0;
}


755
#define DECODE_TRANSFER2 \
756 757 758 759 760 761 762 763 764 765 766
   do {							\
      handle = thdr_buf[VCMD_TRANSFER2_RES_HANDLE];	\
      level = thdr_buf[VCMD_TRANSFER2_LEVEL];		\
      box.x = thdr_buf[VCMD_TRANSFER2_X];		\
      box.y = thdr_buf[VCMD_TRANSFER2_Y];		\
      box.z = thdr_buf[VCMD_TRANSFER2_Z];		\
      box.w = thdr_buf[VCMD_TRANSFER2_WIDTH];		\
      box.h = thdr_buf[VCMD_TRANSFER2_HEIGHT];		\
      box.d = thdr_buf[VCMD_TRANSFER2_DEPTH];		\
      offset = thdr_buf[VCMD_TRANSFER2_OFFSET];		\
   } while(0)
767 768


769
int vtest_transfer_get2(UNUSED uint32_t length_dw)
770
{
771 772 773 774 775 776 777 778
   uint32_t thdr_buf[VCMD_TRANSFER2_HDR_SIZE];
   int ret;
   int level;
   uint32_t handle;
   struct virgl_box box;
   uint32_t offset;
   struct iovec *iovec;

779
   ret = renderer.input->read(renderer.input, thdr_buf, sizeof(thdr_buf));
780
   if (ret != sizeof(thdr_buf)) {
781
      return ret;
782
   }
783

784
   DECODE_TRANSFER2;
785

786 787
   iovec = util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(handle));
   if (!iovec) {
788
      return report_failed_call("util_hash_table_get", -ESRCH);
789
   }
790

791
   if (offset >= iovec->iov_len) {
792
      return report_failure("offset larger then length of backing store", -EFAULT);
793 794 795 796 797 798 799 800 801 802 803
   }

   ret = virgl_renderer_transfer_read_iov(handle,
                                          ctx_id,
                                          level,
                                          0,
                                          0,
                                          &box,
                                          offset,
                                          NULL, 0);
   if (ret) {
804
      return report_failed_call("virgl_renderer_transfer_read_iov", ret);
805
   }
806

807
   return 0;
808 809
}

810 811 812 813
int vtest_transfer_get2_nop(UNUSED uint32_t length_dw)
{
   uint32_t thdr_buf[VCMD_TRANSFER2_HDR_SIZE];
   int ret;
814
   UNUSED int level;
815
   uint32_t handle;
816
   UNUSED struct virgl_box box;
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
   uint32_t offset;
   struct iovec *iovec;

   ret = renderer.input->read(renderer.input, thdr_buf, sizeof(thdr_buf));
   if (ret != sizeof(thdr_buf)) {
      return ret;
   }

   DECODE_TRANSFER2;

   iovec = util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(handle));
   if (!iovec) {
      return report_failed_call("util_hash_table_get", -ESRCH);
   }

   if (offset >= iovec->iov_len) {
      return report_failure("offset larger then length of backing store", -EFAULT);
   }

   return 0;
}

839
int vtest_transfer_put2(UNUSED uint32_t length_dw)
840
{
841 842 843 844 845
   uint32_t thdr_buf[VCMD_TRANSFER2_HDR_SIZE];
   int ret;
   int level;
   uint32_t handle;
   struct virgl_box box;
846
   UNUSED uint32_t data_size;
847 848 849
   uint32_t offset;
   struct iovec *iovec;

850
   ret = renderer.input->read(renderer.input, thdr_buf, sizeof(thdr_buf));
851
   if (ret != sizeof(thdr_buf)) {
852
      return ret;
853
   }
854

855
   DECODE_TRANSFER2;
856

857 858
   iovec = util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(handle));
   if (!iovec) {
859
      return report_failed_call("util_hash_table_get", -ESRCH);
860
   }
861

862 863 864 865 866 867 868 869 870
   ret = virgl_renderer_transfer_write_iov(handle,
                                           ctx_id,
                                           level,
                                           0,
                                           0,
                                           &box,
                                           offset,
                                           NULL, 0);
   if (ret) {
871
      return report_failed_call("virgl_renderer_transfer_write_iov", ret);
872
   }
873

874
   return 0;
875 876
}

877 878 879 880
int vtest_transfer_put2_nop(UNUSED uint32_t length_dw)
{
   uint32_t thdr_buf[VCMD_TRANSFER2_HDR_SIZE];
   int ret;
881
   UNUSED int level;
882
   uint32_t handle;
883
   UNUSED struct virgl_box box;
884
   UNUSED uint32_t data_size;
885
   UNUSED uint32_t offset;
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
   struct iovec *iovec;

   ret = renderer.input->read(renderer.input, thdr_buf, sizeof(thdr_buf));
   if (ret != sizeof(thdr_buf)) {
      return ret;
   }

   DECODE_TRANSFER2;

   iovec = util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(handle));
   if (!iovec) {
      return report_failed_call("util_hash_table_get", -ESRCH);
   }

   return 0;
}

903
int vtest_resource_busy_wait(UNUSED uint32_t length_dw)
904
{
905 906 907 908 909 910 911
   uint32_t bw_buf[VCMD_BUSY_WAIT_SIZE];
   int ret, fd;
   int flags;
   uint32_t hdr_buf[VTEST_HDR_SIZE];
   uint32_t reply_buf[1];
   bool busy = false;

912
   ret = renderer.input->read(renderer.input, &bw_buf, sizeof(bw_buf));
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
   if (ret != sizeof(bw_buf)) {
      return -1;
   }

   /*  handle = bw_buf[VCMD_BUSY_WAIT_HANDLE]; unused as of now */
   flags = bw_buf[VCMD_BUSY_WAIT_FLAGS];

   if (flags == VCMD_BUSY_WAIT_FLAG_WAIT) {
      do {
         if (last_fence == (fence_id - 1)) {
            break;
         }

         fd = virgl_renderer_get_poll_fd();
         if (fd != -1) {
            vtest_wait_for_fd_read(fd);
         }

         virgl_renderer_poll();
      } while (1);

      busy = false;
   } else {
      busy = last_fence != (fence_id - 1);
   }

   hdr_buf[VTEST_CMD_LEN] = 1;
   hdr_buf[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;
   reply_buf[0] = busy ? 1 : 0;

   ret = vtest_block_write(renderer.out_fd, hdr_buf, sizeof(hdr_buf));
   if (ret < 0) {
      return ret;
   }

   ret = vtest_block_write(renderer.out_fd, reply_buf, sizeof(reply_buf));
   if (ret < 0) {
      return ret;
   }

   return 0;
954 955 956 957
}

int vtest_renderer_create_fence(void)
{
958 959
   virgl_renderer_create_fence(fence_id++, ctx_id);
   return 0;
960 961 962 963
}

int vtest_poll(void)
{
964 965
   virgl_renderer_poll();
   return 0;
966
}
967 968 969 970 971

void vtest_set_max_length(uint32_t length)
{
   max_length = length;
}