[Mesa-dev] [PATCH 4/4] virgl/vtest: add vtest driver

Dave Airlie airlied at gmail.com
Mon Oct 12 21:41:00 PDT 2015


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 <airlied at redhat.com>
---
 configure.ac                                       |   1 +
 src/gallium/Makefile.am                            |   2 +-
 .../auxiliary/target-helpers/inline_sw_helper.h    |  12 +
 src/gallium/drivers/virgl/Automake.inc             |   3 +-
 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 +++
 11 files changed, 1243 insertions(+), 2 deletions(-)
 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

diff --git a/configure.ac b/configure.ac
index 37ccb3d..7bf8781 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2414,6 +2414,7 @@ AC_CONFIG_FILES([Makefile
 		src/gallium/winsys/sw/xlib/Makefile
 		src/gallium/winsys/vc4/drm/Makefile
 		src/gallium/winsys/virgl/drm/Makefile
+		src/gallium/winsys/virgl/vtest/Makefile
 		src/gbm/Makefile
 		src/gbm/main/gbm.pc
 		src/glsl/Makefile
diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am
index 2fa93dd..611d55f 100644
--- a/src/gallium/Makefile.am
+++ b/src/gallium/Makefile.am
@@ -84,7 +84,7 @@ endif
 
 ## virgl
 if HAVE_GALLIUM_VIRGL
-SUBDIRS += drivers/virgl winsys/virgl/drm
+SUBDIRS += drivers/virgl winsys/virgl/drm winsys/virgl/vtest
 endif
 
 ## the sw winsys'
diff --git a/src/gallium/auxiliary/target-helpers/inline_sw_helper.h b/src/gallium/auxiliary/target-helpers/inline_sw_helper.h
index 5f46552..f3693fb 100644
--- a/src/gallium/auxiliary/target-helpers/inline_sw_helper.h
+++ b/src/gallium/auxiliary/target-helpers/inline_sw_helper.h
@@ -19,6 +19,10 @@
 #include "llvmpipe/lp_public.h"
 #endif
 
+#ifdef GALLIUM_VIRGL
+#include "virgl/virgl_public.h"
+#include "virgl/vtest/virgl_vtest_public.h"
+#endif
 
 static inline struct pipe_screen *
 sw_screen_create_named(struct sw_winsys *winsys, const char *driver)
@@ -30,6 +34,14 @@ sw_screen_create_named(struct sw_winsys *winsys, const char *driver)
       screen = llvmpipe_create_screen(winsys);
 #endif
 
+#if defined(GALLIUM_VIRGL)
+   if (screen == NULL && strcmp(driver, "virpipe") == 0) {
+      struct virgl_winsys *vws;
+      vws = virgl_vtest_winsys_wrap(winsys);
+      screen = virgl_create_screen(vws);
+   }
+#endif
+
 #if defined(GALLIUM_SOFTPIPE)
    if (screen == NULL)
       screen = softpipe_create_screen(winsys);
diff --git a/src/gallium/drivers/virgl/Automake.inc b/src/gallium/drivers/virgl/Automake.inc
index 457ca77..b05d3e3 100644
--- a/src/gallium/drivers/virgl/Automake.inc
+++ b/src/gallium/drivers/virgl/Automake.inc
@@ -4,7 +4,8 @@ TARGET_DRIVERS += virtio_gpu
 TARGET_CPPFLAGS += -DGALLIUM_VIRGL
 TARGET_LIB_DEPS += \
 	$(top_builddir)/src/gallium/drivers/virgl/libvirgl.la \
-	$(top_builddir)/src/gallium/winsys/virgl/drm/libvirgldrm.la
+	$(top_builddir)/src/gallium/winsys/virgl/drm/libvirgldrm.la \
+	$(top_builddir)/src/gallium/winsys/virgl/vtest/libvirglvtest.la \
 	$(LIBDRM_LIBS)
 
 endif
diff --git a/src/gallium/winsys/virgl/vtest/Makefile.am b/src/gallium/winsys/virgl/vtest/Makefile.am
new file mode 100644
index 0000000..81270d7
--- /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 0000000..ab72560
--- /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 0000000..7233649
--- /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 0000000..48dff8d
--- /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 <sys/socket.h>
+#include <errno.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <os/os_process.h>
+#include <util/u_format.h>
+/* 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 0000000..f69d200
--- /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 <stdio.h>
+#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 & (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT)) {
+      res->dt = vtws->sws->displaytarget_create(vtws->sws,
+                                                bind,
+                                                format,
+                                                width,
+                                                height,
+                                                64,
+                                                &res->stride);
+
+   } else {
+      res->ptr = malloc(size);
+      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 != PIPE_BIND_CONSTANT_BUFFER && bind != PIPE_BIND_INDEX_BUFFER &&
+       bind != PIPE_BIND_VERTEX_BUFFER && bind != PIPE_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 == PIPE_BIND_CONSTANT_BUFFER || bind == PIPE_BIND_INDEX_BUFFER ||
+       bind == PIPE_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 0000000..3967bef
--- /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 <stdint.h>
+#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 0000000..86d197f
--- /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
-- 
2.4.3



More information about the mesa-dev mailing list