• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
24 #include <sys/socket.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <netinet/in.h>
28 #include <sys/un.h>
29 #include <unistd.h>
30 
31 #include <util/format/u_format.h>
32 #include <util/u_process.h>
33 
34 #define VIRGL_RENDERER_UNSTABLE_APIS
35 
36 #include "virgl_vtest_winsys.h"
37 #include "virgl_vtest_public.h"
38 
39 /* block read/write routines */
virgl_block_write(int fd,void * buf,int size)40 static int virgl_block_write(int fd, void *buf, int size)
41 {
42    void *ptr = buf;
43    int left;
44    int ret;
45    left = size;
46    do {
47       ret = write(fd, ptr, left);
48       if (ret < 0)
49          return -errno;
50       left -= ret;
51       ptr += ret;
52    } while (left);
53    return size;
54 }
55 
virgl_block_read(int fd,void * buf,int size)56 static int virgl_block_read(int fd, void *buf, int size)
57 {
58    void *ptr = buf;
59    int left;
60    int ret;
61    left = size;
62    do {
63       ret = read(fd, ptr, left);
64       if (ret <= 0) {
65          fprintf(stderr,
66                  "lost connection to rendering server on %d read %d %d\n",
67                  size, ret, errno);
68          abort();
69          return ret < 0 ? -errno : 0;
70       }
71       left -= ret;
72       ptr += ret;
73    } while (left);
74    return size;
75 }
76 
virgl_vtest_receive_fd(int socket_fd)77 static int virgl_vtest_receive_fd(int socket_fd)
78 {
79     struct cmsghdr *cmsgh;
80     struct msghdr msgh = { 0 };
81     char buf[CMSG_SPACE(sizeof(int))], c;
82     struct iovec iovec;
83 
84     iovec.iov_base = &c;
85     iovec.iov_len = sizeof(char);
86 
87     msgh.msg_name = NULL;
88     msgh.msg_namelen = 0;
89     msgh.msg_iov = &iovec;
90     msgh.msg_iovlen = 1;
91     msgh.msg_control = buf;
92     msgh.msg_controllen = sizeof(buf);
93     msgh.msg_flags = 0;
94 
95     int size = recvmsg(socket_fd, &msgh, 0);
96     if (size < 0) {
97       fprintf(stderr, "Failed with %s\n", strerror(errno));
98       return -1;
99     }
100 
101     cmsgh = CMSG_FIRSTHDR(&msgh);
102     if (!cmsgh) {
103       fprintf(stderr, "No headers available\n");
104       return -1;
105     }
106 
107     if (cmsgh->cmsg_level != SOL_SOCKET) {
108       fprintf(stderr, "invalid cmsg_level %d\n", cmsgh->cmsg_level);
109       return -1;
110     }
111 
112     if (cmsgh->cmsg_type != SCM_RIGHTS) {
113       fprintf(stderr, "invalid cmsg_type %d\n", cmsgh->cmsg_type);
114       return -1;
115     }
116 
117     return *((int *) CMSG_DATA(cmsgh));
118 }
119 
virgl_vtest_send_init(struct virgl_vtest_winsys * vws)120 static int virgl_vtest_send_init(struct virgl_vtest_winsys *vws)
121 {
122    uint32_t buf[VTEST_HDR_SIZE];
123    const char *nstr = "virtest";
124    char cmdline[64] = { 0 };
125    const char *proc_name = util_get_process_name();
126 
127    if (proc_name)
128       strncpy(cmdline, proc_name, 63);
129    else
130       strcpy(cmdline, nstr);
131 #if defined(HAVE_PROGRAM_INVOCATION_NAME)
132    if (!strcmp(cmdline, "shader_runner")) {
133       const char *name;
134       /* hack to get better testname */
135       name = program_invocation_short_name;
136       name += strlen(name) + 1;
137       strncpy(cmdline, name, 63);
138    }
139 #endif
140    buf[VTEST_CMD_LEN] = strlen(cmdline) + 1;
141    buf[VTEST_CMD_ID] = VCMD_CREATE_RENDERER;
142 
143    virgl_block_write(vws->sock_fd, &buf, sizeof(buf));
144    virgl_block_write(vws->sock_fd, (void *)cmdline, strlen(cmdline) + 1);
145    return 0;
146 }
147 
virgl_vtest_negotiate_version(struct virgl_vtest_winsys * vws,int version)148 static int virgl_vtest_negotiate_version(struct virgl_vtest_winsys *vws, int version)
149 {
150    uint32_t vtest_hdr[VTEST_HDR_SIZE];
151    uint32_t version_buf[VCMD_PROTOCOL_VERSION_SIZE];
152    uint32_t busy_wait_buf[VCMD_BUSY_WAIT_SIZE];
153    uint32_t busy_wait_result[1];
154    ASSERTED int ret;
155 
156    vtest_hdr[VTEST_CMD_LEN] = VCMD_PING_PROTOCOL_VERSION_SIZE;
157    vtest_hdr[VTEST_CMD_ID] = VCMD_PING_PROTOCOL_VERSION;
158    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
159 
160    vtest_hdr[VTEST_CMD_LEN] = VCMD_BUSY_WAIT_SIZE;
161    vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;
162    busy_wait_buf[VCMD_BUSY_WAIT_HANDLE] = 0;
163    busy_wait_buf[VCMD_BUSY_WAIT_FLAGS] = 0;
164    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
165    virgl_block_write(vws->sock_fd, &busy_wait_buf, sizeof(busy_wait_buf));
166 
167    ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));
168    assert(ret);
169 
170    if (vtest_hdr[VTEST_CMD_ID] == VCMD_PING_PROTOCOL_VERSION) {
171      /* Read dummy busy_wait response */
172      ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));
173      assert(ret);
174      ret = virgl_block_read(vws->sock_fd, busy_wait_result, sizeof(busy_wait_result));
175      assert(ret);
176 
177      vtest_hdr[VTEST_CMD_LEN] = VCMD_PROTOCOL_VERSION_SIZE;
178      vtest_hdr[VTEST_CMD_ID] = VCMD_PROTOCOL_VERSION;
179      version_buf[VCMD_PROTOCOL_VERSION_VERSION] = version;
180      virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
181      virgl_block_write(vws->sock_fd, &version_buf, sizeof(version_buf));
182 
183      ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));
184      assert(ret);
185      ret = virgl_block_read(vws->sock_fd, version_buf, sizeof(version_buf));
186      assert(ret);
187      return version_buf[VCMD_PROTOCOL_VERSION_VERSION];
188    }
189 
190    /* Read dummy busy_wait response */
191    assert(vtest_hdr[VTEST_CMD_ID] == VCMD_RESOURCE_BUSY_WAIT);
192    ret = virgl_block_read(vws->sock_fd, busy_wait_result, sizeof(busy_wait_result));
193    assert(ret);
194 
195    /* Old server, return version 0 */
196    return 0;
197 }
198 
virgl_vtest_connect(struct virgl_vtest_winsys * vws)199 int virgl_vtest_connect(struct virgl_vtest_winsys *vws)
200 {
201    struct sockaddr_un un;
202    int sock, ret;
203    const char* socket_name = os_get_option("VTEST_SOCKET_NAME");
204 
205    sock = socket(PF_UNIX, SOCK_STREAM, 0);
206    if (sock < 0)
207       return -1;
208 
209    memset(&un, 0, sizeof(un));
210    un.sun_family = AF_UNIX;
211    snprintf(un.sun_path, sizeof(un.sun_path), "%s", socket_name ?
212       socket_name : VTEST_DEFAULT_SOCKET_NAME);
213 
214    do {
215       ret = 0;
216       if (connect(sock, (struct sockaddr *)&un, sizeof(un)) < 0) {
217          ret = -errno;
218       }
219    } while (ret == -EINTR);
220 
221    vws->sock_fd = sock;
222    virgl_vtest_send_init(vws);
223    vws->protocol_version = virgl_vtest_negotiate_version(vws, VTEST_PROTOCOL_VERSION);
224 
225    /* Version 1 is deprecated. */
226    if (vws->protocol_version == 1)
227       vws->protocol_version = 0;
228 
229    return 0;
230 }
231 
virgl_vtest_send_get_caps(struct virgl_vtest_winsys * vws,struct virgl_drm_caps * caps)232 int virgl_vtest_send_get_caps(struct virgl_vtest_winsys *vws,
233                               struct virgl_drm_caps *caps)
234 {
235    uint32_t get_caps_buf[VTEST_HDR_SIZE * 2];
236    uint32_t resp_buf[VTEST_HDR_SIZE];
237    uint32_t caps_size = sizeof(struct virgl_caps_v2);
238    int ret;
239    get_caps_buf[VTEST_CMD_LEN] = 0;
240    get_caps_buf[VTEST_CMD_ID] = VCMD_GET_CAPS2;
241    get_caps_buf[VTEST_CMD_LEN + 2] = 0;
242    get_caps_buf[VTEST_CMD_ID + 2] = VCMD_GET_CAPS;
243 
244    virgl_block_write(vws->sock_fd, &get_caps_buf, sizeof(get_caps_buf));
245 
246    ret = virgl_block_read(vws->sock_fd, resp_buf, sizeof(resp_buf));
247    if (ret <= 0)
248       return 0;
249 
250    if (resp_buf[1] == 2) {
251        struct virgl_caps_v1 dummy;
252        uint32_t resp_size = resp_buf[0] - 1;
253        uint32_t dummy_size = 0;
254        if (resp_size > caps_size) {
255 	   dummy_size = resp_size - caps_size;
256 	   resp_size = caps_size;
257        }
258 
259        ret = virgl_block_read(vws->sock_fd, &caps->caps, resp_size);
260 
261        while (dummy_size) {
262            ret = virgl_block_read(vws->sock_fd, &dummy,
263                     dummy_size < sizeof(dummy) ? dummy_size : sizeof(dummy));
264            if (ret <= 0)
265                break;
266            dummy_size -= ret;
267        }
268 
269        /* now read back the pointless caps v1 we requested */
270        ret = virgl_block_read(vws->sock_fd, resp_buf, sizeof(resp_buf));
271        if (ret <= 0)
272 	   return 0;
273        ret = virgl_block_read(vws->sock_fd, &dummy, sizeof(struct virgl_caps_v1));
274    } else
275        ret = virgl_block_read(vws->sock_fd, &caps->caps, sizeof(struct virgl_caps_v1));
276 
277    // Old virglrenderer versions can't handle the re-use of host-generated
278    // resource IDs that are used with protocol version 3, so re-negotiate the
279    // protocol version limiting to <= 2
280    if (vws->protocol_version > 2 &&
281        caps->caps.v2.host_feature_check_version < 23) {
282       vws->protocol_version = virgl_vtest_negotiate_version(vws, 2);
283    }
284 
285    return 0;
286 }
287 
virgl_vtest_send_resource_create2(struct virgl_vtest_winsys * vws,uint32_t handle,enum pipe_texture_target target,uint32_t format,uint32_t bind,uint32_t width,uint32_t height,uint32_t depth,uint32_t array_size,uint32_t last_level,uint32_t nr_samples,uint32_t size,int * out_fd)288 static int virgl_vtest_send_resource_create2(struct virgl_vtest_winsys *vws,
289                                              uint32_t handle,
290                                              enum pipe_texture_target target,
291                                              uint32_t format,
292                                              uint32_t bind,
293                                              uint32_t width,
294                                              uint32_t height,
295                                              uint32_t depth,
296                                              uint32_t array_size,
297                                              uint32_t last_level,
298                                              uint32_t nr_samples,
299                                              uint32_t size,
300                                              int *out_fd)
301 {
302    uint32_t res_create_buf[VCMD_RES_CREATE2_SIZE], vtest_hdr[VTEST_HDR_SIZE];
303 
304    vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE2_SIZE;
305    vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE2;
306 
307    res_create_buf[VCMD_RES_CREATE2_RES_HANDLE] = vws->protocol_version < 3 ? handle : 0;
308    res_create_buf[VCMD_RES_CREATE2_TARGET] = target;
309    res_create_buf[VCMD_RES_CREATE2_FORMAT] = format;
310    res_create_buf[VCMD_RES_CREATE2_BIND] = bind;
311    res_create_buf[VCMD_RES_CREATE2_WIDTH] = width;
312    res_create_buf[VCMD_RES_CREATE2_HEIGHT] = height;
313    res_create_buf[VCMD_RES_CREATE2_DEPTH] = depth;
314    res_create_buf[VCMD_RES_CREATE2_ARRAY_SIZE] = array_size;
315    res_create_buf[VCMD_RES_CREATE2_LAST_LEVEL] = last_level;
316    res_create_buf[VCMD_RES_CREATE2_NR_SAMPLES] = nr_samples;
317    res_create_buf[VCMD_RES_CREATE2_DATA_SIZE] = size;
318 
319    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
320    virgl_block_write(vws->sock_fd, &res_create_buf, sizeof(res_create_buf));
321 
322    if (vws->protocol_version >= 3) {
323       virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));
324       assert(vtest_hdr[VTEST_CMD_LEN] == 1);
325       assert(vtest_hdr[VTEST_CMD_ID] == VCMD_RESOURCE_CREATE2);
326       virgl_block_read(vws->sock_fd, &handle, sizeof(handle));
327    }
328 
329    /* Multi-sampled textures have no backing store attached. */
330    if (size == 0)
331       return handle;
332 
333    *out_fd = virgl_vtest_receive_fd(vws->sock_fd);
334    if (*out_fd < 0) {
335       fprintf(stderr, "failed to get fd\n");
336       return -1;
337    }
338 
339    return handle;
340 }
341 
virgl_vtest_send_resource_create(struct virgl_vtest_winsys * vws,uint32_t handle,enum pipe_texture_target target,uint32_t format,uint32_t bind,uint32_t width,uint32_t height,uint32_t depth,uint32_t array_size,uint32_t last_level,uint32_t nr_samples,uint32_t size,int * out_fd)342 int virgl_vtest_send_resource_create(struct virgl_vtest_winsys *vws,
343                                      uint32_t handle,
344                                      enum pipe_texture_target target,
345                                      uint32_t format,
346                                      uint32_t bind,
347                                      uint32_t width,
348                                      uint32_t height,
349                                      uint32_t depth,
350                                      uint32_t array_size,
351                                      uint32_t last_level,
352                                      uint32_t nr_samples,
353                                      uint32_t size,
354                                      int *out_fd)
355 {
356    uint32_t res_create_buf[VCMD_RES_CREATE_SIZE], vtest_hdr[VTEST_HDR_SIZE];
357 
358    if (vws->protocol_version >= 2)
359       return virgl_vtest_send_resource_create2(vws, handle, target, format,
360                                                bind, width, height, depth,
361                                                array_size, last_level,
362                                                nr_samples, size, out_fd);
363 
364    vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE_SIZE;
365    vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE;
366 
367    res_create_buf[VCMD_RES_CREATE_RES_HANDLE] = handle;
368    res_create_buf[VCMD_RES_CREATE_TARGET] = target;
369    res_create_buf[VCMD_RES_CREATE_FORMAT] = format;
370    res_create_buf[VCMD_RES_CREATE_BIND] = bind;
371    res_create_buf[VCMD_RES_CREATE_WIDTH] = width;
372    res_create_buf[VCMD_RES_CREATE_HEIGHT] = height;
373    res_create_buf[VCMD_RES_CREATE_DEPTH] = depth;
374    res_create_buf[VCMD_RES_CREATE_ARRAY_SIZE] = array_size;
375    res_create_buf[VCMD_RES_CREATE_LAST_LEVEL] = last_level;
376    res_create_buf[VCMD_RES_CREATE_NR_SAMPLES] = nr_samples;
377 
378    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
379    virgl_block_write(vws->sock_fd, &res_create_buf, sizeof(res_create_buf));
380 
381    return handle;
382 }
383 
virgl_vtest_submit_cmd(struct virgl_vtest_winsys * vws,uint32_t * buf,uint32_t buf_len)384 int virgl_vtest_submit_cmd(struct virgl_vtest_winsys *vws,
385                            uint32_t *buf, uint32_t buf_len)
386 {
387    uint32_t vtest_hdr[VTEST_HDR_SIZE];
388    vtest_hdr[VTEST_CMD_LEN] = buf_len;
389    vtest_hdr[VTEST_CMD_ID] = VCMD_SUBMIT_CMD;
390 
391    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
392    virgl_block_write(vws->sock_fd, buf, 4 * buf_len);
393    return 0;
394 }
395 
virgl_vtest_send_resource_unref(struct virgl_vtest_winsys * vws,uint32_t handle)396 int virgl_vtest_send_resource_unref(struct virgl_vtest_winsys *vws,
397                                     uint32_t handle)
398 {
399    uint32_t vtest_hdr[VTEST_HDR_SIZE];
400    uint32_t cmd[1];
401    vtest_hdr[VTEST_CMD_LEN] = 1;
402    vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_UNREF;
403 
404    cmd[0] = handle;
405    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
406    virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));
407    return 0;
408 }
409 
virgl_vtest_send_transfer_cmd(struct virgl_vtest_winsys * vws,uint32_t vcmd,uint32_t handle,uint32_t level,uint32_t stride,uint32_t layer_stride,const struct pipe_box * box,uint32_t data_size)410 static int virgl_vtest_send_transfer_cmd(struct virgl_vtest_winsys *vws,
411                                   uint32_t vcmd,
412                                   uint32_t handle,
413                                   uint32_t level, uint32_t stride,
414                                   uint32_t layer_stride,
415                                   const struct pipe_box *box,
416                                   uint32_t data_size)
417 {
418    uint32_t vtest_hdr[VTEST_HDR_SIZE];
419    uint32_t cmd[VCMD_TRANSFER_HDR_SIZE];
420    vtest_hdr[VTEST_CMD_LEN] = VCMD_TRANSFER_HDR_SIZE;
421    vtest_hdr[VTEST_CMD_ID] = vcmd;
422 
423    /* The host expects the size in dwords so calculate the rounded up
424     * value here. */
425    if (vcmd == VCMD_TRANSFER_PUT)
426       vtest_hdr[VTEST_CMD_LEN] += (data_size + 3) / 4;
427 
428    cmd[0] = handle;
429    cmd[1] = level;
430    cmd[2] = stride;
431    cmd[3] = layer_stride;
432    cmd[4] = box->x;
433    cmd[5] = box->y;
434    cmd[6] = box->z;
435    cmd[7] = box->width;
436    cmd[8] = box->height;
437    cmd[9] = box->depth;
438    cmd[10] = data_size;
439    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
440    virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));
441 
442    return 0;
443 }
444 
virgl_vtest_send_transfer_cmd2(struct virgl_vtest_winsys * vws,uint32_t vcmd,uint32_t handle,uint32_t level,const struct pipe_box * box,uint32_t data_size,uint32_t offset)445 static int virgl_vtest_send_transfer_cmd2(struct virgl_vtest_winsys *vws,
446                                   uint32_t vcmd,
447                                   uint32_t handle,
448                                   uint32_t level,
449                                   const struct pipe_box *box,
450                                   uint32_t data_size,
451                                   uint32_t offset)
452 {
453    uint32_t vtest_hdr[VTEST_HDR_SIZE];
454    uint32_t cmd[VCMD_TRANSFER2_HDR_SIZE];
455    vtest_hdr[VTEST_CMD_LEN] = VCMD_TRANSFER2_HDR_SIZE;
456    vtest_hdr[VTEST_CMD_ID] = vcmd;
457 
458    /* The host expects the size in dwords so calculate the rounded up
459     * value here. */
460    if (vcmd == VCMD_TRANSFER_PUT2)
461       vtest_hdr[VTEST_CMD_LEN] += (data_size + 3) / 4;
462 
463    cmd[VCMD_TRANSFER2_RES_HANDLE] = handle;
464    cmd[VCMD_TRANSFER2_LEVEL] = level;
465    cmd[VCMD_TRANSFER2_X] = box->x;
466    cmd[VCMD_TRANSFER2_Y] = box->y;
467    cmd[VCMD_TRANSFER2_Z] = box->z;
468    cmd[VCMD_TRANSFER2_WIDTH] = box->width;
469    cmd[VCMD_TRANSFER2_HEIGHT] = box->height;
470    cmd[VCMD_TRANSFER2_DEPTH] = box->depth;
471    cmd[VCMD_TRANSFER2_DATA_SIZE] = data_size;
472    cmd[VCMD_TRANSFER2_OFFSET] = offset;
473    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
474    virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));
475 
476    return 0;
477 }
478 
virgl_vtest_send_transfer_get(struct virgl_vtest_winsys * vws,uint32_t handle,uint32_t level,uint32_t stride,uint32_t layer_stride,const struct pipe_box * box,uint32_t data_size,uint32_t offset)479 int virgl_vtest_send_transfer_get(struct virgl_vtest_winsys *vws,
480                                   uint32_t handle,
481                                   uint32_t level, uint32_t stride,
482                                   uint32_t layer_stride,
483                                   const struct pipe_box *box,
484                                   uint32_t data_size,
485                                   uint32_t offset)
486 {
487    if (vws->protocol_version < 2)
488       return virgl_vtest_send_transfer_cmd(vws, VCMD_TRANSFER_GET, handle,
489                                            level, stride, layer_stride, box,
490                                            data_size);
491 
492    return virgl_vtest_send_transfer_cmd2(vws, VCMD_TRANSFER_GET2, handle,
493                                         level, box, data_size, offset);
494 }
495 
virgl_vtest_send_transfer_put(struct virgl_vtest_winsys * vws,uint32_t handle,uint32_t level,uint32_t stride,uint32_t layer_stride,const struct pipe_box * box,uint32_t data_size,uint32_t offset)496 int virgl_vtest_send_transfer_put(struct virgl_vtest_winsys *vws,
497                                   uint32_t handle,
498                                   uint32_t level, uint32_t stride,
499                                   uint32_t layer_stride,
500                                   const struct pipe_box *box,
501                                   uint32_t data_size,
502                                   uint32_t offset)
503 {
504    if (vws->protocol_version < 2)
505       return virgl_vtest_send_transfer_cmd(vws, VCMD_TRANSFER_PUT, handle,
506                                            level, stride, layer_stride, box,
507                                            data_size);
508 
509    return virgl_vtest_send_transfer_cmd2(vws, VCMD_TRANSFER_PUT2, handle,
510                                         level, box, data_size, offset);
511 }
512 
virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys * vws,void * data,uint32_t data_size)513 int virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys *vws,
514                                        void *data,
515                                        uint32_t data_size)
516 {
517    return virgl_block_write(vws->sock_fd, data, data_size);
518 }
519 
virgl_vtest_recv_transfer_get_data(struct virgl_vtest_winsys * vws,void * data,uint32_t data_size,uint32_t stride,const struct pipe_box * box,uint32_t format)520 int virgl_vtest_recv_transfer_get_data(struct virgl_vtest_winsys *vws,
521                                        void *data,
522                                        uint32_t data_size,
523                                        uint32_t stride,
524                                        const struct pipe_box *box,
525                                        uint32_t format)
526 {
527    void *line;
528    void *ptr = data;
529    int hblocks = util_format_get_nblocksy(format, box->height);
530 
531    line = malloc(stride);
532    while (hblocks) {
533       virgl_block_read(vws->sock_fd, line, stride);
534       memcpy(ptr, line, util_format_get_stride(format, box->width));
535       ptr += stride;
536       hblocks--;
537    }
538    free(line);
539    return 0;
540 }
541 
virgl_vtest_busy_wait(struct virgl_vtest_winsys * vws,int handle,int flags)542 int virgl_vtest_busy_wait(struct virgl_vtest_winsys *vws, int handle,
543                           int flags)
544 {
545    uint32_t vtest_hdr[VTEST_HDR_SIZE];
546    uint32_t cmd[VCMD_BUSY_WAIT_SIZE];
547    uint32_t result[1];
548    ASSERTED int ret;
549    vtest_hdr[VTEST_CMD_LEN] = VCMD_BUSY_WAIT_SIZE;
550    vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;
551    cmd[VCMD_BUSY_WAIT_HANDLE] = handle;
552    cmd[VCMD_BUSY_WAIT_FLAGS] = flags;
553 
554    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
555    virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));
556 
557    ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));
558    assert(ret);
559    ret = virgl_block_read(vws->sock_fd, result, sizeof(result));
560    assert(ret);
561    return result[0];
562 }
563 
564 int
virgl_vtest_send_create_blob(struct virgl_vtest_winsys * vws,uint32_t size,uint32_t blob_id,int * out_fd)565 virgl_vtest_send_create_blob(struct virgl_vtest_winsys *vws,
566                                  uint32_t size, uint32_t blob_id,
567                                  int *out_fd)
568 {
569    uint32_t vtest_hdr[VTEST_HDR_SIZE];
570    vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE_BLOB_SIZE;
571    vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE_BLOB;
572 
573    uint32_t vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_SIZE];
574 
575    vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_TYPE] = VCMD_BLOB_TYPE_HOST3D;
576    vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_FLAGS] = VCMD_BLOB_FLAG_MAPPABLE;
577    vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_SIZE_LO] = (uint32_t)size;
578    vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_SIZE_HI] = 0;
579    vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_ID_LO] = (uint32_t)blob_id;
580    vcmd_res_create_blob[VCMD_RES_CREATE_BLOB_ID_HI] = 0;
581 
582    virgl_block_write(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));
583    virgl_block_write(vws->sock_fd, vcmd_res_create_blob, sizeof(vcmd_res_create_blob));
584 
585    vtest_hdr[0] = 0;
586    virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));
587    assert(vtest_hdr[VTEST_CMD_LEN] == 1);
588    assert(vtest_hdr[VTEST_CMD_ID] == VCMD_RESOURCE_CREATE_BLOB);
589 
590    uint32_t res_id;
591    virgl_block_read(vws->sock_fd, &res_id, sizeof(res_id));
592 
593    *out_fd = virgl_vtest_receive_fd(vws->sock_fd);
594 
595    return res_id;
596 }
597 
598