Path: blob/21.2-virgl/src/gallium/winsys/virgl/vtest/virgl_vtest_socket.c
4566 views
/*1* Copyright 2014, 2015 Red Hat.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* on the rights to use, copy, modify, merge, publish, distribute, sub7* license, and/or sell copies of the Software, and to permit persons to whom8* the Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,18* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR19* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE20* USE OR OTHER DEALINGS IN THE SOFTWARE.21*/2223#include <sys/socket.h>24#include <errno.h>25#include <stdio.h>26#include <netinet/in.h>27#include <sys/un.h>28#include <unistd.h>2930#include <os/os_process.h>31#include <util/format/u_format.h>3233#include "virgl_vtest_winsys.h"34#include "virgl_vtest_public.h"3536/* block read/write routines */37static int virgl_block_write(int fd, void *buf, int size)38{39void *ptr = buf;40int left;41int ret;42left = size;43do {44ret = write(fd, ptr, left);45if (ret < 0)46return -errno;47left -= ret;48ptr += ret;49} while (left);50return size;51}5253static int virgl_block_read(int fd, void *buf, int size)54{55void *ptr = buf;56int left;57int ret;58left = size;59do {60ret = read(fd, ptr, left);61if (ret <= 0) {62fprintf(stderr,63"lost connection to rendering server on %d read %d %d\n",64size, ret, errno);65abort();66return ret < 0 ? -errno : 0;67}68left -= ret;69ptr += ret;70} while (left);71return size;72}7374static int virgl_vtest_receive_fd(int socket_fd)75{76struct cmsghdr *cmsgh;77struct msghdr msgh = { 0 };78char buf[CMSG_SPACE(sizeof(int))], c;79struct iovec iovec;8081iovec.iov_base = &c;82iovec.iov_len = sizeof(char);8384msgh.msg_name = NULL;85msgh.msg_namelen = 0;86msgh.msg_iov = &iovec;87msgh.msg_iovlen = 1;88msgh.msg_control = buf;89msgh.msg_controllen = sizeof(buf);90msgh.msg_flags = 0;9192int size = recvmsg(socket_fd, &msgh, 0);93if (size < 0) {94fprintf(stderr, "Failed with %s\n", strerror(errno));95return -1;96}9798cmsgh = CMSG_FIRSTHDR(&msgh);99if (!cmsgh) {100fprintf(stderr, "No headers available\n");101return -1;102}103104if (cmsgh->cmsg_level != SOL_SOCKET) {105fprintf(stderr, "invalid cmsg_level %d\n", cmsgh->cmsg_level);106return -1;107}108109if (cmsgh->cmsg_type != SCM_RIGHTS) {110fprintf(stderr, "invalid cmsg_type %d\n", cmsgh->cmsg_type);111return -1;112}113114return *((int *) CMSG_DATA(cmsgh));115}116117static int virgl_vtest_send_init(struct virgl_vtest_winsys *vws)118{119uint32_t buf[VTEST_HDR_SIZE];120const char *nstr = "virtest";121char cmdline[64];122int ret;123124ret = os_get_process_name(cmdline, 63);125if (ret == FALSE)126strcpy(cmdline, nstr);127#if defined(HAVE_PROGRAM_INVOCATION_NAME)128if (!strcmp(cmdline, "shader_runner")) {129const char *name;130/* hack to get better testname */131name = program_invocation_short_name;132name += strlen(name) + 1;133strncpy(cmdline, name, 63);134}135#endif136buf[VTEST_CMD_LEN] = strlen(cmdline) + 1;137buf[VTEST_CMD_ID] = VCMD_CREATE_RENDERER;138139virgl_block_write(vws->sock_fd, &buf, sizeof(buf));140virgl_block_write(vws->sock_fd, (void *)cmdline, strlen(cmdline) + 1);141return 0;142}143144static int virgl_vtest_negotiate_version(struct virgl_vtest_winsys *vws)145{146uint32_t vtest_hdr[VTEST_HDR_SIZE];147uint32_t version_buf[VCMD_PROTOCOL_VERSION_SIZE];148uint32_t busy_wait_buf[VCMD_BUSY_WAIT_SIZE];149uint32_t busy_wait_result[1];150ASSERTED int ret;151152vtest_hdr[VTEST_CMD_LEN] = VCMD_PING_PROTOCOL_VERSION_SIZE;153vtest_hdr[VTEST_CMD_ID] = VCMD_PING_PROTOCOL_VERSION;154virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));155156vtest_hdr[VTEST_CMD_LEN] = VCMD_BUSY_WAIT_SIZE;157vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;158busy_wait_buf[VCMD_BUSY_WAIT_HANDLE] = 0;159busy_wait_buf[VCMD_BUSY_WAIT_FLAGS] = 0;160virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));161virgl_block_write(vws->sock_fd, &busy_wait_buf, sizeof(busy_wait_buf));162163ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));164assert(ret);165166if (vtest_hdr[VTEST_CMD_ID] == VCMD_PING_PROTOCOL_VERSION) {167/* Read dummy busy_wait response */168ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));169assert(ret);170ret = virgl_block_read(vws->sock_fd, busy_wait_result, sizeof(busy_wait_result));171assert(ret);172173vtest_hdr[VTEST_CMD_LEN] = VCMD_PROTOCOL_VERSION_SIZE;174vtest_hdr[VTEST_CMD_ID] = VCMD_PROTOCOL_VERSION;175version_buf[VCMD_PROTOCOL_VERSION_VERSION] = VTEST_PROTOCOL_VERSION;176virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));177virgl_block_write(vws->sock_fd, &version_buf, sizeof(version_buf));178179ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));180assert(ret);181ret = virgl_block_read(vws->sock_fd, version_buf, sizeof(version_buf));182assert(ret);183return version_buf[VCMD_PROTOCOL_VERSION_VERSION];184}185186/* Read dummy busy_wait response */187assert(vtest_hdr[VTEST_CMD_ID] == VCMD_RESOURCE_BUSY_WAIT);188ret = virgl_block_read(vws->sock_fd, busy_wait_result, sizeof(busy_wait_result));189assert(ret);190191/* Old server, return version 0 */192return 0;193}194195int virgl_vtest_connect(struct virgl_vtest_winsys *vws)196{197struct sockaddr_un un;198int sock, ret;199200sock = socket(PF_UNIX, SOCK_STREAM, 0);201if (sock < 0)202return -1;203204memset(&un, 0, sizeof(un));205un.sun_family = AF_UNIX;206const char *override_socket_name = getenv("VTEST_SOCKET_NAME");207snprintf(un.sun_path, sizeof(un.sun_path), "%s", override_socket_name ?208override_socket_name : VTEST_DEFAULT_SOCKET_NAME);209210do {211ret = 0;212if (connect(sock, (struct sockaddr *)&un, sizeof(un)) < 0) {213ret = -errno;214}215} while (ret == -EINTR);216217vws->sock_fd = sock;218virgl_vtest_send_init(vws);219vws->protocol_version = virgl_vtest_negotiate_version(vws);220221/* Version 1 is deprecated. */222if (vws->protocol_version == 1)223vws->protocol_version = 0;224225return 0;226}227228int virgl_vtest_send_get_caps(struct virgl_vtest_winsys *vws,229struct virgl_drm_caps *caps)230{231uint32_t get_caps_buf[VTEST_HDR_SIZE * 2];232uint32_t resp_buf[VTEST_HDR_SIZE];233uint32_t caps_size = sizeof(struct virgl_caps_v2);234int ret;235get_caps_buf[VTEST_CMD_LEN] = 0;236get_caps_buf[VTEST_CMD_ID] = VCMD_GET_CAPS2;237get_caps_buf[VTEST_CMD_LEN + 2] = 0;238get_caps_buf[VTEST_CMD_ID + 2] = VCMD_GET_CAPS;239240virgl_block_write(vws->sock_fd, &get_caps_buf, sizeof(get_caps_buf));241242ret = virgl_block_read(vws->sock_fd, resp_buf, sizeof(resp_buf));243if (ret <= 0)244return 0;245246if (resp_buf[1] == 2) {247struct virgl_caps_v1 dummy;248uint32_t resp_size = resp_buf[0] - 1;249uint32_t dummy_size = 0;250if (resp_size > caps_size) {251dummy_size = resp_size - caps_size;252resp_size = caps_size;253}254255ret = virgl_block_read(vws->sock_fd, &caps->caps, resp_size);256257if (dummy_size)258ret = virgl_block_read(vws->sock_fd, &dummy, dummy_size);259260/* now read back the pointless caps v1 we requested */261ret = virgl_block_read(vws->sock_fd, resp_buf, sizeof(resp_buf));262if (ret <= 0)263return 0;264ret = virgl_block_read(vws->sock_fd, &dummy, sizeof(struct virgl_caps_v1));265} else266ret = virgl_block_read(vws->sock_fd, &caps->caps, sizeof(struct virgl_caps_v1));267268return 0;269}270271static int virgl_vtest_send_resource_create2(struct virgl_vtest_winsys *vws,272uint32_t handle,273enum pipe_texture_target target,274uint32_t format,275uint32_t bind,276uint32_t width,277uint32_t height,278uint32_t depth,279uint32_t array_size,280uint32_t last_level,281uint32_t nr_samples,282uint32_t size,283int *out_fd)284{285uint32_t res_create_buf[VCMD_RES_CREATE2_SIZE], vtest_hdr[VTEST_HDR_SIZE];286287vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE2_SIZE;288vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE2;289290res_create_buf[VCMD_RES_CREATE2_RES_HANDLE] = handle;291res_create_buf[VCMD_RES_CREATE2_TARGET] = target;292res_create_buf[VCMD_RES_CREATE2_FORMAT] = format;293res_create_buf[VCMD_RES_CREATE2_BIND] = bind;294res_create_buf[VCMD_RES_CREATE2_WIDTH] = width;295res_create_buf[VCMD_RES_CREATE2_HEIGHT] = height;296res_create_buf[VCMD_RES_CREATE2_DEPTH] = depth;297res_create_buf[VCMD_RES_CREATE2_ARRAY_SIZE] = array_size;298res_create_buf[VCMD_RES_CREATE2_LAST_LEVEL] = last_level;299res_create_buf[VCMD_RES_CREATE2_NR_SAMPLES] = nr_samples;300res_create_buf[VCMD_RES_CREATE2_DATA_SIZE] = size;301302virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));303virgl_block_write(vws->sock_fd, &res_create_buf, sizeof(res_create_buf));304305/* Multi-sampled textures have no backing store attached. */306if (size == 0)307return 0;308309*out_fd = virgl_vtest_receive_fd(vws->sock_fd);310if (*out_fd < 0) {311fprintf(stderr, "failed to get fd\n");312return -1;313}314315return 0;316}317318int virgl_vtest_send_resource_create(struct virgl_vtest_winsys *vws,319uint32_t handle,320enum pipe_texture_target target,321uint32_t format,322uint32_t bind,323uint32_t width,324uint32_t height,325uint32_t depth,326uint32_t array_size,327uint32_t last_level,328uint32_t nr_samples,329uint32_t size,330int *out_fd)331{332uint32_t res_create_buf[VCMD_RES_CREATE_SIZE], vtest_hdr[VTEST_HDR_SIZE];333334if (vws->protocol_version >= 2)335return virgl_vtest_send_resource_create2(vws, handle, target, format,336bind, width, height, depth,337array_size, last_level,338nr_samples, size, out_fd);339340vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE_SIZE;341vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE;342343res_create_buf[VCMD_RES_CREATE_RES_HANDLE] = handle;344res_create_buf[VCMD_RES_CREATE_TARGET] = target;345res_create_buf[VCMD_RES_CREATE_FORMAT] = format;346res_create_buf[VCMD_RES_CREATE_BIND] = bind;347res_create_buf[VCMD_RES_CREATE_WIDTH] = width;348res_create_buf[VCMD_RES_CREATE_HEIGHT] = height;349res_create_buf[VCMD_RES_CREATE_DEPTH] = depth;350res_create_buf[VCMD_RES_CREATE_ARRAY_SIZE] = array_size;351res_create_buf[VCMD_RES_CREATE_LAST_LEVEL] = last_level;352res_create_buf[VCMD_RES_CREATE_NR_SAMPLES] = nr_samples;353354virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));355virgl_block_write(vws->sock_fd, &res_create_buf, sizeof(res_create_buf));356357return 0;358}359360int virgl_vtest_submit_cmd(struct virgl_vtest_winsys *vws,361struct virgl_vtest_cmd_buf *cbuf)362{363uint32_t vtest_hdr[VTEST_HDR_SIZE];364365vtest_hdr[VTEST_CMD_LEN] = cbuf->base.cdw;366vtest_hdr[VTEST_CMD_ID] = VCMD_SUBMIT_CMD;367368virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));369virgl_block_write(vws->sock_fd, cbuf->buf, cbuf->base.cdw * 4);370return 0;371}372373int virgl_vtest_send_resource_unref(struct virgl_vtest_winsys *vws,374uint32_t handle)375{376uint32_t vtest_hdr[VTEST_HDR_SIZE];377uint32_t cmd[1];378vtest_hdr[VTEST_CMD_LEN] = 1;379vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_UNREF;380381cmd[0] = handle;382virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));383virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));384return 0;385}386387static int virgl_vtest_send_transfer_cmd(struct virgl_vtest_winsys *vws,388uint32_t vcmd,389uint32_t handle,390uint32_t level, uint32_t stride,391uint32_t layer_stride,392const struct pipe_box *box,393uint32_t data_size)394{395uint32_t vtest_hdr[VTEST_HDR_SIZE];396uint32_t cmd[VCMD_TRANSFER_HDR_SIZE];397vtest_hdr[VTEST_CMD_LEN] = VCMD_TRANSFER_HDR_SIZE;398vtest_hdr[VTEST_CMD_ID] = vcmd;399400/* The host expects the size in dwords so calculate the rounded up401* value here. */402if (vcmd == VCMD_TRANSFER_PUT)403vtest_hdr[VTEST_CMD_LEN] += (data_size + 3) / 4;404405cmd[0] = handle;406cmd[1] = level;407cmd[2] = stride;408cmd[3] = layer_stride;409cmd[4] = box->x;410cmd[5] = box->y;411cmd[6] = box->z;412cmd[7] = box->width;413cmd[8] = box->height;414cmd[9] = box->depth;415cmd[10] = data_size;416virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));417virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));418419return 0;420}421422static int virgl_vtest_send_transfer_cmd2(struct virgl_vtest_winsys *vws,423uint32_t vcmd,424uint32_t handle,425uint32_t level,426const struct pipe_box *box,427uint32_t data_size,428uint32_t offset)429{430uint32_t vtest_hdr[VTEST_HDR_SIZE];431uint32_t cmd[VCMD_TRANSFER2_HDR_SIZE];432vtest_hdr[VTEST_CMD_LEN] = VCMD_TRANSFER2_HDR_SIZE;433vtest_hdr[VTEST_CMD_ID] = vcmd;434435/* The host expects the size in dwords so calculate the rounded up436* value here. */437if (vcmd == VCMD_TRANSFER_PUT2)438vtest_hdr[VTEST_CMD_LEN] += (data_size + 3) / 4;439440cmd[VCMD_TRANSFER2_RES_HANDLE] = handle;441cmd[VCMD_TRANSFER2_LEVEL] = level;442cmd[VCMD_TRANSFER2_X] = box->x;443cmd[VCMD_TRANSFER2_Y] = box->y;444cmd[VCMD_TRANSFER2_Z] = box->z;445cmd[VCMD_TRANSFER2_WIDTH] = box->width;446cmd[VCMD_TRANSFER2_HEIGHT] = box->height;447cmd[VCMD_TRANSFER2_DEPTH] = box->depth;448cmd[VCMD_TRANSFER2_DATA_SIZE] = data_size;449cmd[VCMD_TRANSFER2_OFFSET] = offset;450virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));451virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));452453return 0;454}455456int virgl_vtest_send_transfer_get(struct virgl_vtest_winsys *vws,457uint32_t handle,458uint32_t level, uint32_t stride,459uint32_t layer_stride,460const struct pipe_box *box,461uint32_t data_size,462uint32_t offset)463{464if (vws->protocol_version < 2)465return virgl_vtest_send_transfer_cmd(vws, VCMD_TRANSFER_GET, handle,466level, stride, layer_stride, box,467data_size);468469return virgl_vtest_send_transfer_cmd2(vws, VCMD_TRANSFER_GET2, handle,470level, box, data_size, offset);471}472473int virgl_vtest_send_transfer_put(struct virgl_vtest_winsys *vws,474uint32_t handle,475uint32_t level, uint32_t stride,476uint32_t layer_stride,477const struct pipe_box *box,478uint32_t data_size,479uint32_t offset)480{481if (vws->protocol_version < 2)482return virgl_vtest_send_transfer_cmd(vws, VCMD_TRANSFER_PUT, handle,483level, stride, layer_stride, box,484data_size);485486return virgl_vtest_send_transfer_cmd2(vws, VCMD_TRANSFER_PUT2, handle,487level, box, data_size, offset);488}489490int virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys *vws,491void *data,492uint32_t data_size)493{494return virgl_block_write(vws->sock_fd, data, data_size);495}496497int virgl_vtest_recv_transfer_get_data(struct virgl_vtest_winsys *vws,498void *data,499uint32_t data_size,500uint32_t stride,501const struct pipe_box *box,502uint32_t format)503{504void *line;505void *ptr = data;506int hblocks = util_format_get_nblocksy(format, box->height);507508line = malloc(stride);509while (hblocks) {510virgl_block_read(vws->sock_fd, line, stride);511memcpy(ptr, line, util_format_get_stride(format, box->width));512ptr += stride;513hblocks--;514}515free(line);516return 0;517}518519int virgl_vtest_busy_wait(struct virgl_vtest_winsys *vws, int handle,520int flags)521{522uint32_t vtest_hdr[VTEST_HDR_SIZE];523uint32_t cmd[VCMD_BUSY_WAIT_SIZE];524uint32_t result[1];525ASSERTED int ret;526vtest_hdr[VTEST_CMD_LEN] = VCMD_BUSY_WAIT_SIZE;527vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;528cmd[VCMD_BUSY_WAIT_HANDLE] = handle;529cmd[VCMD_BUSY_WAIT_FLAGS] = flags;530531virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr));532virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd));533534ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr));535assert(ret);536ret = virgl_block_read(vws->sock_fd, result, sizeof(result));537assert(ret);538return result[0];539}540541542