2 * Copyright 2014, 2015 Red Hat.
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:
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
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.
24 #include <sys/socket.h>
27 #include <netinet/in.h>
31 #include <os/os_process.h>
32 #include <util/format/u_format.h>
34 #include "virgl_vtest_winsys.h"
35 #include "virgl_vtest_public.h"
37 /* block read/write routines */
38 static int virgl_block_write(int fd
, void *buf
, int size
)
45 ret
= write(fd
, ptr
, left
);
54 static int virgl_block_read(int fd
, void *buf
, int size
)
61 ret
= read(fd
, ptr
, left
);
64 "lost connection to rendering server on %d read %d %d\n",
67 return ret
< 0 ? -errno
: 0;
75 static int virgl_vtest_receive_fd(int socket_fd
)
77 struct cmsghdr
*cmsgh
;
78 struct msghdr msgh
= { 0 };
79 char buf
[CMSG_SPACE(sizeof(int))], c
;
83 iovec
.iov_len
= sizeof(char);
87 msgh
.msg_iov
= &iovec
;
89 msgh
.msg_control
= buf
;
90 msgh
.msg_controllen
= sizeof(buf
);
93 int size
= recvmsg(socket_fd
, &msgh
, 0);
95 fprintf(stderr
, "Failed with %s\n", strerror(errno
));
99 cmsgh
= CMSG_FIRSTHDR(&msgh
);
101 fprintf(stderr
, "No headers available\n");
105 if (cmsgh
->cmsg_level
!= SOL_SOCKET
) {
106 fprintf(stderr
, "invalid cmsg_level %d\n", cmsgh
->cmsg_level
);
110 if (cmsgh
->cmsg_type
!= SCM_RIGHTS
) {
111 fprintf(stderr
, "invalid cmsg_type %d\n", cmsgh
->cmsg_type
);
115 return *((int *) CMSG_DATA(cmsgh
));
118 static int virgl_vtest_send_init(struct virgl_vtest_winsys
*vws
)
120 uint32_t buf
[VTEST_HDR_SIZE
];
121 const char *nstr
= "virtest";
125 ret
= os_get_process_name(cmdline
, 63);
127 strcpy(cmdline
, nstr
);
128 #if defined(HAVE_PROGRAM_INVOCATION_NAME)
129 if (!strcmp(cmdline
, "shader_runner")) {
131 /* hack to get better testname */
132 name
= program_invocation_short_name
;
133 name
+= strlen(name
) + 1;
134 strncpy(cmdline
, name
, 63);
137 buf
[VTEST_CMD_LEN
] = strlen(cmdline
) + 1;
138 buf
[VTEST_CMD_ID
] = VCMD_CREATE_RENDERER
;
140 virgl_block_write(vws
->sock_fd
, &buf
, sizeof(buf
));
141 virgl_block_write(vws
->sock_fd
, (void *)cmdline
, strlen(cmdline
) + 1);
145 static int virgl_vtest_negotiate_version(struct virgl_vtest_winsys
*vws
)
147 uint32_t vtest_hdr
[VTEST_HDR_SIZE
];
148 uint32_t version_buf
[VCMD_PROTOCOL_VERSION_SIZE
];
149 uint32_t busy_wait_buf
[VCMD_BUSY_WAIT_SIZE
];
150 uint32_t busy_wait_result
[1];
153 vtest_hdr
[VTEST_CMD_LEN
] = VCMD_PING_PROTOCOL_VERSION_SIZE
;
154 vtest_hdr
[VTEST_CMD_ID
] = VCMD_PING_PROTOCOL_VERSION
;
155 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
157 vtest_hdr
[VTEST_CMD_LEN
] = VCMD_BUSY_WAIT_SIZE
;
158 vtest_hdr
[VTEST_CMD_ID
] = VCMD_RESOURCE_BUSY_WAIT
;
159 busy_wait_buf
[VCMD_BUSY_WAIT_HANDLE
] = 0;
160 busy_wait_buf
[VCMD_BUSY_WAIT_FLAGS
] = 0;
161 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
162 virgl_block_write(vws
->sock_fd
, &busy_wait_buf
, sizeof(busy_wait_buf
));
164 ret
= virgl_block_read(vws
->sock_fd
, vtest_hdr
, sizeof(vtest_hdr
));
167 if (vtest_hdr
[VTEST_CMD_ID
] == VCMD_PING_PROTOCOL_VERSION
) {
168 /* Read dummy busy_wait response */
169 ret
= virgl_block_read(vws
->sock_fd
, vtest_hdr
, sizeof(vtest_hdr
));
171 ret
= virgl_block_read(vws
->sock_fd
, busy_wait_result
, sizeof(busy_wait_result
));
174 vtest_hdr
[VTEST_CMD_LEN
] = VCMD_PROTOCOL_VERSION_SIZE
;
175 vtest_hdr
[VTEST_CMD_ID
] = VCMD_PROTOCOL_VERSION
;
176 version_buf
[VCMD_PROTOCOL_VERSION_VERSION
] = VTEST_PROTOCOL_VERSION
;
177 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
178 virgl_block_write(vws
->sock_fd
, &version_buf
, sizeof(version_buf
));
180 ret
= virgl_block_read(vws
->sock_fd
, vtest_hdr
, sizeof(vtest_hdr
));
182 ret
= virgl_block_read(vws
->sock_fd
, version_buf
, sizeof(version_buf
));
184 return version_buf
[VCMD_PROTOCOL_VERSION_VERSION
];
187 /* Read dummy busy_wait response */
188 assert(vtest_hdr
[VTEST_CMD_ID
] == VCMD_RESOURCE_BUSY_WAIT
);
189 ret
= virgl_block_read(vws
->sock_fd
, busy_wait_result
, sizeof(busy_wait_result
));
192 /* Old server, return version 0 */
196 int virgl_vtest_connect(struct virgl_vtest_winsys
*vws
)
198 struct sockaddr_un un
;
201 sock
= socket(PF_UNIX
, SOCK_STREAM
, 0);
205 memset(&un
, 0, sizeof(un
));
206 un
.sun_family
= AF_UNIX
;
207 snprintf(un
.sun_path
, sizeof(un
.sun_path
), "%s", VTEST_DEFAULT_SOCKET_NAME
);
211 if (connect(sock
, (struct sockaddr
*)&un
, sizeof(un
)) < 0) {
214 } while (ret
== -EINTR
);
217 virgl_vtest_send_init(vws
);
218 vws
->protocol_version
= virgl_vtest_negotiate_version(vws
);
220 /* Version 1 is deprecated. */
221 if (vws
->protocol_version
== 1)
222 vws
->protocol_version
= 0;
227 int virgl_vtest_send_get_caps(struct virgl_vtest_winsys
*vws
,
228 struct virgl_drm_caps
*caps
)
230 uint32_t get_caps_buf
[VTEST_HDR_SIZE
* 2];
231 uint32_t resp_buf
[VTEST_HDR_SIZE
];
232 uint32_t caps_size
= sizeof(struct virgl_caps_v2
);
234 get_caps_buf
[VTEST_CMD_LEN
] = 0;
235 get_caps_buf
[VTEST_CMD_ID
] = VCMD_GET_CAPS2
;
236 get_caps_buf
[VTEST_CMD_LEN
+ 2] = 0;
237 get_caps_buf
[VTEST_CMD_ID
+ 2] = VCMD_GET_CAPS
;
239 virgl_block_write(vws
->sock_fd
, &get_caps_buf
, sizeof(get_caps_buf
));
241 ret
= virgl_block_read(vws
->sock_fd
, resp_buf
, sizeof(resp_buf
));
245 if (resp_buf
[1] == 2) {
246 struct virgl_caps_v1 dummy
;
247 uint32_t resp_size
= resp_buf
[0] - 1;
248 uint32_t dummy_size
= 0;
249 if (resp_size
> caps_size
) {
250 dummy_size
= resp_size
- caps_size
;
251 resp_size
= caps_size
;
254 ret
= virgl_block_read(vws
->sock_fd
, &caps
->caps
, resp_size
);
257 ret
= virgl_block_read(vws
->sock_fd
, &dummy
, dummy_size
);
259 /* now read back the pointless caps v1 we requested */
260 ret
= virgl_block_read(vws
->sock_fd
, resp_buf
, sizeof(resp_buf
));
263 ret
= virgl_block_read(vws
->sock_fd
, &dummy
, sizeof(struct virgl_caps_v1
));
265 ret
= virgl_block_read(vws
->sock_fd
, &caps
->caps
, sizeof(struct virgl_caps_v1
));
270 static int virgl_vtest_send_resource_create2(struct virgl_vtest_winsys
*vws
,
272 enum pipe_texture_target target
,
284 uint32_t res_create_buf
[VCMD_RES_CREATE2_SIZE
], vtest_hdr
[VTEST_HDR_SIZE
];
286 vtest_hdr
[VTEST_CMD_LEN
] = VCMD_RES_CREATE2_SIZE
;
287 vtest_hdr
[VTEST_CMD_ID
] = VCMD_RESOURCE_CREATE2
;
289 res_create_buf
[VCMD_RES_CREATE2_RES_HANDLE
] = handle
;
290 res_create_buf
[VCMD_RES_CREATE2_TARGET
] = target
;
291 res_create_buf
[VCMD_RES_CREATE2_FORMAT
] = format
;
292 res_create_buf
[VCMD_RES_CREATE2_BIND
] = bind
;
293 res_create_buf
[VCMD_RES_CREATE2_WIDTH
] = width
;
294 res_create_buf
[VCMD_RES_CREATE2_HEIGHT
] = height
;
295 res_create_buf
[VCMD_RES_CREATE2_DEPTH
] = depth
;
296 res_create_buf
[VCMD_RES_CREATE2_ARRAY_SIZE
] = array_size
;
297 res_create_buf
[VCMD_RES_CREATE2_LAST_LEVEL
] = last_level
;
298 res_create_buf
[VCMD_RES_CREATE2_NR_SAMPLES
] = nr_samples
;
299 res_create_buf
[VCMD_RES_CREATE2_DATA_SIZE
] = size
;
301 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
302 virgl_block_write(vws
->sock_fd
, &res_create_buf
, sizeof(res_create_buf
));
304 /* Multi-sampled textures have no backing store attached. */
308 *out_fd
= virgl_vtest_receive_fd(vws
->sock_fd
);
310 fprintf(stderr
, "failed to get fd\n");
317 int virgl_vtest_send_resource_create(struct virgl_vtest_winsys
*vws
,
319 enum pipe_texture_target target
,
331 uint32_t res_create_buf
[VCMD_RES_CREATE_SIZE
], vtest_hdr
[VTEST_HDR_SIZE
];
333 if (vws
->protocol_version
>= 2)
334 return virgl_vtest_send_resource_create2(vws
, handle
, target
, format
,
335 bind
, width
, height
, depth
,
336 array_size
, last_level
,
337 nr_samples
, size
, out_fd
);
339 vtest_hdr
[VTEST_CMD_LEN
] = VCMD_RES_CREATE_SIZE
;
340 vtest_hdr
[VTEST_CMD_ID
] = VCMD_RESOURCE_CREATE
;
342 res_create_buf
[VCMD_RES_CREATE_RES_HANDLE
] = handle
;
343 res_create_buf
[VCMD_RES_CREATE_TARGET
] = target
;
344 res_create_buf
[VCMD_RES_CREATE_FORMAT
] = format
;
345 res_create_buf
[VCMD_RES_CREATE_BIND
] = bind
;
346 res_create_buf
[VCMD_RES_CREATE_WIDTH
] = width
;
347 res_create_buf
[VCMD_RES_CREATE_HEIGHT
] = height
;
348 res_create_buf
[VCMD_RES_CREATE_DEPTH
] = depth
;
349 res_create_buf
[VCMD_RES_CREATE_ARRAY_SIZE
] = array_size
;
350 res_create_buf
[VCMD_RES_CREATE_LAST_LEVEL
] = last_level
;
351 res_create_buf
[VCMD_RES_CREATE_NR_SAMPLES
] = nr_samples
;
353 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
354 virgl_block_write(vws
->sock_fd
, &res_create_buf
, sizeof(res_create_buf
));
359 int virgl_vtest_submit_cmd(struct virgl_vtest_winsys
*vws
,
360 struct virgl_vtest_cmd_buf
*cbuf
)
362 uint32_t vtest_hdr
[VTEST_HDR_SIZE
];
364 vtest_hdr
[VTEST_CMD_LEN
] = cbuf
->base
.cdw
;
365 vtest_hdr
[VTEST_CMD_ID
] = VCMD_SUBMIT_CMD
;
367 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
368 virgl_block_write(vws
->sock_fd
, cbuf
->buf
, cbuf
->base
.cdw
* 4);
372 int virgl_vtest_send_resource_unref(struct virgl_vtest_winsys
*vws
,
375 uint32_t vtest_hdr
[VTEST_HDR_SIZE
];
377 vtest_hdr
[VTEST_CMD_LEN
] = 1;
378 vtest_hdr
[VTEST_CMD_ID
] = VCMD_RESOURCE_UNREF
;
381 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
382 virgl_block_write(vws
->sock_fd
, &cmd
, sizeof(cmd
));
386 static int virgl_vtest_send_transfer_cmd(struct virgl_vtest_winsys
*vws
,
389 uint32_t level
, uint32_t stride
,
390 uint32_t layer_stride
,
391 const struct pipe_box
*box
,
394 uint32_t vtest_hdr
[VTEST_HDR_SIZE
];
395 uint32_t cmd
[VCMD_TRANSFER_HDR_SIZE
];
396 vtest_hdr
[VTEST_CMD_LEN
] = VCMD_TRANSFER_HDR_SIZE
;
397 vtest_hdr
[VTEST_CMD_ID
] = vcmd
;
399 /* The host expects the size in dwords so calculate the rounded up
401 if (vcmd
== VCMD_TRANSFER_PUT
)
402 vtest_hdr
[VTEST_CMD_LEN
] += (data_size
+ 3) / 4;
407 cmd
[3] = layer_stride
;
412 cmd
[8] = box
->height
;
415 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
416 virgl_block_write(vws
->sock_fd
, &cmd
, sizeof(cmd
));
421 static int virgl_vtest_send_transfer_cmd2(struct virgl_vtest_winsys
*vws
,
425 const struct pipe_box
*box
,
429 uint32_t vtest_hdr
[VTEST_HDR_SIZE
];
430 uint32_t cmd
[VCMD_TRANSFER2_HDR_SIZE
];
431 vtest_hdr
[VTEST_CMD_LEN
] = VCMD_TRANSFER2_HDR_SIZE
;
432 vtest_hdr
[VTEST_CMD_ID
] = vcmd
;
434 /* The host expects the size in dwords so calculate the rounded up
436 if (vcmd
== VCMD_TRANSFER_PUT2
)
437 vtest_hdr
[VTEST_CMD_LEN
] += (data_size
+ 3) / 4;
439 cmd
[VCMD_TRANSFER2_RES_HANDLE
] = handle
;
440 cmd
[VCMD_TRANSFER2_LEVEL
] = level
;
441 cmd
[VCMD_TRANSFER2_X
] = box
->x
;
442 cmd
[VCMD_TRANSFER2_Y
] = box
->y
;
443 cmd
[VCMD_TRANSFER2_Z
] = box
->z
;
444 cmd
[VCMD_TRANSFER2_WIDTH
] = box
->width
;
445 cmd
[VCMD_TRANSFER2_HEIGHT
] = box
->height
;
446 cmd
[VCMD_TRANSFER2_DEPTH
] = box
->depth
;
447 cmd
[VCMD_TRANSFER2_DATA_SIZE
] = data_size
;
448 cmd
[VCMD_TRANSFER2_OFFSET
] = offset
;
449 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
450 virgl_block_write(vws
->sock_fd
, &cmd
, sizeof(cmd
));
455 int virgl_vtest_send_transfer_get(struct virgl_vtest_winsys
*vws
,
457 uint32_t level
, uint32_t stride
,
458 uint32_t layer_stride
,
459 const struct pipe_box
*box
,
463 if (vws
->protocol_version
< 2)
464 return virgl_vtest_send_transfer_cmd(vws
, VCMD_TRANSFER_GET
, handle
,
465 level
, stride
, layer_stride
, box
,
468 return virgl_vtest_send_transfer_cmd2(vws
, VCMD_TRANSFER_GET2
, handle
,
469 level
, box
, data_size
, offset
);
472 int virgl_vtest_send_transfer_put(struct virgl_vtest_winsys
*vws
,
474 uint32_t level
, uint32_t stride
,
475 uint32_t layer_stride
,
476 const struct pipe_box
*box
,
480 if (vws
->protocol_version
< 2)
481 return virgl_vtest_send_transfer_cmd(vws
, VCMD_TRANSFER_PUT
, handle
,
482 level
, stride
, layer_stride
, box
,
485 return virgl_vtest_send_transfer_cmd2(vws
, VCMD_TRANSFER_PUT2
, handle
,
486 level
, box
, data_size
, offset
);
489 int virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys
*vws
,
493 return virgl_block_write(vws
->sock_fd
, data
, data_size
);
496 int virgl_vtest_recv_transfer_get_data(struct virgl_vtest_winsys
*vws
,
500 const struct pipe_box
*box
,
505 int hblocks
= util_format_get_nblocksy(format
, box
->height
);
507 line
= malloc(stride
);
509 virgl_block_read(vws
->sock_fd
, line
, stride
);
510 memcpy(ptr
, line
, util_format_get_stride(format
, box
->width
));
518 int virgl_vtest_busy_wait(struct virgl_vtest_winsys
*vws
, int handle
,
521 uint32_t vtest_hdr
[VTEST_HDR_SIZE
];
522 uint32_t cmd
[VCMD_BUSY_WAIT_SIZE
];
525 vtest_hdr
[VTEST_CMD_LEN
] = VCMD_BUSY_WAIT_SIZE
;
526 vtest_hdr
[VTEST_CMD_ID
] = VCMD_RESOURCE_BUSY_WAIT
;
527 cmd
[VCMD_BUSY_WAIT_HANDLE
] = handle
;
528 cmd
[VCMD_BUSY_WAIT_FLAGS
] = flags
;
530 virgl_block_write(vws
->sock_fd
, &vtest_hdr
, sizeof(vtest_hdr
));
531 virgl_block_write(vws
->sock_fd
, &cmd
, sizeof(cmd
));
533 ret
= virgl_block_read(vws
->sock_fd
, vtest_hdr
, sizeof(vtest_hdr
));
535 ret
= virgl_block_read(vws
->sock_fd
, result
, sizeof(result
));