687f4f3052825167177fe6a6fecadf8fac776ace
[mesa.git] / src / gallium / winsys / virgl / vtest / virgl_vtest_winsys.c
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
35 static void *virgl_vtest_resource_map(struct virgl_winsys *vws,
36 struct virgl_hw_res *res);
37 static void virgl_vtest_resource_unmap(struct virgl_winsys *vws,
38 struct virgl_hw_res *res);
39
40 static inline boolean can_cache_resource(struct virgl_hw_res *res)
41 {
42 return res->cacheable == TRUE;
43 }
44
45 static 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
69 static int
70 virgl_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
97 static int
98 virgl_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
154 static int
155 virgl_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
166 static 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
182 static 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
195 static void
196 virgl_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
215 static void
216 virgl_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
237 static 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
259 static struct virgl_hw_res *
260 virgl_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
328 out:
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
335 static 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
342 static 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
361 static 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
372 static 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
380 static 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
401 static struct virgl_hw_res *
402 virgl_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
475 alloc:
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
485 static 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
506 static 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
518 static 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
547 static 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 cbuf->ws = vws;
563 cbuf->base.buf = cbuf->buf;
564 return &cbuf->base;
565 }
566
567 static void virgl_vtest_cmd_buf_destroy(struct virgl_cmd_buf *_cbuf)
568 {
569 struct virgl_vtest_cmd_buf *cbuf = virgl_vtest_cmd_buf(_cbuf);
570
571 virgl_vtest_release_all_res(virgl_vtest_winsys(cbuf->ws), cbuf);
572 FREE(cbuf->res_bo);
573 FREE(cbuf);
574 }
575
576 static struct pipe_fence_handle *
577 virgl_vtest_fence_create(struct virgl_winsys *vws)
578 {
579 struct virgl_hw_res *res;
580
581 res = virgl_vtest_winsys_resource_cache_create(vws,
582 PIPE_BUFFER,
583 PIPE_FORMAT_R8_UNORM,
584 VIRGL_BIND_CUSTOM,
585 8, 1, 1, 0, 0, 0, 8);
586
587 return (struct pipe_fence_handle *)res;
588 }
589
590 static int virgl_vtest_winsys_submit_cmd(struct virgl_winsys *vws,
591 struct virgl_cmd_buf *_cbuf,
592 struct pipe_fence_handle **fence)
593 {
594 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws);
595 struct virgl_vtest_cmd_buf *cbuf = virgl_vtest_cmd_buf(_cbuf);
596 int ret;
597
598 if (cbuf->base.cdw == 0)
599 return 0;
600
601 ret = virgl_vtest_submit_cmd(vtws, cbuf);
602 if (fence && ret == 0)
603 *fence = virgl_vtest_fence_create(vws);
604
605 virgl_vtest_release_all_res(vtws, cbuf);
606 memset(cbuf->is_handle_added, 0, sizeof(cbuf->is_handle_added));
607 cbuf->base.cdw = 0;
608 return ret;
609 }
610
611 static void virgl_vtest_emit_res(struct virgl_winsys *vws,
612 struct virgl_cmd_buf *_cbuf,
613 struct virgl_hw_res *res, boolean write_buf)
614 {
615 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws);
616 struct virgl_vtest_cmd_buf *cbuf = virgl_vtest_cmd_buf(_cbuf);
617 boolean already_in_list = virgl_vtest_lookup_res(cbuf, res);
618
619 if (write_buf)
620 cbuf->base.buf[cbuf->base.cdw++] = res->res_handle;
621 if (!already_in_list)
622 virgl_vtest_add_res(vtws, cbuf, res);
623 }
624
625 static boolean virgl_vtest_res_is_ref(struct virgl_winsys *vws,
626 struct virgl_cmd_buf *_cbuf,
627 struct virgl_hw_res *res)
628 {
629 if (!p_atomic_read(&res->num_cs_references))
630 return FALSE;
631
632 return TRUE;
633 }
634
635 static int virgl_vtest_get_caps(struct virgl_winsys *vws,
636 struct virgl_drm_caps *caps)
637 {
638 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws);
639
640 virgl_ws_fill_new_caps_defaults(caps);
641 return virgl_vtest_send_get_caps(vtws, caps);
642 }
643
644 static struct pipe_fence_handle *
645 virgl_cs_create_fence(struct virgl_winsys *vws, int fd)
646 {
647 return virgl_vtest_fence_create(vws);
648 }
649
650 static bool virgl_fence_wait(struct virgl_winsys *vws,
651 struct pipe_fence_handle *fence,
652 uint64_t timeout)
653 {
654 struct virgl_vtest_winsys *vdws = virgl_vtest_winsys(vws);
655 struct virgl_hw_res *res = virgl_hw_res(fence);
656
657 if (timeout == 0)
658 return !virgl_vtest_resource_is_busy(vdws, res);
659
660 if (timeout != PIPE_TIMEOUT_INFINITE) {
661 int64_t start_time = os_time_get();
662 timeout /= 1000;
663 while (virgl_vtest_resource_is_busy(vdws, res)) {
664 if (os_time_get() - start_time >= timeout)
665 return FALSE;
666 os_time_sleep(10);
667 }
668 return TRUE;
669 }
670 virgl_vtest_resource_wait(vws, res);
671 return TRUE;
672 }
673
674 static void virgl_fence_reference(struct virgl_winsys *vws,
675 struct pipe_fence_handle **dst,
676 struct pipe_fence_handle *src)
677 {
678 struct virgl_vtest_winsys *vdws = virgl_vtest_winsys(vws);
679 virgl_vtest_resource_reference(vdws, (struct virgl_hw_res **)dst,
680 virgl_hw_res(src));
681 }
682
683 static void virgl_vtest_flush_frontbuffer(struct virgl_winsys *vws,
684 struct virgl_hw_res *res,
685 unsigned level, unsigned layer,
686 void *winsys_drawable_handle,
687 struct pipe_box *sub_box)
688 {
689 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws);
690 struct pipe_box box;
691 uint32_t offset = 0;
692 if (!res->dt)
693 return;
694
695 memset(&box, 0, sizeof(box));
696
697 if (sub_box) {
698 box = *sub_box;
699 offset = box.y / util_format_get_blockheight(res->format) * res->stride +
700 box.x / util_format_get_blockwidth(res->format) * util_format_get_blocksize(res->format);
701 } else {
702 box.z = layer;
703 box.width = res->width;
704 box.height = res->height;
705 box.depth = 1;
706 }
707
708 virgl_vtest_transfer_get_internal(vws, res, &box, res->stride, 0, offset,
709 level, true);
710
711 vtws->sws->displaytarget_display(vtws->sws, res->dt, winsys_drawable_handle,
712 sub_box);
713 }
714
715 static void
716 virgl_vtest_winsys_destroy(struct virgl_winsys *vws)
717 {
718 struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws);
719
720 virgl_cache_flush(vtws);
721
722 mtx_destroy(&vtws->mutex);
723 FREE(vtws);
724 }
725
726 struct virgl_winsys *
727 virgl_vtest_winsys_wrap(struct sw_winsys *sws)
728 {
729 struct virgl_vtest_winsys *vtws;
730
731 vtws = CALLOC_STRUCT(virgl_vtest_winsys);
732 if (!vtws)
733 return NULL;
734
735 virgl_vtest_connect(vtws);
736 vtws->sws = sws;
737
738 vtws->usecs = 1000000;
739 LIST_INITHEAD(&vtws->delayed);
740 (void) mtx_init(&vtws->mutex, mtx_plain);
741
742 vtws->base.destroy = virgl_vtest_winsys_destroy;
743
744 vtws->base.transfer_put = virgl_vtest_transfer_put;
745 vtws->base.transfer_get = virgl_vtest_transfer_get;
746
747 vtws->base.resource_create = virgl_vtest_winsys_resource_cache_create;
748 vtws->base.resource_unref = virgl_vtest_winsys_resource_unref;
749 vtws->base.resource_map = virgl_vtest_resource_map;
750 vtws->base.resource_wait = virgl_vtest_resource_wait;
751 vtws->base.cmd_buf_create = virgl_vtest_cmd_buf_create;
752 vtws->base.cmd_buf_destroy = virgl_vtest_cmd_buf_destroy;
753 vtws->base.submit_cmd = virgl_vtest_winsys_submit_cmd;
754
755 vtws->base.emit_res = virgl_vtest_emit_res;
756 vtws->base.res_is_referenced = virgl_vtest_res_is_ref;
757 vtws->base.get_caps = virgl_vtest_get_caps;
758
759 vtws->base.cs_create_fence = virgl_cs_create_fence;
760 vtws->base.fence_wait = virgl_fence_wait;
761 vtws->base.fence_reference = virgl_fence_reference;
762 vtws->base.supports_fences = 0;
763 vtws->base.supports_encoded_transfers = 0;
764
765 vtws->base.flush_frontbuffer = virgl_vtest_flush_frontbuffer;
766
767 return &vtws->base;
768 }