• 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 <os/os_process.h>
32 #include <util/u_format.h>
33 /* connect to remote socket */
34 #define VTEST_SOCKET_NAME "/tmp/.virgl_test"
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_send_init(struct virgl_vtest_winsys * vws)77 static int virgl_vtest_send_init(struct virgl_vtest_winsys *vws)
78 {
79    uint32_t buf[VTEST_HDR_SIZE];
80    const char *nstr = "virtest";
81    char cmdline[64];
82    int ret;
83 
84    ret = os_get_process_name(cmdline, 63);
85    if (ret == FALSE)
86       strcpy(cmdline, nstr);
87 #if defined(__GLIBC__) || defined(__CYGWIN__)
88    if (!strcmp(cmdline, "shader_runner")) {
89       const char *name;
90       /* hack to get better testname */
91       name = program_invocation_short_name;
92       name += strlen(name) + 1;
93       strncpy(cmdline, name, 63);
94    }
95 #endif
96    buf[VTEST_CMD_LEN] = strlen(cmdline) + 1;
97    buf[VTEST_CMD_ID] = VCMD_CREATE_RENDERER;
98 
99    virgl_block_write(vws->sock_fd, &buf, sizeof(buf));
100    virgl_block_write(vws->sock_fd, (void *)cmdline, strlen(cmdline) + 1);
101    return 0;
102 }
103 
virgl_vtest_connect(struct virgl_vtest_winsys * vws)104 int virgl_vtest_connect(struct virgl_vtest_winsys *vws)
105 {
106    struct sockaddr_un un;
107    int sock, ret;
108 
109    sock = socket(PF_UNIX, SOCK_STREAM, 0);
110    if (sock < 0)
111       return -1;
112 
113    memset(&un, 0, sizeof(un));
114    un.sun_family = AF_UNIX;
115    snprintf(un.sun_path, sizeof(un.sun_path), "%s", VTEST_SOCKET_NAME);
116 
117    do {
118       ret = 0;
119       if (connect(sock, (struct sockaddr *)&un, sizeof(un)) < 0) {
120          ret = -errno;
121       }
122    } while (ret == -EINTR);
123 
124    vws->sock_fd = sock;
125    virgl_vtest_send_init(vws);
126    return 0;
127 }
128 
virgl_vtest_send_get_caps(struct virgl_vtest_winsys * vws,struct virgl_drm_caps * caps)129 int virgl_vtest_send_get_caps(struct virgl_vtest_winsys *vws,
130                               struct virgl_drm_caps *caps)
131 {
132    uint32_t get_caps_buf[VTEST_HDR_SIZE];
133    uint32_t resp_buf[VTEST_HDR_SIZE];
134 
135    int ret;
136    get_caps_buf[VTEST_CMD_LEN] = 0;
137    get_caps_buf[VTEST_CMD_ID] = VCMD_GET_CAPS;
138 
139    virgl_block_write(vws->sock_fd, &get_caps_buf, sizeof(get_caps_buf));
140 
141    ret = virgl_block_read(vws->sock_fd, resp_buf, sizeof(resp_buf));
142    if (ret <= 0)
143       return 0;
144 
145    ret = virgl_block_read(vws->sock_fd, &caps->caps, sizeof(union virgl_caps));
146 
147    return 0;
148 }
149 
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)150 int virgl_vtest_send_resource_create(struct virgl_vtest_winsys *vws,
151                                      uint32_t handle,
152                                      enum pipe_texture_target target,
153                                      uint32_t format,
154                                      uint32_t bind,
155                                      uint32_t width,
156                                      uint32_t height,
157                                      uint32_t depth,
158                                      uint32_t array_size,
159                                      uint32_t last_level,
160                                      uint32_t nr_samples)
161 {
162    uint32_t res_create_buf[VCMD_RES_CREATE_SIZE], vtest_hdr[VTEST_HDR_SIZE];
163 
164    vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE_SIZE;
165    vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE;
166 
167    res_create_buf[VCMD_RES_CREATE_RES_HANDLE] = handle;
168    res_create_buf[VCMD_RES_CREATE_TARGET] = target;
169    res_create_buf[VCMD_RES_CREATE_FORMAT] = format;
170    res_create_buf[VCMD_RES_CREATE_BIND] = bind;
171    res_create_buf[VCMD_RES_CREATE_WIDTH] = width;
172    res_create_buf[VCMD_RES_CREATE_HEIGHT] = height;
173    res_create_buf[VCMD_RES_CREATE_DEPTH] = depth;
174    res_create_buf[VCMD_RES_CREATE_ARRAY_SIZE] = array_size;
175    res_create_buf[VCMD_RES_CREATE_LAST_LEVEL] = last_level;
176    res_create_buf[VCMD_RES_CREATE_NR_SAMPLES] = nr_samples;
177 
178    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
179    virgl_block_write(vws->sock_fd, &res_create_buf, sizeof(res_create_buf));
180 
181    return 0;
182 }
183 
virgl_vtest_submit_cmd(struct virgl_vtest_winsys * vws,struct virgl_vtest_cmd_buf * cbuf)184 int virgl_vtest_submit_cmd(struct virgl_vtest_winsys *vws,
185                            struct virgl_vtest_cmd_buf *cbuf)
186 {
187    uint32_t vtest_hdr[VTEST_HDR_SIZE];
188 
189    vtest_hdr[VTEST_CMD_LEN] = cbuf->base.cdw;
190    vtest_hdr[VTEST_CMD_ID] = VCMD_SUBMIT_CMD;
191 
192    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
193    virgl_block_write(vws->sock_fd, cbuf->buf, cbuf->base.cdw * 4);
194    return 0;
195 }
196 
virgl_vtest_send_resource_unref(struct virgl_vtest_winsys * vws,uint32_t handle)197 int virgl_vtest_send_resource_unref(struct virgl_vtest_winsys *vws,
198                                     uint32_t handle)
199 {
200    uint32_t vtest_hdr[VTEST_HDR_SIZE];
201    uint32_t cmd[1];
202    vtest_hdr[VTEST_CMD_LEN] = 1;
203    vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_UNREF;
204 
205    cmd[0] = handle;
206    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
207    virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));
208    return 0;
209 }
210 
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)211 int virgl_vtest_send_transfer_cmd(struct virgl_vtest_winsys *vws,
212                                   uint32_t vcmd,
213                                   uint32_t handle,
214                                   uint32_t level, uint32_t stride,
215                                   uint32_t layer_stride,
216                                   const struct pipe_box *box,
217                                   uint32_t data_size)
218 {
219    uint32_t vtest_hdr[VTEST_HDR_SIZE];
220    uint32_t cmd[VCMD_TRANSFER_HDR_SIZE];
221    vtest_hdr[VTEST_CMD_LEN] = VCMD_TRANSFER_HDR_SIZE;
222    vtest_hdr[VTEST_CMD_ID] = vcmd;
223 
224    if (vcmd == VCMD_TRANSFER_PUT)
225       vtest_hdr[VTEST_CMD_LEN] += data_size + 3 / 4;
226 
227    cmd[0] = handle;
228    cmd[1] = level;
229    cmd[2] = stride;
230    cmd[3] = layer_stride;
231    cmd[4] = box->x;
232    cmd[5] = box->y;
233    cmd[6] = box->z;
234    cmd[7] = box->width;
235    cmd[8] = box->height;
236    cmd[9] = box->depth;
237    cmd[10] = data_size;
238    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
239    virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));
240 
241    return 0;
242 }
243 
virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys * vws,void * data,uint32_t data_size)244 int virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys *vws,
245                                        void *data,
246                                        uint32_t data_size)
247 {
248    return virgl_block_write(vws->sock_fd, data, data_size);
249 }
250 
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)251 int virgl_vtest_recv_transfer_get_data(struct virgl_vtest_winsys *vws,
252                                        void *data,
253                                        uint32_t data_size,
254                                        uint32_t stride,
255                                        const struct pipe_box *box,
256                                        uint32_t format)
257 {
258    void *line;
259    void *ptr = data;
260    int hblocks = util_format_get_nblocksy(format, box->height);
261 
262    line = malloc(stride);
263    while (hblocks) {
264       virgl_block_read(vws->sock_fd, line, stride);
265       memcpy(ptr, line, util_format_get_stride(format, box->width));
266       ptr += stride;
267       hblocks--;
268    }
269    free(line);
270    return 0;
271 }
272 
virgl_vtest_busy_wait(struct virgl_vtest_winsys * vws,int handle,int flags)273 int virgl_vtest_busy_wait(struct virgl_vtest_winsys *vws, int handle,
274                           int flags)
275 {
276    uint32_t vtest_hdr[VTEST_HDR_SIZE];
277    uint32_t cmd[VCMD_BUSY_WAIT_SIZE];
278    uint32_t result[1];
279    int ret;
280    vtest_hdr[VTEST_CMD_LEN] = VCMD_BUSY_WAIT_SIZE;
281    vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;
282    cmd[VCMD_BUSY_WAIT_HANDLE] = handle;
283    cmd[VCMD_BUSY_WAIT_FLAGS] = flags;
284 
285    virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));
286    virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));
287 
288    ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));
289    assert(ret);
290    ret = virgl_block_read(vws->sock_fd, result, sizeof(result));
291    assert(ret);
292    return result[0];
293 }
294