1/* 2 * Copyright 2014, 2015 Red Hat. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23#include <stdio.h> 24#include "util/u_surface.h" 25#include "util/u_memory.h" 26#include "util/u_format.h" 27#include "util/u_inlines.h" 28#include "util/os_time.h" 29#include "state_tracker/sw_winsys.h" 30#include "os/os_mman.h" 31 32#include "virgl_vtest_winsys.h" 33#include "virgl_vtest_public.h" 34 35static void *virgl_vtest_resource_map(struct virgl_winsys *vws, 36 struct virgl_hw_res *res); 37static void virgl_vtest_resource_unmap(struct virgl_winsys *vws, 38 struct virgl_hw_res *res); 39 40static inline boolean can_cache_resource(struct virgl_hw_res *res) 41{ 42 return res->cacheable == TRUE; 43} 44 45static uint32_t vtest_get_transfer_size(struct virgl_hw_res *res, 46 const struct pipe_box *box, 47 uint32_t stride, uint32_t layer_stride, 48 uint32_t level, uint32_t *valid_stride_p) 49{ 50 uint32_t valid_stride, valid_layer_stride; 51 52 valid_stride = util_format_get_stride(res->format, box->width); 53 if (stride) { 54 if (box->height > 1) 55 valid_stride = stride; 56 } 57 58 valid_layer_stride = util_format_get_2d_size(res->format, valid_stride, 59 box->height); 60 if (layer_stride) { 61 if (box->depth > 1) 62 valid_layer_stride = layer_stride; 63 } 64 65 *valid_stride_p = valid_stride; 66 return valid_layer_stride * box->depth; 67} 68 69static int 70virgl_vtest_transfer_put(struct virgl_winsys *vws, 71 struct virgl_hw_res *res, 72 const struct pipe_box *box, 73 uint32_t stride, uint32_t layer_stride, 74 uint32_t buf_offset, uint32_t level) 75{ 76 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 77 uint32_t size; 78 void *ptr; 79 uint32_t valid_stride; 80 81 size = vtest_get_transfer_size(res, box, stride, layer_stride, level, 82 &valid_stride); 83 84 virgl_vtest_send_transfer_put(vtws, res->res_handle, 85 level, stride, layer_stride, 86 box, size, buf_offset); 87 88 if (vtws->protocol_version >= 2) 89 return 0; 90 91 ptr = virgl_vtest_resource_map(vws, res); 92 virgl_vtest_send_transfer_put_data(vtws, ptr + buf_offset, size); 93 virgl_vtest_resource_unmap(vws, res); 94 return 0; 95} 96 97static int 98virgl_vtest_transfer_get_internal(struct virgl_winsys *vws, 99 struct virgl_hw_res *res, 100 const struct pipe_box *box, 101 uint32_t stride, uint32_t layer_stride, 102 uint32_t buf_offset, uint32_t level, 103 bool flush_front_buffer) 104{ 105 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 106 uint32_t size; 107 void *ptr; 108 uint32_t valid_stride; 109 110 size = vtest_get_transfer_size(res, box, stride, layer_stride, level, 111 &valid_stride); 112 virgl_vtest_send_transfer_get(vtws, res->res_handle, 113 level, stride, layer_stride, 114 box, size, buf_offset); 115 116 if (flush_front_buffer || vtws->protocol_version >= 2) 117 virgl_vtest_busy_wait(vtws, res->res_handle, VCMD_BUSY_WAIT_FLAG_WAIT); 118 119 if (vtws->protocol_version >= 2) { 120 if (flush_front_buffer) { 121 if (box->depth > 1 || box->z > 1) { 122 fprintf(stderr, "Expected a 2D resource, received a 3D resource\n"); 123 return -1; 124 } 125 126 void *dt_map; 127 uint32_t shm_stride; 128 129 /* 130 * The display target is aligned to 64 bytes, while the shared resource 131 * between the client/server is not. 132 */ 133 shm_stride = util_format_get_stride(res->format, res->width); 134 ptr = virgl_vtest_resource_map(vws, res); 135 dt_map = vtws->sws->displaytarget_map(vtws->sws, res->dt, 0); 136 137 util_copy_rect(dt_map, res->format, res->stride, box->x, box->y, 138 box->width, box->height, ptr, shm_stride, box->x, 139 box->y); 140 141 virgl_vtest_resource_unmap(vws, res); 142 vtws->sws->displaytarget_unmap(vtws->sws, res->dt); 143 } 144 } else { 145 ptr = virgl_vtest_resource_map(vws, res); 146 virgl_vtest_recv_transfer_get_data(vtws, ptr + buf_offset, size, 147 valid_stride, box, res->format); 148 virgl_vtest_resource_unmap(vws, res); 149 } 150 151 return 0; 152} 153 154static int 155virgl_vtest_transfer_get(struct virgl_winsys *vws, 156 struct virgl_hw_res *res, 157 const struct pipe_box *box, 158 uint32_t stride, uint32_t layer_stride, 159 uint32_t buf_offset, uint32_t level) 160{ 161 return virgl_vtest_transfer_get_internal(vws, res, box, stride, 162 layer_stride, buf_offset, 163 level, false); 164} 165 166static void virgl_hw_res_destroy(struct virgl_vtest_winsys *vtws, 167 struct virgl_hw_res *res) 168{ 169 virgl_vtest_send_resource_unref(vtws, res->res_handle); 170 if (res->dt) 171 vtws->sws->displaytarget_destroy(vtws->sws, res->dt); 172 if (vtws->protocol_version >= 2) { 173 if (res->ptr) 174 os_munmap(res->ptr, res->size); 175 } else { 176 free(res->ptr); 177 } 178 179 FREE(res); 180} 181 182static boolean virgl_vtest_resource_is_busy(struct virgl_vtest_winsys *vtws, 183 struct virgl_hw_res *res) 184{ 185 /* implement busy check */ 186 int ret; 187 ret = virgl_vtest_busy_wait(vtws, res->res_handle, 0); 188 189 if (ret < 0) 190 return FALSE; 191 192 return ret == 1 ? TRUE : FALSE; 193} 194 195static void 196virgl_cache_flush(struct virgl_vtest_winsys *vtws) 197{ 198 struct list_head *curr, *next; 199 struct virgl_hw_res *res; 200 201 mtx_lock(&vtws->mutex); 202 curr = vtws->delayed.next; 203 next = curr->next; 204 205 while (curr != &vtws->delayed) { 206 res = LIST_ENTRY(struct virgl_hw_res, curr, head); 207 LIST_DEL(&res->head); 208 virgl_hw_res_destroy(vtws, res); 209 curr = next; 210 next = curr->next; 211 } 212 mtx_unlock(&vtws->mutex); 213} 214 215static void 216virgl_cache_list_check_free(struct virgl_vtest_winsys *vtws) 217{ 218 struct list_head *curr, *next; 219 struct virgl_hw_res *res; 220 int64_t now; 221 222 now = os_time_get(); 223 curr = vtws->delayed.next; 224 next = curr->next; 225 while (curr != &vtws->delayed) { 226 res = LIST_ENTRY(struct virgl_hw_res, curr, head); 227 if (!os_time_timeout(res->start, res->end, now)) 228 break; 229 230 LIST_DEL(&res->head); 231 virgl_hw_res_destroy(vtws, res); 232 curr = next; 233 next = curr->next; 234 } 235} 236 237static void virgl_vtest_resource_reference(struct virgl_vtest_winsys *vtws, 238 struct virgl_hw_res **dres, 239 struct virgl_hw_res *sres) 240{ 241 struct virgl_hw_res *old = *dres; 242 if (pipe_reference(&(*dres)->reference, &sres->reference)) { 243 if (!can_cache_resource(old)) { 244 virgl_hw_res_destroy(vtws, old); 245 } else { 246 mtx_lock(&vtws->mutex); 247 virgl_cache_list_check_free(vtws); 248 249 old->start = os_time_get(); 250 old->end = old->start + vtws->usecs; 251 LIST_ADDTAIL(&old->head, &vtws->delayed); 252 vtws->num_delayed++; 253 mtx_unlock(&vtws->mutex); 254 } 255 } 256 *dres = sres; 257} 258 259static struct virgl_hw_res * 260virgl_vtest_winsys_resource_create(struct virgl_winsys *vws, 261 enum pipe_texture_target target, 262 uint32_t format, 263 uint32_t bind, 264 uint32_t width, 265 uint32_t height, 266 uint32_t depth, 267 uint32_t array_size, 268 uint32_t last_level, 269 uint32_t nr_samples, 270 uint32_t size) 271{ 272 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 273 struct virgl_hw_res *res; 274 static int handle = 1; 275 int fd = -1; 276 277 res = CALLOC_STRUCT(virgl_hw_res); 278 if (!res) 279 return NULL; 280 281 if (bind & (VIRGL_BIND_DISPLAY_TARGET | VIRGL_BIND_SCANOUT)) { 282 res->dt = vtws->sws->displaytarget_create(vtws->sws, bind, format, 283 width, height, 64, NULL, 284 &res->stride); 285 286 } else if (vtws->protocol_version < 2) { 287 res->ptr = align_malloc(size, 64); 288 if (!res->ptr) { 289 FREE(res); 290 return NULL; 291 } 292 } 293 294 res->bind = bind; 295 res->format = format; 296 res->height = height; 297 res->width = width; 298 res->size = size; 299 virgl_vtest_send_resource_create(vtws, handle, target, format, bind, 300 width, height, depth, array_size, 301 last_level, nr_samples, size, &fd); 302 303 if (vtws->protocol_version >= 2) { 304 if (res->size == 0) { 305 res->ptr = NULL; 306 goto out; 307 } 308 309 if (fd < 0) { 310 FREE(res); 311 fprintf(stderr, "Unable to get a valid fd\n"); 312 return NULL; 313 } 314 315 res->ptr = os_mmap(NULL, res->size, PROT_WRITE | PROT_READ, MAP_SHARED, 316 fd, 0); 317 318 if (res->ptr == MAP_FAILED) { 319 fprintf(stderr, "Client failed to map shared memory region\n"); 320 close(fd); 321 FREE(res); 322 return NULL; 323 } 324 325 close(fd); 326 } 327 328out: 329 res->res_handle = handle++; 330 pipe_reference_init(&res->reference, 1); 331 p_atomic_set(&res->num_cs_references, 0); 332 return res; 333} 334 335static void virgl_vtest_winsys_resource_unref(struct virgl_winsys *vws, 336 struct virgl_hw_res *hres) 337{ 338 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 339 virgl_vtest_resource_reference(vtws, &hres, NULL); 340} 341 342static void *virgl_vtest_resource_map(struct virgl_winsys *vws, 343 struct virgl_hw_res *res) 344{ 345 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 346 347 /* 348 * With protocol v0 we can either have a display target or a resource backing 349 * store. With protocol v2 we can have both, so only return the memory mapped 350 * backing store in this function. We can copy to the display target when 351 * appropriate. 352 */ 353 if (vtws->protocol_version >= 2 || !res->dt) { 354 res->mapped = res->ptr; 355 return res->mapped; 356 } else { 357 return vtws->sws->displaytarget_map(vtws->sws, res->dt, 0); 358 } 359} 360 361static void virgl_vtest_resource_unmap(struct virgl_winsys *vws, 362 struct virgl_hw_res *res) 363{ 364 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 365 if (res->mapped) 366 res->mapped = NULL; 367 368 if (res->dt && vtws->protocol_version < 2) 369 vtws->sws->displaytarget_unmap(vtws->sws, res->dt); 370} 371 372static void virgl_vtest_resource_wait(struct virgl_winsys *vws, 373 struct virgl_hw_res *res) 374{ 375 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 376 377 virgl_vtest_busy_wait(vtws, res->res_handle, VCMD_BUSY_WAIT_FLAG_WAIT); 378} 379 380static inline int virgl_is_res_compat(struct virgl_vtest_winsys *vtws, 381 struct virgl_hw_res *res, 382 uint32_t size, uint32_t bind, 383 uint32_t format) 384{ 385 if (res->bind != bind) 386 return 0; 387 if (res->format != format) 388 return 0; 389 if (res->size < size) 390 return 0; 391 if (res->size > size * 2) 392 return 0; 393 394 if (virgl_vtest_resource_is_busy(vtws, res)) { 395 return -1; 396 } 397 398 return 1; 399} 400 401static struct virgl_hw_res * 402virgl_vtest_winsys_resource_cache_create(struct virgl_winsys *vws, 403 enum pipe_texture_target target, 404 uint32_t format, 405 uint32_t bind, 406 uint32_t width, 407 uint32_t height, 408 uint32_t depth, 409 uint32_t array_size, 410 uint32_t last_level, 411 uint32_t nr_samples, 412 uint32_t size) 413{ 414 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 415 struct virgl_hw_res *res, *curr_res; 416 struct list_head *curr, *next; 417 int64_t now; 418 int ret = -1; 419 420 /* only store binds for vertex/index/const buffers */ 421 if (bind != VIRGL_BIND_CONSTANT_BUFFER && bind != VIRGL_BIND_INDEX_BUFFER && 422 bind != VIRGL_BIND_VERTEX_BUFFER && bind != VIRGL_BIND_CUSTOM) 423 goto alloc; 424 425 mtx_lock(&vtws->mutex); 426 427 res = NULL; 428 curr = vtws->delayed.next; 429 next = curr->next; 430 431 now = os_time_get(); 432 while (curr != &vtws->delayed) { 433 curr_res = LIST_ENTRY(struct virgl_hw_res, curr, head); 434 435 if (!res && ((ret = virgl_is_res_compat(vtws, curr_res, size, bind, format)) > 0)) 436 res = curr_res; 437 else if (os_time_timeout(curr_res->start, curr_res->end, now)) { 438 LIST_DEL(&curr_res->head); 439 virgl_hw_res_destroy(vtws, curr_res); 440 } else 441 break; 442 443 if (ret == -1) 444 break; 445 446 curr = next; 447 next = curr->next; 448 } 449 450 if (!res && ret != -1) { 451 while (curr != &vtws->delayed) { 452 curr_res = LIST_ENTRY(struct virgl_hw_res, curr, head); 453 ret = virgl_is_res_compat(vtws, curr_res, size, bind, format); 454 if (ret > 0) { 455 res = curr_res; 456 break; 457 } 458 if (ret == -1) 459 break; 460 curr = next; 461 next = curr->next; 462 } 463 } 464 465 if (res) { 466 LIST_DEL(&res->head); 467 --vtws->num_delayed; 468 mtx_unlock(&vtws->mutex); 469 pipe_reference_init(&res->reference, 1); 470 return res; 471 } 472 473 mtx_unlock(&vtws->mutex); 474 475alloc: 476 res = virgl_vtest_winsys_resource_create(vws, target, format, bind, 477 width, height, depth, array_size, 478 last_level, nr_samples, size); 479 if (bind == VIRGL_BIND_CONSTANT_BUFFER || bind == VIRGL_BIND_INDEX_BUFFER || 480 bind == VIRGL_BIND_VERTEX_BUFFER) 481 res->cacheable = TRUE; 482 return res; 483} 484 485static boolean virgl_vtest_lookup_res(struct virgl_vtest_cmd_buf *cbuf, 486 struct virgl_hw_res *res) 487{ 488 unsigned hash = res->res_handle & (sizeof(cbuf->is_handle_added)-1); 489 int i; 490 491 if (cbuf->is_handle_added[hash]) { 492 i = cbuf->reloc_indices_hashlist[hash]; 493 if (cbuf->res_bo[i] == res) 494 return true; 495 496 for (i = 0; i < cbuf->cres; i++) { 497 if (cbuf->res_bo[i] == res) { 498 cbuf->reloc_indices_hashlist[hash] = i; 499 return true; 500 } 501 } 502 } 503 return false; 504} 505 506static void virgl_vtest_release_all_res(struct virgl_vtest_winsys *vtws, 507 struct virgl_vtest_cmd_buf *cbuf) 508{ 509 int i; 510 511 for (i = 0; i < cbuf->cres; i++) { 512 p_atomic_dec(&cbuf->res_bo[i]->num_cs_references); 513 virgl_vtest_resource_reference(vtws, &cbuf->res_bo[i], NULL); 514 } 515 cbuf->cres = 0; 516} 517 518static void virgl_vtest_add_res(struct virgl_vtest_winsys *vtws, 519 struct virgl_vtest_cmd_buf *cbuf, 520 struct virgl_hw_res *res) 521{ 522 unsigned hash = res->res_handle & (sizeof(cbuf->is_handle_added)-1); 523 524 if (cbuf->cres >= cbuf->nres) { 525 unsigned new_nres = cbuf->nres + 256; 526 struct virgl_hw_res **new_re_bo = REALLOC(cbuf->res_bo, 527 cbuf->nres * sizeof(struct virgl_hw_buf*), 528 new_nres * sizeof(struct virgl_hw_buf*)); 529 if (!new_re_bo) { 530 fprintf(stderr,"failure to add relocation %d, %d\n", cbuf->cres, cbuf->nres); 531 return; 532 } 533 534 cbuf->res_bo = new_re_bo; 535 cbuf->nres = new_nres; 536 } 537 538 cbuf->res_bo[cbuf->cres] = NULL; 539 virgl_vtest_resource_reference(vtws, &cbuf->res_bo[cbuf->cres], res); 540 cbuf->is_handle_added[hash] = TRUE; 541 542 cbuf->reloc_indices_hashlist[hash] = cbuf->cres; 543 p_atomic_inc(&res->num_cs_references); 544 cbuf->cres++; 545} 546 547static struct virgl_cmd_buf *virgl_vtest_cmd_buf_create(struct virgl_winsys *vws, 548 uint32_t size) 549{ 550 struct virgl_vtest_cmd_buf *cbuf; 551 552 cbuf = CALLOC_STRUCT(virgl_vtest_cmd_buf); 553 if (!cbuf) 554 return NULL; 555 556 cbuf->nres = 512; 557 cbuf->res_bo = CALLOC(cbuf->nres, sizeof(struct virgl_hw_buf*)); 558 if (!cbuf->res_bo) { 559 FREE(cbuf); 560 return NULL; 561 } 562 563 cbuf->buf = CALLOC(size, sizeof(uint32_t)); 564 if (!cbuf->buf) { 565 FREE(cbuf->res_bo); 566 FREE(cbuf); 567 return NULL; 568 } 569 570 cbuf->ws = vws; 571 cbuf->base.buf = cbuf->buf; 572 return &cbuf->base; 573} 574 575static void virgl_vtest_cmd_buf_destroy(struct virgl_cmd_buf *_cbuf) 576{ 577 struct virgl_vtest_cmd_buf *cbuf = virgl_vtest_cmd_buf(_cbuf); 578 579 virgl_vtest_release_all_res(virgl_vtest_winsys(cbuf->ws), cbuf); 580 FREE(cbuf->res_bo); 581 FREE(cbuf->buf); 582 FREE(cbuf); 583} 584 585static struct pipe_fence_handle * 586virgl_vtest_fence_create(struct virgl_winsys *vws) 587{ 588 struct virgl_hw_res *res; 589 590 res = virgl_vtest_winsys_resource_cache_create(vws, 591 PIPE_BUFFER, 592 PIPE_FORMAT_R8_UNORM, 593 VIRGL_BIND_CUSTOM, 594 8, 1, 1, 0, 0, 0, 8); 595 596 return (struct pipe_fence_handle *)res; 597} 598 599static int virgl_vtest_winsys_submit_cmd(struct virgl_winsys *vws, 600 struct virgl_cmd_buf *_cbuf, 601 struct pipe_fence_handle **fence) 602{ 603 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 604 struct virgl_vtest_cmd_buf *cbuf = virgl_vtest_cmd_buf(_cbuf); 605 int ret; 606 607 if (cbuf->base.cdw == 0) 608 return 0; 609 610 ret = virgl_vtest_submit_cmd(vtws, cbuf); 611 if (fence && ret == 0) 612 *fence = virgl_vtest_fence_create(vws); 613 614 virgl_vtest_release_all_res(vtws, cbuf); 615 memset(cbuf->is_handle_added, 0, sizeof(cbuf->is_handle_added)); 616 cbuf->base.cdw = 0; 617 return ret; 618} 619 620static void virgl_vtest_emit_res(struct virgl_winsys *vws, 621 struct virgl_cmd_buf *_cbuf, 622 struct virgl_hw_res *res, boolean write_buf) 623{ 624 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 625 struct virgl_vtest_cmd_buf *cbuf = virgl_vtest_cmd_buf(_cbuf); 626 boolean already_in_list = virgl_vtest_lookup_res(cbuf, res); 627 628 if (write_buf) 629 cbuf->base.buf[cbuf->base.cdw++] = res->res_handle; 630 if (!already_in_list) 631 virgl_vtest_add_res(vtws, cbuf, res); 632} 633 634static boolean virgl_vtest_res_is_ref(struct virgl_winsys *vws, 635 struct virgl_cmd_buf *_cbuf, 636 struct virgl_hw_res *res) 637{ 638 if (!p_atomic_read(&res->num_cs_references)) 639 return FALSE; 640 641 return TRUE; 642} 643 644static int virgl_vtest_get_caps(struct virgl_winsys *vws, 645 struct virgl_drm_caps *caps) 646{ 647 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 648 649 virgl_ws_fill_new_caps_defaults(caps); 650 return virgl_vtest_send_get_caps(vtws, caps); 651} 652 653static struct pipe_fence_handle * 654virgl_cs_create_fence(struct virgl_winsys *vws, int fd) 655{ 656 return virgl_vtest_fence_create(vws); 657} 658 659static bool virgl_fence_wait(struct virgl_winsys *vws, 660 struct pipe_fence_handle *fence, 661 uint64_t timeout) 662{ 663 struct virgl_vtest_winsys *vdws = virgl_vtest_winsys(vws); 664 struct virgl_hw_res *res = virgl_hw_res(fence); 665 666 if (timeout == 0) 667 return !virgl_vtest_resource_is_busy(vdws, res); 668 669 if (timeout != PIPE_TIMEOUT_INFINITE) { 670 int64_t start_time = os_time_get(); 671 timeout /= 1000; 672 while (virgl_vtest_resource_is_busy(vdws, res)) { 673 if (os_time_get() - start_time >= timeout) 674 return FALSE; 675 os_time_sleep(10); 676 } 677 return TRUE; 678 } 679 virgl_vtest_resource_wait(vws, res); 680 return TRUE; 681} 682 683static void virgl_fence_reference(struct virgl_winsys *vws, 684 struct pipe_fence_handle **dst, 685 struct pipe_fence_handle *src) 686{ 687 struct virgl_vtest_winsys *vdws = virgl_vtest_winsys(vws); 688 virgl_vtest_resource_reference(vdws, (struct virgl_hw_res **)dst, 689 virgl_hw_res(src)); 690} 691 692static void virgl_vtest_flush_frontbuffer(struct virgl_winsys *vws, 693 struct virgl_hw_res *res, 694 unsigned level, unsigned layer, 695 void *winsys_drawable_handle, 696 struct pipe_box *sub_box) 697{ 698 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 699 struct pipe_box box; 700 uint32_t offset = 0; 701 if (!res->dt) 702 return; 703 704 memset(&box, 0, sizeof(box)); 705 706 if (sub_box) { 707 box = *sub_box; 708 offset = box.y / util_format_get_blockheight(res->format) * res->stride + 709 box.x / util_format_get_blockwidth(res->format) * util_format_get_blocksize(res->format); 710 } else { 711 box.z = layer; 712 box.width = res->width; 713 box.height = res->height; 714 box.depth = 1; 715 } 716 717 virgl_vtest_transfer_get_internal(vws, res, &box, res->stride, 0, offset, 718 level, true); 719 720 vtws->sws->displaytarget_display(vtws->sws, res->dt, winsys_drawable_handle, 721 sub_box); 722} 723 724static void 725virgl_vtest_winsys_destroy(struct virgl_winsys *vws) 726{ 727 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); 728 729 virgl_cache_flush(vtws); 730 731 mtx_destroy(&vtws->mutex); 732 FREE(vtws); 733} 734 735struct virgl_winsys * 736virgl_vtest_winsys_wrap(struct sw_winsys *sws) 737{ 738 struct virgl_vtest_winsys *vtws; 739 740 vtws = CALLOC_STRUCT(virgl_vtest_winsys); 741 if (!vtws) 742 return NULL; 743 744 virgl_vtest_connect(vtws); 745 vtws->sws = sws; 746 747 vtws->usecs = 1000000; 748 LIST_INITHEAD(&vtws->delayed); 749 (void) mtx_init(&vtws->mutex, mtx_plain); 750 751 vtws->base.destroy = virgl_vtest_winsys_destroy; 752 753 vtws->base.transfer_put = virgl_vtest_transfer_put; 754 vtws->base.transfer_get = virgl_vtest_transfer_get; 755 756 vtws->base.resource_create = virgl_vtest_winsys_resource_cache_create; 757 vtws->base.resource_unref = virgl_vtest_winsys_resource_unref; 758 vtws->base.resource_map = virgl_vtest_resource_map; 759 vtws->base.resource_wait = virgl_vtest_resource_wait; 760 vtws->base.cmd_buf_create = virgl_vtest_cmd_buf_create; 761 vtws->base.cmd_buf_destroy = virgl_vtest_cmd_buf_destroy; 762 vtws->base.submit_cmd = virgl_vtest_winsys_submit_cmd; 763 764 vtws->base.emit_res = virgl_vtest_emit_res; 765 vtws->base.res_is_referenced = virgl_vtest_res_is_ref; 766 vtws->base.get_caps = virgl_vtest_get_caps; 767 768 vtws->base.cs_create_fence = virgl_cs_create_fence; 769 vtws->base.fence_wait = virgl_fence_wait; 770 vtws->base.fence_reference = virgl_fence_reference; 771 vtws->base.supports_fences = 0; 772 vtws->base.supports_encoded_transfers = (vtws->protocol_version >= 2); 773 774 vtws->base.flush_frontbuffer = virgl_vtest_flush_frontbuffer; 775 776 return &vtws->base; 777} 778