From b3b82fe8ea1f7d02c93513920143cba2fe145b6c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 13 Mar 2015 14:15:47 +1000 Subject: virgl/vtest: add vtest driver virgl/vtest is a swrast driver that allows the virgl acceleration to be tested without having a virtual machine. The backend has a unix socket server that this connects to. This is run by setting LIBGL_ALWAYS_SOFTWARE=y GALLIUM_DRIVER=virpipe In this mode all renderering is sent over a socket to the remote renderer, and the results are readback and copies to the screen using drisw. This works well enough to develop new features and to help debug. Signed-off-by: Dave Airlie --- src/gallium/winsys/virgl/vtest/Makefile.am | 33 ++ src/gallium/winsys/virgl/vtest/Makefile.sources | 3 + .../winsys/virgl/vtest/virgl_vtest_public.h | 30 + .../winsys/virgl/vtest/virgl_vtest_socket.c | 288 +++++++++ .../winsys/virgl/vtest/virgl_vtest_winsys.c | 653 +++++++++++++++++++++ .../winsys/virgl/vtest/virgl_vtest_winsys.h | 132 +++++ src/gallium/winsys/virgl/vtest/vtest_protocol.h | 88 +++ 7 files changed, 1227 insertions(+) create mode 100644 src/gallium/winsys/virgl/vtest/Makefile.am create mode 100644 src/gallium/winsys/virgl/vtest/Makefile.sources create mode 100644 src/gallium/winsys/virgl/vtest/virgl_vtest_public.h create mode 100644 src/gallium/winsys/virgl/vtest/virgl_vtest_socket.c create mode 100644 src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c create mode 100644 src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.h create mode 100644 src/gallium/winsys/virgl/vtest/vtest_protocol.h (limited to 'src/gallium/winsys/virgl/vtest') diff --git a/src/gallium/winsys/virgl/vtest/Makefile.am b/src/gallium/winsys/virgl/vtest/Makefile.am new file mode 100644 index 00000000000..81270d7b74b --- /dev/null +++ b/src/gallium/winsys/virgl/vtest/Makefile.am @@ -0,0 +1,33 @@ +# Copyright © 2015 Red Hat +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +include Makefile.sources +include $(top_srcdir)/src/gallium/Automake.inc + +AM_CFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/gallium/drivers \ + $(GALLIUM_CFLAGS) + +noinst_LTLIBRARIES = libvirglvtest.la + +libvirglvtest_la_SOURCES = $(C_SOURCES) diff --git a/src/gallium/winsys/virgl/vtest/Makefile.sources b/src/gallium/winsys/virgl/vtest/Makefile.sources new file mode 100644 index 00000000000..ab72560849a --- /dev/null +++ b/src/gallium/winsys/virgl/vtest/Makefile.sources @@ -0,0 +1,3 @@ +C_SOURCES := \ + virgl_vtest_winsys.c \ + virgl_vtest_socket.c \ No newline at end of file diff --git a/src/gallium/winsys/virgl/vtest/virgl_vtest_public.h b/src/gallium/winsys/virgl/vtest/virgl_vtest_public.h new file mode 100644 index 00000000000..72336499b44 --- /dev/null +++ b/src/gallium/winsys/virgl/vtest/virgl_vtest_public.h @@ -0,0 +1,30 @@ +/* + * Copyright 2014, 2015 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef VIRGL_VTEST_PUBLIC_H +#define VIRGL_VTEST_PUBLIC_H + +struct virgl_winsys; + +struct virgl_winsys *virgl_vtest_winsys_wrap(struct sw_winsys *sws); + +#endif diff --git a/src/gallium/winsys/virgl/vtest/virgl_vtest_socket.c b/src/gallium/winsys/virgl/vtest/virgl_vtest_socket.c new file mode 100644 index 00000000000..48dff8d0c17 --- /dev/null +++ b/src/gallium/winsys/virgl/vtest/virgl_vtest_socket.c @@ -0,0 +1,288 @@ +/* + * Copyright 2014, 2015 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#define _FILE_OFFSET_BITS 64 + +#include "virgl_vtest_winsys.h" +#include "virgl_vtest_public.h" +#include +#include +#include +#include +#include +#include + +#include +#include +/* connect to remote socket */ +#define VTEST_SOCKET_NAME "/tmp/.virgl_test" + +/* block read/write routines */ +static int virgl_block_write(int fd, void *buf, int size) +{ + void *ptr = buf; + int left; + int ret; + left = size; + do { + ret = write(fd, ptr, left); + if (ret < 0) + return -errno; + left -= ret; + ptr += ret; + } while (left); + return size; +} + +static int virgl_block_read(int fd, void *buf, int size) +{ + void *ptr = buf; + int left; + int ret; + left = size; + do { + ret = read(fd, ptr, left); + if (ret <= 0) { + fprintf(stderr, "lost connection to rendering server on %d read %d %d\n", size, ret, errno); + abort(); + return ret < 0 ? -errno : 0; + } + left -= ret; + ptr += ret; + } while (left); + return size; +} + +static int virgl_vtest_send_init(struct virgl_vtest_winsys *vws) +{ + uint32_t buf[VTEST_HDR_SIZE]; + const char *nstr = "virtest"; + char cmdline[64]; + int ret; + + ret = os_get_process_name(cmdline, 63); + if (ret == FALSE) + strcpy(cmdline, nstr); +#if defined(__GLIBC__) || defined(__CYGWIN__) + if (!strcmp(cmdline, "shader_runner")) { + const char *name; + /* hack to get better testname */ + name = program_invocation_short_name; + name += strlen(name) + 1; + strncpy(cmdline, name, 63); + } +#endif + buf[VTEST_CMD_LEN] = strlen(cmdline) + 1; + buf[VTEST_CMD_ID] = VCMD_CREATE_RENDERER; + + virgl_block_write(vws->sock_fd, &buf, sizeof(buf)); + virgl_block_write(vws->sock_fd, (void *)cmdline, strlen(cmdline) + 1); + return 0; +} + +int virgl_vtest_connect(struct virgl_vtest_winsys *vws) +{ + struct sockaddr_un un; + int sock, ret; + + sock = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + snprintf(un.sun_path, sizeof(un.sun_path), "%s", VTEST_SOCKET_NAME); + + do { + ret = 0; + if (connect(sock, (struct sockaddr *)&un, sizeof(un)) < 0) { + ret = -errno; + } + } while (ret == -EINTR); + + vws->sock_fd = sock; + virgl_vtest_send_init(vws); + return 0; +} + +int virgl_vtest_send_get_caps(struct virgl_vtest_winsys *vws, + struct virgl_drm_caps *caps) +{ + uint32_t get_caps_buf[VTEST_HDR_SIZE]; + uint32_t resp_buf[VTEST_HDR_SIZE]; + + int ret; + get_caps_buf[VTEST_CMD_LEN] = 0; + get_caps_buf[VTEST_CMD_ID] = VCMD_GET_CAPS; + + virgl_block_write(vws->sock_fd, &get_caps_buf, sizeof(get_caps_buf)); + + ret = virgl_block_read(vws->sock_fd, resp_buf, sizeof(resp_buf)); + if (ret <= 0) + return 0; + + ret = virgl_block_read(vws->sock_fd, &caps->caps, sizeof(union virgl_caps)); + + return 0; +} + +int 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 res_create_buf[VCMD_RES_CREATE_SIZE], vtest_hdr[VTEST_HDR_SIZE]; + + vtest_hdr[VTEST_CMD_LEN] = VCMD_RES_CREATE_SIZE; + vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_CREATE; + + res_create_buf[VCMD_RES_CREATE_RES_HANDLE] = handle; + res_create_buf[VCMD_RES_CREATE_TARGET] = target; + res_create_buf[VCMD_RES_CREATE_FORMAT] = format; + res_create_buf[VCMD_RES_CREATE_BIND] = bind; + res_create_buf[VCMD_RES_CREATE_WIDTH] = width; + res_create_buf[VCMD_RES_CREATE_HEIGHT] = height; + res_create_buf[VCMD_RES_CREATE_DEPTH] = depth; + res_create_buf[VCMD_RES_CREATE_ARRAY_SIZE] = array_size; + res_create_buf[VCMD_RES_CREATE_LAST_LEVEL] = last_level; + res_create_buf[VCMD_RES_CREATE_NR_SAMPLES] = nr_samples; + + virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr)); + virgl_block_write(vws->sock_fd, &res_create_buf, sizeof(res_create_buf)); + + return 0; +} + +int virgl_vtest_submit_cmd(struct virgl_vtest_winsys *vws, + struct virgl_vtest_cmd_buf *cbuf) +{ + uint32_t vtest_hdr[VTEST_HDR_SIZE]; + + vtest_hdr[VTEST_CMD_LEN] = cbuf->base.cdw; + vtest_hdr[VTEST_CMD_ID] = VCMD_SUBMIT_CMD; + + virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr)); + virgl_block_write(vws->sock_fd, cbuf->buf, cbuf->base.cdw * 4); + return 0; +} + +int virgl_vtest_send_resource_unref(struct virgl_vtest_winsys *vws, + uint32_t handle) +{ + uint32_t vtest_hdr[VTEST_HDR_SIZE]; + uint32_t cmd[1]; + vtest_hdr[VTEST_CMD_LEN] = 1; + vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_UNREF; + + cmd[0] = handle; + virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr)); + virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd)); + return 0; +} + +int 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) +{ + uint32_t vtest_hdr[VTEST_HDR_SIZE]; + uint32_t cmd[VCMD_TRANSFER_HDR_SIZE]; + bool is_put = (vcmd == VCMD_TRANSFER_PUT); + vtest_hdr[VTEST_CMD_LEN] = VCMD_TRANSFER_HDR_SIZE + (is_put ? (data_size + 3 / 4) : 0); + vtest_hdr[VTEST_CMD_ID] = vcmd; + + cmd[0] = handle; + cmd[1] = level; + cmd[2] = stride; + cmd[3] = layer_stride; + cmd[4] = box->x; + cmd[5] = box->y; + cmd[6] = box->z; + cmd[7] = box->width; + cmd[8] = box->height; + cmd[9] = box->depth; + cmd[10] = data_size; + virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr)); + virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd)); + + return 0; +} + +int virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys *vws, + void *data, + uint32_t data_size) +{ + return virgl_block_write(vws->sock_fd, data, data_size); +} + +int 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) +{ + void *line = malloc(stride); + void *ptr = data; + int hblocks = util_format_get_nblocksy(format, box->height); + + line = malloc(stride); + while (hblocks) { + virgl_block_read(vws->sock_fd, line, stride); + memcpy(ptr, line, util_format_get_stride(format, box->width)); + ptr += stride; + hblocks--; + } + free(line); + return 0; +} + +int virgl_vtest_busy_wait(struct virgl_vtest_winsys *vws, int handle, + int flags) +{ + uint32_t vtest_hdr[VTEST_HDR_SIZE]; + uint32_t cmd[VCMD_BUSY_WAIT_SIZE]; + uint32_t result[1]; + int ret; + vtest_hdr[VTEST_CMD_LEN] = VCMD_BUSY_WAIT_SIZE; + vtest_hdr[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT; + cmd[VCMD_BUSY_WAIT_HANDLE] = handle; + cmd[VCMD_BUSY_WAIT_FLAGS] = flags; + + virgl_block_write(vws->sock_fd, &vtest_hdr, sizeof(vtest_hdr)); + virgl_block_write(vws->sock_fd, &cmd, sizeof(cmd)); + + ret = virgl_block_read(vws->sock_fd, vtest_hdr, sizeof(vtest_hdr)); + assert(ret); + ret = virgl_block_read(vws->sock_fd, result, sizeof(result)); + assert(ret); + return result[0]; +} diff --git a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c new file mode 100644 index 00000000000..9002d40450b --- /dev/null +++ b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.c @@ -0,0 +1,653 @@ +/* + * Copyright 2014, 2015 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#define _FILE_OFFSET_BITS 64 + +#include +#include "virgl_vtest_winsys.h" +#include "virgl_vtest_public.h" +#include "util/u_memory.h" +#include "util/u_format.h" +#include "util/u_inlines.h" +#include "state_tracker/drm_driver.h" +#include "os/os_time.h" + +static void *virgl_vtest_resource_map(struct virgl_winsys *vws, struct virgl_hw_res *res); +static void virgl_vtest_resource_unmap(struct virgl_winsys *vws, struct virgl_hw_res *res); +static inline boolean can_cache_resource(struct virgl_hw_res *res) +{ + return res->cacheable == TRUE; +} + +static uint32_t vtest_get_transfer_size(struct virgl_hw_res *res, + const struct pipe_box *box, + uint32_t stride, uint32_t layer_stride, + uint32_t level, uint32_t *valid_stride_p) +{ + uint32_t valid_stride, valid_layer_stride; + + valid_stride = util_format_get_stride(res->format, box->width); + if (stride) { + if (box->height > 1) + valid_stride = stride; + } + + valid_layer_stride = util_format_get_2d_size(res->format, valid_stride, + box->height); + if (layer_stride) { + if (box->depth > 1) + valid_layer_stride = layer_stride; + } + + *valid_stride_p = valid_stride; + return valid_layer_stride * box->depth; +} + +static int +virgl_vtest_transfer_put(struct virgl_winsys *vws, + struct virgl_hw_res *res, + const struct pipe_box *box, + uint32_t stride, uint32_t layer_stride, + uint32_t buf_offset, uint32_t level) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + uint32_t size; + void *ptr; + uint32_t valid_stride; + + size = vtest_get_transfer_size(res, box, stride, layer_stride, level, &valid_stride); + + virgl_vtest_send_transfer_cmd(vtws, VCMD_TRANSFER_PUT, res->res_handle, + level, stride, layer_stride, + box, size); + ptr = virgl_vtest_resource_map(vws, res); + virgl_vtest_send_transfer_put_data(vtws, ptr + buf_offset, size); + virgl_vtest_resource_unmap(vws, res); + return 0; +} + +static int +virgl_vtest_transfer_get(struct virgl_winsys *vws, + struct virgl_hw_res *res, + const struct pipe_box *box, + uint32_t stride, uint32_t layer_stride, + uint32_t buf_offset, uint32_t level) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + uint32_t size; + void *ptr; + uint32_t valid_stride; + + size = vtest_get_transfer_size(res, box, stride, layer_stride, level, &valid_stride); + + virgl_vtest_send_transfer_cmd(vtws, VCMD_TRANSFER_GET, res->res_handle, + level, stride, layer_stride, + box, size); + + + ptr = virgl_vtest_resource_map(vws, res); + virgl_vtest_recv_transfer_get_data(vtws, ptr + buf_offset, size, valid_stride, box, res->format); + virgl_vtest_resource_unmap(vws, res); + return 0; +} + +static void virgl_hw_res_destroy(struct virgl_vtest_winsys *vtws, + struct virgl_hw_res *res) +{ + virgl_vtest_send_resource_unref(vtws, res->res_handle); + if (res->dt) + vtws->sws->displaytarget_destroy(vtws->sws, res->dt); + free(res->ptr); + FREE(res); +} + +static boolean virgl_vtest_resource_is_busy(struct virgl_vtest_winsys *vtws, + struct virgl_hw_res *res) +{ + /* implement busy check */ + int ret; + ret = virgl_vtest_busy_wait(vtws, res->res_handle, 0); + + if (ret < 0) + return FALSE; + + return ret == 1 ? TRUE : FALSE; +} + +static void +virgl_cache_flush(struct virgl_vtest_winsys *vtws) +{ + struct list_head *curr, *next; + struct virgl_hw_res *res; + + pipe_mutex_lock(vtws->mutex); + curr = vtws->delayed.next; + next = curr->next; + + while (curr != &vtws->delayed) { + res = LIST_ENTRY(struct virgl_hw_res, curr, head); + LIST_DEL(&res->head); + virgl_hw_res_destroy(vtws, res); + curr = next; + next = curr->next; + } + pipe_mutex_unlock(vtws->mutex); +} + +static void +virgl_cache_list_check_free(struct virgl_vtest_winsys *vtws) +{ + struct list_head *curr, *next; + struct virgl_hw_res *res; + int64_t now; + + now = os_time_get(); + curr = vtws->delayed.next; + next = curr->next; + while (curr != &vtws->delayed) { + res = LIST_ENTRY(struct virgl_hw_res, curr, head); + if (!os_time_timeout(res->start, res->end, now)) + break; + + LIST_DEL(&res->head); + virgl_hw_res_destroy(vtws, res); + curr = next; + next = curr->next; + } +} + +static void virgl_vtest_resource_reference(struct virgl_vtest_winsys *vtws, + struct virgl_hw_res **dres, + struct virgl_hw_res *sres) +{ + struct virgl_hw_res *old = *dres; + if (pipe_reference(&(*dres)->reference, &sres->reference)) { + if (!can_cache_resource(old)) { + virgl_hw_res_destroy(vtws, old); + } else { + pipe_mutex_lock(vtws->mutex); + virgl_cache_list_check_free(vtws); + + old->start = os_time_get(); + old->end = old->start + vtws->usecs; + LIST_ADDTAIL(&old->head, &vtws->delayed); + vtws->num_delayed++; + pipe_mutex_unlock(vtws->mutex); + } + } + *dres = sres; +} + +static struct virgl_hw_res *virgl_vtest_winsys_resource_create( + struct virgl_winsys *vws, + 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) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + struct virgl_hw_res *res; + static int handle = 1; + + res = CALLOC_STRUCT(virgl_hw_res); + if (!res) + return NULL; + + if (bind & (VIRGL_BIND_DISPLAY_TARGET | VIRGL_BIND_SCANOUT)) { + res->dt = vtws->sws->displaytarget_create(vtws->sws, + bind, + format, + width, + height, + 64, + &res->stride); + + } else { + res->ptr = align_malloc(size, 64); + if (!res->ptr) { + FREE(res); + return NULL; + } + } + + res->bind = bind; + res->format = format; + res->height = height; + res->width = width; + virgl_vtest_send_resource_create(vtws, handle, target, format, bind, width, + height, depth, array_size, last_level, + nr_samples); + + res->res_handle = handle++; + pipe_reference_init(&res->reference, 1); + return res; +} + +static void virgl_vtest_winsys_resource_unref(struct virgl_winsys *vws, + struct virgl_hw_res *hres) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + virgl_vtest_resource_reference(vtws, &hres, NULL); +} + +static void *virgl_vtest_resource_map(struct virgl_winsys *vws, struct virgl_hw_res *res) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + + if (res->dt) { + return vtws->sws->displaytarget_map(vtws->sws, res->dt, 0); + } else { + res->mapped = res->ptr; + return res->mapped; + } +} + +static void virgl_vtest_resource_unmap(struct virgl_winsys *vws, struct virgl_hw_res *res) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + if (res->mapped) + res->mapped = NULL; + + if (res->dt) + vtws->sws->displaytarget_unmap(vtws->sws, res->dt); +} + +static void virgl_vtest_resource_wait(struct virgl_winsys *vws, struct virgl_hw_res *res) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + + virgl_vtest_busy_wait(vtws, res->res_handle, VCMD_BUSY_WAIT_FLAG_WAIT); +} + +static inline int virgl_is_res_compat(struct virgl_vtest_winsys *vtws, + struct virgl_hw_res *res, + uint32_t size, uint32_t bind, uint32_t format) +{ + if (res->bind != bind) + return 0; + if (res->format != format) + return 0; + if (res->size < size) + return 0; + if (res->size > size * 2) + return 0; + + if (virgl_vtest_resource_is_busy(vtws, res)) { + return -1; + } + + return 1; +} + +static struct virgl_hw_res *virgl_vtest_winsys_resource_cache_create(struct virgl_winsys *vws, + 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) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + struct virgl_hw_res *res, *curr_res; + struct list_head *curr, *next; + int64_t now; + int ret; + + /* only store binds for vertex/index/const buffers */ + if (bind != VIRGL_BIND_CONSTANT_BUFFER && bind != VIRGL_BIND_INDEX_BUFFER && + bind != VIRGL_BIND_VERTEX_BUFFER && bind != VIRGL_BIND_CUSTOM) + goto alloc; + + pipe_mutex_lock(vtws->mutex); + + res = NULL; + curr = vtws->delayed.next; + next = curr->next; + + now = os_time_get(); + while (curr != &vtws->delayed) { + curr_res = LIST_ENTRY(struct virgl_hw_res, curr, head); + + if (!res && (ret = virgl_is_res_compat(vtws, curr_res, size, bind, format) > 0)) + res = curr_res; + else if (os_time_timeout(curr_res->start, curr_res->end, now)) { + LIST_DEL(&curr_res->head); + virgl_hw_res_destroy(vtws, curr_res); + } else + break; + + if (ret == -1) + break; + + curr = next; + next = curr->next; + } + + if (!res && ret != -1) { + while (curr != &vtws->delayed) { + curr_res = LIST_ENTRY(struct virgl_hw_res, curr, head); + ret = virgl_is_res_compat(vtws, curr_res, size, bind, format); + if (ret > 0) { + res = curr_res; + break; + } + if (ret == -1) + break; + curr = next; + next = curr->next; + } + } + + if (res) { + LIST_DEL(&res->head); + --vtws->num_delayed; + pipe_mutex_unlock(vtws->mutex); + pipe_reference_init(&res->reference, 1); + return res; + } + + pipe_mutex_unlock(vtws->mutex); + +alloc: + res = virgl_vtest_winsys_resource_create(vws, target, format, bind, + width, height, depth, array_size, + last_level, nr_samples, size); + if (bind == VIRGL_BIND_CONSTANT_BUFFER || bind == VIRGL_BIND_INDEX_BUFFER || + bind == VIRGL_BIND_VERTEX_BUFFER) + res->cacheable = TRUE; + return res; +} + +static struct virgl_cmd_buf *virgl_vtest_cmd_buf_create(struct virgl_winsys *vws) +{ + struct virgl_vtest_cmd_buf *cbuf; + + cbuf = CALLOC_STRUCT(virgl_vtest_cmd_buf); + if (!cbuf) + return NULL; + + cbuf->nres = 512; + cbuf->res_bo = (struct virgl_hw_res **) + CALLOC(cbuf->nres, sizeof(struct virgl_hw_buf*)); + if (!cbuf->res_bo) { + FREE(cbuf); + return NULL; + } + cbuf->ws = vws; + cbuf->base.buf = cbuf->buf; + return &cbuf->base; +} + +static void virgl_vtest_cmd_buf_destroy(struct virgl_cmd_buf *_cbuf) +{ + struct virgl_vtest_cmd_buf *cbuf = (struct virgl_vtest_cmd_buf *)_cbuf; + + FREE(cbuf->res_bo); + FREE(cbuf); +} + +static boolean virgl_vtest_lookup_res(struct virgl_vtest_cmd_buf *cbuf, + struct virgl_hw_res *res) +{ + unsigned hash = res->res_handle & (sizeof(cbuf->is_handle_added)-1); + int i; + + if (cbuf->is_handle_added[hash]) { + i = cbuf->reloc_indices_hashlist[hash]; + if (cbuf->res_bo[i] == res) + return true; + + for (i = 0; i < cbuf->cres; i++) { + if (cbuf->res_bo[i] == res) { + cbuf->reloc_indices_hashlist[hash] = i; + return true; + } + } + } + return false; +} + +static void virgl_vtest_release_all_res(struct virgl_vtest_winsys *vtws, + struct virgl_vtest_cmd_buf *cbuf) +{ + int i; + + for (i = 0; i < cbuf->cres; i++) { + p_atomic_dec(&cbuf->res_bo[i]->num_cs_references); + virgl_vtest_resource_reference(vtws, &cbuf->res_bo[i], NULL); + } + cbuf->cres = 0; +} + +static void virgl_vtest_add_res(struct virgl_vtest_winsys *vtws, + struct virgl_vtest_cmd_buf *cbuf, struct virgl_hw_res *res) +{ + unsigned hash = res->res_handle & (sizeof(cbuf->is_handle_added)-1); + + if (cbuf->cres > cbuf->nres) { + fprintf(stderr,"failure to add relocation\n"); + return; + } + + cbuf->res_bo[cbuf->cres] = NULL; + virgl_vtest_resource_reference(vtws, &cbuf->res_bo[cbuf->cres], res); + cbuf->is_handle_added[hash] = TRUE; + + cbuf->reloc_indices_hashlist[hash] = cbuf->cres; + p_atomic_inc(&res->num_cs_references); + cbuf->cres++; +} + +static int virgl_vtest_winsys_submit_cmd(struct virgl_winsys *vws, struct virgl_cmd_buf *_cbuf) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + struct virgl_vtest_cmd_buf *cbuf = (struct virgl_vtest_cmd_buf *)_cbuf; + int ret; + + if (cbuf->base.cdw == 0) + return 0; + + ret = virgl_vtest_submit_cmd(vtws, cbuf); + + virgl_vtest_release_all_res(vtws, cbuf); + memset(cbuf->is_handle_added, 0, sizeof(cbuf->is_handle_added)); + cbuf->base.cdw = 0; + return ret; +} + +static void virgl_vtest_emit_res(struct virgl_winsys *vws, struct virgl_cmd_buf *_cbuf, struct virgl_hw_res *res, boolean write_buf) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + struct virgl_vtest_cmd_buf *cbuf = (struct virgl_vtest_cmd_buf *)_cbuf; + boolean already_in_list = virgl_vtest_lookup_res(cbuf, res); + + if (write_buf) + cbuf->base.buf[cbuf->base.cdw++] = res->res_handle; + if (!already_in_list) + virgl_vtest_add_res(vtws, cbuf, res); +} + +static boolean virgl_vtest_res_is_ref(struct virgl_winsys *vws, + struct virgl_cmd_buf *_cbuf, + struct virgl_hw_res *res) +{ + if (!res->num_cs_references) + return FALSE; + + return TRUE; +} + +static int virgl_vtest_get_caps(struct virgl_winsys *vws, struct virgl_drm_caps *caps) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + return virgl_vtest_send_get_caps(vtws, caps); +} + +static struct pipe_fence_handle * +virgl_cs_create_fence(struct virgl_winsys *vws) +{ + struct virgl_hw_res *res; + + res = virgl_vtest_winsys_resource_cache_create(vws, + PIPE_BUFFER, + PIPE_FORMAT_R8_UNORM, + PIPE_BIND_CUSTOM, + 8, 1, 1, 0, 0, 0, 8); + + return (struct pipe_fence_handle *)res; +} + +static bool virgl_fence_wait(struct virgl_winsys *vws, + struct pipe_fence_handle *fence, + uint64_t timeout) +{ + struct virgl_vtest_winsys *vdws = virgl_vtest_winsys(vws); + struct virgl_hw_res *res = (struct virgl_hw_res *)fence; + + if (timeout == 0) + return virgl_vtest_resource_is_busy(vdws, res); + + if (timeout != PIPE_TIMEOUT_INFINITE) { + int64_t start_time = os_time_get(); + timeout /= 1000; + while (virgl_vtest_resource_is_busy(vdws, res)) { + if (os_time_get() - start_time >= timeout) + return FALSE; + os_time_sleep(10); + } + return TRUE; + } + virgl_vtest_resource_wait(vws, res); + return TRUE; +} + +static void virgl_fence_reference(struct virgl_winsys *vws, + struct pipe_fence_handle **dst, + struct pipe_fence_handle *src) +{ + struct virgl_vtest_winsys *vdws = virgl_vtest_winsys(vws); + virgl_vtest_resource_reference(vdws, (struct virgl_hw_res **)dst, + (struct virgl_hw_res *)src); +} + +static void virgl_vtest_flush_frontbuffer(struct virgl_winsys *vws, + struct virgl_hw_res *res, + unsigned level, unsigned layer, + void *winsys_drawable_handle, + struct pipe_box *sub_box) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + struct pipe_box box; + void *map; + uint32_t size; + uint32_t offset = 0, valid_stride; + if (!res->dt) + return; + + memset(&box, 0, sizeof(box)); + + if (sub_box) { + box = *sub_box; + offset = (res->stride * (box.y / util_format_get_blockheight(res->format))) + (box.x / util_format_get_blockwidth(res->format)) * util_format_get_blocksize(res->format); + } else { + box.z = layer; + box.width = res->width; + box.height = res->height; + box.depth = 1; + } + + size = vtest_get_transfer_size(res, &box, res->stride, 0, level, &valid_stride); + + virgl_vtest_busy_wait(vtws, res->res_handle, VCMD_BUSY_WAIT_FLAG_WAIT); + map = vtws->sws->displaytarget_map(vtws->sws, res->dt, 0); + + /* execute a transfer */ + virgl_vtest_send_transfer_cmd(vtws, VCMD_TRANSFER_GET, res->res_handle, + level, res->stride, 0, &box, size); + virgl_vtest_recv_transfer_get_data(vtws, map + offset, size, valid_stride, &box, res->format); + vtws->sws->displaytarget_unmap(vtws->sws, res->dt); + + vtws->sws->displaytarget_display(vtws->sws, res->dt, winsys_drawable_handle, sub_box); +} + +static void +virgl_vtest_winsys_destroy(struct virgl_winsys *vws) +{ + struct virgl_vtest_winsys *vtws = virgl_vtest_winsys(vws); + + virgl_cache_flush(vtws); + + pipe_mutex_destroy(vtws->mutex); + FREE(vtws); +} + +struct virgl_winsys * +virgl_vtest_winsys_wrap(struct sw_winsys *sws) +{ + struct virgl_vtest_winsys *vtws; + + vtws = CALLOC_STRUCT(virgl_vtest_winsys); + if (!vtws) + return NULL; + + virgl_vtest_connect(vtws); + vtws->sws = sws; + + vtws->usecs = 1000000; + LIST_INITHEAD(&vtws->delayed); + pipe_mutex_init(vtws->mutex); + + vtws->base.destroy = virgl_vtest_winsys_destroy; + + vtws->base.transfer_put = virgl_vtest_transfer_put; + vtws->base.transfer_get = virgl_vtest_transfer_get; + + vtws->base.resource_create = virgl_vtest_winsys_resource_cache_create; + vtws->base.resource_unref = virgl_vtest_winsys_resource_unref; + vtws->base.resource_map = virgl_vtest_resource_map; + vtws->base.resource_wait = virgl_vtest_resource_wait; + vtws->base.cmd_buf_create = virgl_vtest_cmd_buf_create; + vtws->base.cmd_buf_destroy = virgl_vtest_cmd_buf_destroy; + vtws->base.submit_cmd = virgl_vtest_winsys_submit_cmd; + + vtws->base.emit_res = virgl_vtest_emit_res; + vtws->base.res_is_referenced = virgl_vtest_res_is_ref; + vtws->base.get_caps = virgl_vtest_get_caps; + + vtws->base.cs_create_fence = virgl_cs_create_fence; + vtws->base.fence_wait = virgl_fence_wait; + vtws->base.fence_reference = virgl_fence_reference; + + vtws->base.flush_frontbuffer = virgl_vtest_flush_frontbuffer; + + return &vtws->base; +} diff --git a/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.h b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.h new file mode 100644 index 00000000000..3967befa1a9 --- /dev/null +++ b/src/gallium/winsys/virgl/vtest/virgl_vtest_winsys.h @@ -0,0 +1,132 @@ +/* + * Copyright 2014, 2015 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef VIRGL_DRM_WINSYS_H +#define VIRGL_DRM_WINSYS_H + +#include +#include "pipe/p_compiler.h" +#include "pipe/p_defines.h" +#include "pipe/p_state.h" +#include "state_tracker/sw_winsys.h" +#include "../drm/virgl_hw.h" +#include "virgl/virgl_winsys.h" +#include "util/list.h" +#include "os/os_thread.h" + +#include "vtest_protocol.h" +struct virgl_vtest_winsys { + struct virgl_winsys base; + + struct sw_winsys *sws; + + /* fd to remote renderer */ + int sock_fd; + + struct list_head delayed; + int num_delayed; + unsigned usecs; + pipe_mutex mutex; +}; + +struct virgl_hw_res { + struct pipe_reference reference; + uint32_t res_handle; + int num_cs_references; + + void *ptr; + int size; + + uint32_t format; + uint32_t stride; + uint32_t width; + uint32_t height; + + struct sw_displaytarget *dt; + void *mapped; + + struct list_head head; + uint32_t bind; + boolean cacheable; + int64_t start, end; + +}; + +struct virgl_vtest_cmd_buf { + struct virgl_cmd_buf base; + uint32_t buf[VIRGL_MAX_CMDBUF_DWORDS]; + unsigned nres; + unsigned cres; + struct virgl_winsys *ws; + struct virgl_hw_res **res_bo; + + char is_handle_added[512]; + unsigned reloc_indices_hashlist[512]; +}; + +static inline struct virgl_vtest_winsys * +virgl_vtest_winsys(struct virgl_winsys *iws) +{ + return (struct virgl_vtest_winsys *)iws; +} + +int virgl_vtest_connect(struct virgl_vtest_winsys *vws); +int virgl_vtest_send_get_caps(struct virgl_vtest_winsys *vws, + struct virgl_drm_caps *caps); + +int 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); + +int virgl_vtest_send_resource_unref(struct virgl_vtest_winsys *vws, + uint32_t handle); +int virgl_vtest_submit_cmd(struct virgl_vtest_winsys *vtws, + struct virgl_vtest_cmd_buf *cbuf); + +int 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); + +int virgl_vtest_send_transfer_put_data(struct virgl_vtest_winsys *vws, + void *data, + uint32_t data_size); +int 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); + +int virgl_vtest_busy_wait(struct virgl_vtest_winsys *vws, int handle, + int flags); +#endif diff --git a/src/gallium/winsys/virgl/vtest/vtest_protocol.h b/src/gallium/winsys/virgl/vtest/vtest_protocol.h new file mode 100644 index 00000000000..86d197f006c --- /dev/null +++ b/src/gallium/winsys/virgl/vtest/vtest_protocol.h @@ -0,0 +1,88 @@ +/* + * Copyright 2014, 2015 Red Hat. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef VTEST_PROTOCOL +#define VTEST_PROTOCOL + +#define VTEST_DEFAULT_SOCKET_NAME "/tmp/.virgl_test" + +/* 32-bit length field */ +/* 32-bit cmd field */ +#define VTEST_HDR_SIZE 2 +#define VTEST_CMD_LEN 0 /* length of data */ +#define VTEST_CMD_ID 1 +#define VTEST_CMD_DATA_START 2 + +/* vtest cmds */ +#define VCMD_GET_CAPS 1 + +#define VCMD_RESOURCE_CREATE 2 +#define VCMD_RESOURCE_UNREF 3 + +#define VCMD_TRANSFER_GET 4 +#define VCMD_TRANSFER_PUT 5 + +#define VCMD_SUBMIT_CMD 6 + +#define VCMD_RESOURCE_BUSY_WAIT 7 + +/* pass the process cmd line for debugging */ +#define VCMD_CREATE_RENDERER 8 +/* get caps */ +/* 0 length cmd */ +/* resp VCMD_GET_CAPS + caps */ + +#define VCMD_RES_CREATE_SIZE 10 +#define VCMD_RES_CREATE_RES_HANDLE 0 +#define VCMD_RES_CREATE_TARGET 1 +#define VCMD_RES_CREATE_FORMAT 2 +#define VCMD_RES_CREATE_BIND 3 +#define VCMD_RES_CREATE_WIDTH 4 +#define VCMD_RES_CREATE_HEIGHT 5 +#define VCMD_RES_CREATE_DEPTH 6 +#define VCMD_RES_CREATE_ARRAY_SIZE 7 +#define VCMD_RES_CREATE_LAST_LEVEL 8 +#define VCMD_RES_CREATE_NR_SAMPLES 9 + +#define VCMD_RES_UNREF_SIZE 1 +#define VCMD_RES_UNREF_RES_HANDLE 0 + +#define VCMD_TRANSFER_HDR_SIZE 11 +#define VCMD_TRANSFER_RES_HANDLE 0 +#define VCMD_TRANSFER_LEVEL 1 +#define VCMD_TRANSFER_STRIDE 2 +#define VCMD_TRANSFER_LAYER_STRIDE 3 +#define VCMD_TRANSFER_X 4 +#define VCMD_TRANSFER_Y 5 +#define VCMD_TRANSFER_Z 6 +#define VCMD_TRANSFER_WIDTH 7 +#define VCMD_TRANSFER_HEIGHT 8 +#define VCMD_TRANSFER_DEPTH 9 +#define VCMD_TRANSFER_DATA_SIZE 10 + +#define VCMD_BUSY_WAIT_FLAG_WAIT 1 + +#define VCMD_BUSY_WAIT_SIZE 2 +#define VCMD_BUSY_WAIT_HANDLE 0 +#define VCMD_BUSY_WAIT_FLAGS 1 + +#endif -- cgit v1.2.3