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