summaryrefslogtreecommitdiffstats
path: root/src/gallium/winsys/svga
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/winsys/svga')
-rw-r--r--src/gallium/winsys/svga/drm/vmw_context.c10
-rw-r--r--src/gallium/winsys/svga/drm/vmw_fence.c235
-rw-r--r--src/gallium/winsys/svga/drm/vmw_fence.h31
-rw-r--r--src/gallium/winsys/svga/drm/vmw_screen.h20
-rw-r--r--src/gallium/winsys/svga/drm/vmw_screen_dri.c13
-rw-r--r--src/gallium/winsys/svga/drm/vmw_screen_ioctl.c248
-rw-r--r--src/gallium/winsys/svga/drm/vmw_screen_pools.c66
-rw-r--r--src/gallium/winsys/svga/drm/vmw_screen_svga.c33
-rw-r--r--src/gallium/winsys/svga/drm/vmwgfx_drm.h270
9 files changed, 665 insertions, 261 deletions
diff --git a/src/gallium/winsys/svga/drm/vmw_context.c b/src/gallium/winsys/svga/drm/vmw_context.c
index 633ef385a69..666e198954b 100644
--- a/src/gallium/winsys/svga/drm/vmw_context.c
+++ b/src/gallium/winsys/svga/drm/vmw_context.c
@@ -89,8 +89,6 @@ struct vmw_svga_winsys_context
struct pb_validate *validate;
- uint32_t last_fence;
-
/**
* The amount of GMR that is referred by the commands currently batched
* in the context.
@@ -166,9 +164,7 @@ vmw_swc_flush(struct svga_winsys_context *swc,
throttle_us,
vswc->command.buffer,
vswc->command.used,
- &vswc->last_fence);
-
- fence = vmw_pipe_fence(vswc->last_fence);
+ &fence);
pb_validate_fence(vswc->validate, fence);
}
@@ -200,7 +196,9 @@ vmw_swc_flush(struct svga_winsys_context *swc,
vswc->seen_regions = 0;
if(pfence)
- *pfence = fence;
+ vmw_fence_reference(vswc->vws, pfence, fence);
+
+ vmw_fence_reference(vswc->vws, &fence, NULL);
return ret;
}
diff --git a/src/gallium/winsys/svga/drm/vmw_fence.c b/src/gallium/winsys/svga/drm/vmw_fence.c
index 873dd51166c..754f8a666df 100644
--- a/src/gallium/winsys/svga/drm/vmw_fence.c
+++ b/src/gallium/winsys/svga/drm/vmw_fence.c
@@ -1,5 +1,5 @@
/**********************************************************
- * Copyright 2009 VMware, Inc. All rights reserved.
+ * Copyright 2009-2011 VMware, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -22,16 +22,26 @@
* SOFTWARE.
*
**********************************************************/
-
+/*
+ * TODO:
+ *
+ * Fencing is currently a bit inefficient, since we need to call the
+ * kernel do determine a fence object signaled status if the fence is not
+ * signaled. This can be greatly improved upon by using the fact that the
+ * execbuf ioctl returns the last signaled fence seqno, as does the
+ * fence signaled ioctl. We should set up a ring of fence objects and
+ * walk through them checking for signaled status each time we receive a
+ * new passed fence seqno.
+ */
#include "util/u_memory.h"
+#include "util/u_atomic.h"
+
#include "pipebuffer/pb_buffer_fenced.h"
#include "vmw_screen.h"
#include "vmw_fence.h"
-
-
struct vmw_fence_ops
{
struct pb_fence_ops base;
@@ -39,7 +49,57 @@ struct vmw_fence_ops
struct vmw_winsys_screen *vws;
};
+struct vmw_fence
+{
+ int32_t refcount;
+ uint32_t handle;
+ uint32_t mask;
+ int32_t signalled;
+};
+/**
+ * vmw_fence - return the vmw_fence object identified by a
+ * struct pipe_fence_handle *
+ *
+ * @fence: The opaque pipe fence handle.
+ */
+static INLINE struct vmw_fence *
+vmw_fence(struct pipe_fence_handle *fence)
+{
+ return (struct vmw_fence *) fence;
+}
+
+/**
+ * vmw_fence_create - Create a user-space fence object.
+ *
+ * @handle: Handle identifying the kernel fence object.
+ * @mask: Mask of flags that this fence object may signal.
+ *
+ * Returns NULL on failure.
+ */
+struct pipe_fence_handle *
+vmw_fence_create(uint32_t handle, uint32_t mask)
+{
+ struct vmw_fence *fence = CALLOC_STRUCT(vmw_fence);
+
+ if (!fence)
+ return NULL;
+
+ p_atomic_set(&fence->refcount, 1);
+ fence->handle = handle;
+ fence->mask = mask;
+ p_atomic_set(&fence->signalled, 0);
+
+ return (struct pipe_fence_handle *) fence;
+}
+
+/**
+ * vmw_fence_ops - Return the vmw_fence_ops structure backing a
+ * struct pb_fence_ops pointer.
+ *
+ * @ops: Pointer to a struct pb_fence_ops.
+ *
+ */
static INLINE struct vmw_fence_ops *
vmw_fence_ops(struct pb_fence_ops *ops)
{
@@ -48,37 +108,182 @@ vmw_fence_ops(struct pb_fence_ops *ops)
}
+
+/**
+ * vmw_fence_reference - Reference / unreference a vmw fence object.
+ *
+ * @vws: Pointer to the winsys screen.
+ * @ptr: Pointer to reference transfer destination.
+ * @fence: Pointer to object to reference. May be NULL.
+ */
+void
+vmw_fence_reference(struct vmw_winsys_screen *vws,
+ struct pipe_fence_handle **ptr,
+ struct pipe_fence_handle *fence)
+{
+ if (*ptr) {
+ struct vmw_fence *vfence = vmw_fence(*ptr);
+
+ if (p_atomic_dec_zero(&vfence->refcount)) {
+ vmw_ioctl_fence_unref(vws, vfence->handle);
+ FREE(vfence);
+ }
+ }
+
+ if (fence) {
+ struct vmw_fence *vfence = vmw_fence(fence);
+
+ p_atomic_inc(&vfence->refcount);
+ }
+
+ *ptr = fence;
+}
+
+
+/**
+ * vmw_fence_signalled - Check whether a fence object is signalled.
+ *
+ * @vws: Pointer to the winsys screen.
+ * @fence: Handle to the fence object.
+ * @flag: Fence flags to check. If the fence object can't signal
+ * a flag, it is assumed to be already signaled.
+ *
+ * Returns 0 if the fence object was signaled, nonzero otherwise.
+ */
+int
+vmw_fence_signalled(struct vmw_winsys_screen *vws,
+ struct pipe_fence_handle *fence,
+ unsigned flag)
+{
+ struct vmw_fence *vfence;
+ int32_t vflags = SVGA_FENCE_FLAG_EXEC;
+ int ret;
+ uint32_t old;
+
+ if (!fence)
+ return 0;
+
+ vfence = vmw_fence(fence);
+ old = p_atomic_read(&vfence->signalled);
+
+ vflags &= ~vfence->mask;
+
+ if ((old & vflags) == vflags)
+ return 0;
+
+ ret = vmw_ioctl_fence_signalled(vws, vfence->handle, vflags);
+
+ if (ret == 0) {
+ int32_t prev = old;
+
+ do {
+ old = prev;
+ prev = p_atomic_cmpxchg(&vfence->signalled, old, old | vflags);
+ } while (prev != old);
+ }
+
+ return ret;
+}
+
+/**
+ * vmw_fence_finish - Wait for a fence object to signal.
+ *
+ * @vws: Pointer to the winsys screen.
+ * @fence: Handle to the fence object.
+ * @flag: Fence flags to wait for. If the fence object can't signal
+ * a flag, it is assumed to be already signaled.
+ *
+ * Returns 0 if the wait succeeded. Nonzero otherwise.
+ */
+int
+vmw_fence_finish(struct vmw_winsys_screen *vws,
+ struct pipe_fence_handle *fence,
+ unsigned flag)
+{
+ struct vmw_fence *vfence;
+ int32_t vflags = SVGA_FENCE_FLAG_EXEC;
+ int ret;
+ uint32_t old;
+
+ if (!fence)
+ return 0;
+
+ vfence = vmw_fence(fence);
+ old = p_atomic_read(&vfence->signalled);
+ vflags &= ~vfence->mask;
+
+ if ((old & vflags) == vflags)
+ return 0;
+
+ ret = vmw_ioctl_fence_finish(vws, vfence->handle, vflags);
+
+ if (ret == 0) {
+ int32_t prev = old;
+
+ do {
+ old = prev;
+ prev = p_atomic_cmpxchg(&vfence->signalled, old, old | vflags);
+ } while (prev != old);
+ }
+
+ return ret;
+}
+
+
+/**
+ * vmw_fence_ops_fence_reference - wrapper for the pb_fence_ops api.
+ *
+ * wrapper around vmw_fence_reference.
+ */
static void
vmw_fence_ops_fence_reference(struct pb_fence_ops *ops,
struct pipe_fence_handle **ptr,
struct pipe_fence_handle *fence)
{
- *ptr = fence;
-}
+ struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws;
+ vmw_fence_reference(vws, ptr, fence);
+}
+/**
+ * vmw_fence_ops_fence_signalled - wrapper for the pb_fence_ops api.
+ *
+ * wrapper around vmw_fence_signalled.
+ */
static int
vmw_fence_ops_fence_signalled(struct pb_fence_ops *ops,
struct pipe_fence_handle *fence,
unsigned flag)
{
struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws;
- (void)flag;
- return vmw_ioctl_fence_signalled(vws, vmw_fence(fence));
+
+ return vmw_fence_signalled(vws, fence, flag);
}
+/**
+ * vmw_fence_ops_fence_finish - wrapper for the pb_fence_ops api.
+ *
+ * wrapper around vmw_fence_finish.
+ */
static int
vmw_fence_ops_fence_finish(struct pb_fence_ops *ops,
struct pipe_fence_handle *fence,
unsigned flag)
{
struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws;
- (void)flag;
- return vmw_ioctl_fence_finish(vws, vmw_fence(fence));
+
+ return vmw_fence_finish(vws, fence, flag);
}
+/**
+ * vmw_fence_ops_destroy - Destroy a pb_fence_ops function table.
+ *
+ * @ops: The function table to destroy.
+ *
+ * Part of the pb_fence_ops api.
+ */
static void
vmw_fence_ops_destroy(struct pb_fence_ops *ops)
{
@@ -86,6 +291,16 @@ vmw_fence_ops_destroy(struct pb_fence_ops *ops)
}
+/**
+ * vmw_fence_ops_create - Create a pb_fence_ops function table.
+ *
+ * @vws: Pointer to a struct vmw_winsys_screen.
+ *
+ * Returns a pointer to a pb_fence_ops function table to interface
+ * with pipe_buffer. This function is typically called on driver setup.
+ *
+ * Returns NULL on failure.
+ */
struct pb_fence_ops *
vmw_fence_ops_create(struct vmw_winsys_screen *vws)
{
diff --git a/src/gallium/winsys/svga/drm/vmw_fence.h b/src/gallium/winsys/svga/drm/vmw_fence.h
index 5357b4f61de..403ae266d5e 100644
--- a/src/gallium/winsys/svga/drm/vmw_fence.h
+++ b/src/gallium/winsys/svga/drm/vmw_fence.h
@@ -36,24 +36,25 @@ struct pb_fence_ops;
struct vmw_winsys_screen;
-/** Cast from a pipe_fence_handle pointer into a SVGA fence */
-static INLINE uint32_t
-vmw_fence( struct pipe_fence_handle *fence )
-{
- return (uint32_t)(uintptr_t)fence;
-}
-
-
-/** Cast from a SVGA fence number to pipe_fence_handle pointer */
-static INLINE struct pipe_fence_handle *
-vmw_pipe_fence( uint32_t fence )
-{
- return (struct pipe_fence_handle *)(uintptr_t)fence;
-}
-
+struct pipe_fence_handle *
+vmw_fence_create(uint32_t handle, uint32_t mask);
+
+int
+vmw_fence_finish(struct vmw_winsys_screen *vws,
+ struct pipe_fence_handle *fence,
+ unsigned flag);
+int
+vmw_fence_signalled(struct vmw_winsys_screen *vws,
+ struct pipe_fence_handle *fence,
+ unsigned flag);
+void
+vmw_fence_reference(struct vmw_winsys_screen *vws,
+ struct pipe_fence_handle **ptr,
+ struct pipe_fence_handle *fence);
struct pb_fence_ops *
vmw_fence_ops_create(struct vmw_winsys_screen *vws);
+
#endif /* VMW_FENCE_H_ */
diff --git a/src/gallium/winsys/svga/drm/vmw_screen.h b/src/gallium/winsys/svga/drm/vmw_screen.h
index b3de72df881..37ccc91dc0e 100644
--- a/src/gallium/winsys/svga/drm/vmw_screen.h
+++ b/src/gallium/winsys/svga/drm/vmw_screen.h
@@ -42,7 +42,7 @@
#define VMW_GMR_POOL_SIZE (16*1024*1024)
-
+#define VMW_QUERY_POOL_SIZE (8192)
struct pb_manager;
struct vmw_region;
@@ -56,15 +56,18 @@ struct vmw_winsys_screen
uint32_t default_throttle_us;
struct {
- volatile uint32_t *fifo_map;
- uint64_t last_fence;
int drm_fd;
+ uint32_t hwversion;
+ uint32_t *buffer;
} ioctl;
struct {
struct pb_manager *gmr;
struct pb_manager *gmr_mm;
struct pb_manager *gmr_fenced;
+ struct pb_manager *query;
+ struct pb_manager *query_mm;
+ struct pb_manager *query_fenced;
} pools;
};
@@ -101,7 +104,7 @@ vmw_ioctl_command(struct vmw_winsys_screen *vws,
uint32_t throttle_us,
void *commands,
uint32_t size,
- uint32_t *fence);
+ struct pipe_fence_handle **fence);
struct vmw_region *
vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size);
@@ -120,17 +123,22 @@ vmw_ioctl_region_unmap(struct vmw_region *region);
int
vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws,
- uint32_t fence);
+ uint32_t handle, uint32_t flags);
int
vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
- uint32_t fence);
+ uint32_t handle, uint32_t flags);
+
+void
+vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws,
+ uint32_t handle);
/* Initialize parts of vmw_winsys_screen at startup:
*/
boolean vmw_ioctl_init(struct vmw_winsys_screen *vws);
boolean vmw_pools_init(struct vmw_winsys_screen *vws);
+boolean vmw_query_pools_init(struct vmw_winsys_screen *vws);
boolean vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws);
void vmw_ioctl_cleanup(struct vmw_winsys_screen *vws);
diff --git a/src/gallium/winsys/svga/drm/vmw_screen_dri.c b/src/gallium/winsys/svga/drm/vmw_screen_dri.c
index 258084a1f10..3c92bb9b87e 100644
--- a/src/gallium/winsys/svga/drm/vmw_screen_dri.c
+++ b/src/gallium/winsys/svga/drm/vmw_screen_dri.c
@@ -56,9 +56,8 @@ vmw_drm_surface_get_handle(struct svga_winsys_screen *sws,
unsigned stride,
struct winsys_handle *whandle);
-static struct dri1_api_version drm_required = { 1, 0, 0 };
-static struct dri1_api_version drm_compat = { 1, 0, 0 };
-static struct dri1_api_version drm_scanout = { 0, 9, 0 };
+static struct dri1_api_version drm_required = { 2, 1, 0 };
+static struct dri1_api_version drm_compat = { 2, 0, 0 };
static boolean
vmw_dri1_check_version(const struct dri1_api_version *cur,
@@ -88,8 +87,6 @@ struct svga_winsys_screen *
svga_drm_winsys_screen_create(int fd)
{
struct vmw_winsys_screen *vws;
- boolean use_old_scanout_flag = FALSE;
-
struct dri1_api_version drm_ver;
drmVersionPtr ver;
@@ -106,11 +103,7 @@ svga_drm_winsys_screen_create(int fd)
&drm_compat, "vmwgfx drm driver"))
return NULL;
- if (!vmw_dri1_check_version(&drm_ver, &drm_scanout,
- &drm_compat, "use old scanout field (not a error)"))
- use_old_scanout_flag = TRUE;
-
- vws = vmw_winsys_create( fd, use_old_scanout_flag );
+ vws = vmw_winsys_create( fd, FALSE );
if (!vws)
goto out_no_vws;
diff --git a/src/gallium/winsys/svga/drm/vmw_screen_ioctl.c b/src/gallium/winsys/svga/drm/vmw_screen_ioctl.c
index afdbd44458d..e3b183a2ac1 100644
--- a/src/gallium/winsys/svga/drm/vmw_screen_ioctl.c
+++ b/src/gallium/winsys/svga/drm/vmw_screen_ioctl.c
@@ -39,8 +39,10 @@
#include "svgadump/svga_dump.h"
#include "vmw_screen.h"
#include "vmw_context.h"
+#include "vmw_fence.h"
#include "xf86drm.h"
#include "vmwgfx_drm.h"
+#include "svga3d_caps.h"
#include "os/os_mman.h"
@@ -64,62 +66,6 @@ struct vmw_region
*/
#define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9)
-static void
-vmw_check_last_cmd(struct vmw_winsys_screen *vws)
-{
- static uint32_t buffer[16384];
- struct drm_vmw_fifo_debug_arg arg;
- int ret;
-
- return;
- memset(&arg, 0, sizeof(arg));
- arg.debug_buffer = (unsigned long)buffer;
- arg.debug_buffer_size = 65536;
-
- ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FIFO_DEBUG,
- &arg, sizeof(arg));
-
- if (ret) {
- debug_printf("%s Ioctl error: \"%s\".\n", __FUNCTION__, strerror(-ret));
- return;
- }
-
- if (arg.did_not_fit) {
- debug_printf("%s Command did not fit completely.\n", __FUNCTION__);
- }
-
- svga_dump_commands(buffer, arg.used_size);
-}
-
-static void
-vmw_ioctl_fifo_unmap(struct vmw_winsys_screen *vws, void *mapping)
-{
- VMW_FUNC;
- (void)os_munmap(mapping, getpagesize());
-}
-
-
-static void *
-vmw_ioctl_fifo_map(struct vmw_winsys_screen *vws,
- uint32_t fifo_offset )
-{
- void *map;
-
- VMW_FUNC;
-
- map = os_mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED,
- vws->ioctl.drm_fd, fifo_offset);
-
- if (map == MAP_FAILED) {
- debug_printf("Map failed %s\n", strerror(errno));
- return NULL;
- }
-
- vmw_printf("Fifo (min) is 0x%08x\n", ((uint32_t *) map)[SVGA_FIFO_MIN]);
-
- return map;
-}
-
uint32
vmw_ioctl_context_create(struct vmw_winsys_screen *vws)
{
@@ -134,7 +80,6 @@ vmw_ioctl_context_create(struct vmw_winsys_screen *vws)
if (ret)
return -1;
- vmw_check_last_cmd(vws);
vmw_printf("Context id is %d\n", c_arg.cid);
return c_arg.cid;
@@ -153,7 +98,6 @@ vmw_ioctl_context_destroy(struct vmw_winsys_screen *vws, uint32 cid)
(void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_CONTEXT,
&c_arg, sizeof(c_arg));
- vmw_check_last_cmd(vws);
}
uint32
@@ -220,7 +164,6 @@ vmw_ioctl_surface_create(struct vmw_winsys_screen *vws,
return -1;
vmw_printf("Surface id is %d\n", rep->sid);
- vmw_check_last_cmd(vws);
return rep->sid;
}
@@ -237,14 +180,12 @@ vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid)
(void)drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_UNREF_SURFACE,
&s_arg, sizeof(s_arg));
- vmw_check_last_cmd(vws);
-
}
void
vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,
uint32_t throttle_us, void *commands, uint32_t size,
- uint32_t *pfence)
+ struct pipe_fence_handle **pfence)
{
struct drm_vmw_execbuf_arg arg;
struct drm_vmw_fence_rep rep;
@@ -274,10 +215,12 @@ vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,
memset(&rep, 0, sizeof(rep));
rep.error = -EFAULT;
- arg.fence_rep = (unsigned long)&rep;
+ if (pfence)
+ arg.fence_rep = (unsigned long)&rep;
arg.commands = (unsigned long)commands;
arg.command_size = size;
arg.throttle_us = throttle_us;
+ arg.version = DRM_VMW_EXECBUF_VERSION;
do {
ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));
@@ -285,26 +228,27 @@ vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,
if (ret) {
debug_printf("%s error %s.\n", __FUNCTION__, strerror(-ret));
}
+
if (rep.error) {
/*
- * Kernel has synced and put the last fence sequence in the FIFO
- * register.
+ * Kernel has already synced, or caller requested no fence.
*/
-
- if (rep.error == -EFAULT)
- rep.fence_seq = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
-
- debug_printf("%s Fence error %s.\n", __FUNCTION__,
- strerror(-rep.error));
+ if (pfence)
+ *pfence = NULL;
+ } else {
+ if (pfence) {
+ *pfence = vmw_fence_create(rep.handle, rep.mask);
+
+ if (*pfence == NULL) {
+ /*
+ * Fence creation failed. Need to sync.
+ */
+ (void) vmw_ioctl_fence_finish(vws, rep.handle, rep.mask);
+ vmw_ioctl_fence_unref(vws, rep.handle);
+ }
+ }
}
-
- vws->ioctl.last_fence = rep.fence_seq;
-
- if (pfence)
- *pfence = rep.fence_seq;
- vmw_check_last_cmd(vws);
-
}
@@ -412,67 +356,81 @@ vmw_ioctl_region_unmap(struct vmw_region *region)
--region->map_count;
}
-
-int
-vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
- uint32_t fence)
+void
+vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws,
+ uint32_t handle)
{
- uint32_t expected;
- uint32_t current;
-
- assert(fence);
- if(!fence)
- return 0;
-
- expected = fence;
- current = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
+ struct drm_vmw_fence_arg arg;
+ int ret;
- if ((int32)(current - expected) >= 0)
- return 0; /* fence passed */
- else
- return -1;
-}
+ memset(&arg, 0, sizeof(arg));
+ arg.handle = handle;
+ ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_FENCE_UNREF,
+ &arg, sizeof(arg));
+ if (ret != 0)
+ debug_printf("%s Failed\n", __FUNCTION__);
+}
-static void
-vmw_ioctl_sync(struct vmw_winsys_screen *vws,
- uint32_t fence)
+static INLINE uint32_t
+vmw_drm_fence_flags(uint32_t flags)
{
- uint32_t cur_fence;
- struct drm_vmw_fence_wait_arg arg;
- int ret;
+ uint32_t dflags = 0;
- vmw_printf("%s: fence = %lu\n", __FUNCTION__,
- (unsigned long)fence);
+ if (flags & SVGA_FENCE_FLAG_EXEC)
+ dflags |= DRM_VMW_FENCE_FLAG_EXEC;
+ if (flags & SVGA_FENCE_FLAG_QUERY)
+ dflags |= DRM_VMW_FENCE_FLAG_QUERY;
+
+ return dflags;
+}
- cur_fence = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
- vmw_printf("%s: Fence id read is 0x%08x\n", __FUNCTION__,
- (unsigned int)cur_fence);
- if ((cur_fence - fence) < (1 << 24))
- return;
+int
+vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
+ uint32_t handle,
+ uint32_t flags)
+{
+ struct drm_vmw_fence_signaled_arg arg;
+ uint32_t vflags = vmw_drm_fence_flags(flags);
+ int ret;
memset(&arg, 0, sizeof(arg));
- arg.sequence = fence;
+ arg.handle = handle;
+ arg.flags = vflags;
- do {
- ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_WAIT, &arg,
- sizeof(arg));
- } while (ret == -ERESTART);
+ ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_SIGNALED,
+ &arg, sizeof(arg));
+
+ if (ret != 0)
+ return ret;
+
+ return (arg.signaled) ? 0 : -1;
}
+
int
vmw_ioctl_fence_finish(struct vmw_winsys_screen *vws,
- uint32_t fence)
+ uint32_t handle,
+ uint32_t flags)
{
- assert(fence);
-
- if(fence) {
- if(vmw_ioctl_fence_signalled(vws, fence) != 0) {
- vmw_ioctl_sync(vws, fence);
- }
- }
+ struct drm_vmw_fence_wait_arg arg;
+ uint32_t vflags = vmw_drm_fence_flags(flags);
+ int ret;
+
+ memset(&arg, 0, sizeof(arg));
+
+ arg.handle = handle;
+ arg.timeout_us = 10*1000000;
+ arg.lazy = 0;
+ arg.flags = vflags;
+
+ ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_FENCE_WAIT,
+ &arg, sizeof(arg));
+
+ if (ret != 0)
+ debug_printf("%s Failed\n", __FUNCTION__);
return 0;
}
@@ -482,6 +440,8 @@ boolean
vmw_ioctl_init(struct vmw_winsys_screen *vws)
{
struct drm_vmw_getparam_arg gp_arg;
+ struct drm_vmw_get_3d_cap_arg cap_arg;
+ unsigned int size;
int ret;
VMW_FUNC;
@@ -491,32 +451,46 @@ vmw_ioctl_init(struct vmw_winsys_screen *vws)
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
&gp_arg, sizeof(gp_arg));
if (ret || gp_arg.value == 0) {
- debug_printf("No 3D enabled (%i, %s)\n", ret, strerror(-ret));
- goto out_err1;
+ debug_printf("No 3D enabled (%i, %s).\n", ret, strerror(-ret));
+ goto out_no_3d;
}
memset(&gp_arg, 0, sizeof(gp_arg));
- gp_arg.param = DRM_VMW_PARAM_FIFO_OFFSET;
+ gp_arg.param = DRM_VMW_PARAM_FIFO_HW_VERSION;
ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_GET_PARAM,
&gp_arg, sizeof(gp_arg));
-
if (ret) {
- debug_printf("GET_PARAM on %d returned %d: %s\n",
- vws->ioctl.drm_fd, ret, strerror(-ret));
- goto out_err1;
+ debug_printf("Failed to get fifo hw version"
+ " (%i, %s).\n", ret, strerror(-ret));
+ goto out_no_3d;
+ }
+ vws->ioctl.hwversion = gp_arg.value;
+
+ size = SVGA_FIFO_3D_CAPS_SIZE * sizeof(uint32_t);
+ vws->ioctl.buffer = calloc(1, size);
+ if (!vws->ioctl.buffer) {
+ debug_printf("Failed alloc fifo 3D caps buffer.\n");
+ goto out_no_3d;
}
- vmw_printf("Offset to map is 0x%08llx\n",
- (unsigned long long)gp_arg.value);
+ memset(&cap_arg, 0, sizeof(cap_arg));
+ cap_arg.buffer = (uint64_t) (unsigned long) (vws->ioctl.buffer);
+ cap_arg.max_size = size;
- vws->ioctl.fifo_map = vmw_ioctl_fifo_map(vws, gp_arg.value);
- if (vws->ioctl.fifo_map == NULL)
- goto out_err1;
+ ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_GET_3D_CAP,
+ &cap_arg, sizeof(cap_arg));
+
+ if (ret) {
+ debug_printf("Failed to get 3D capabilities"
+ " (%i, %s).\n", ret, strerror(-ret));
+ goto out_no_caps;
+ }
vmw_printf("%s OK\n", __FUNCTION__);
return TRUE;
-
- out_err1:
+ out_no_caps:
+ free(vws->ioctl.buffer);
+ out_no_3d:
debug_printf("%s Failed\n", __FUNCTION__);
return FALSE;
}
@@ -527,6 +501,4 @@ void
vmw_ioctl_cleanup(struct vmw_winsys_screen *vws)
{
VMW_FUNC;
-
- vmw_ioctl_fifo_unmap(vws, (void *)vws->ioctl.fifo_map);
}
diff --git a/src/gallium/winsys/svga/drm/vmw_screen_pools.c b/src/gallium/winsys/svga/drm/vmw_screen_pools.c
index b9823d78575..6350ea3cd4f 100644
--- a/src/gallium/winsys/svga/drm/vmw_screen_pools.c
+++ b/src/gallium/winsys/svga/drm/vmw_screen_pools.c
@@ -32,19 +32,81 @@
#include "pipebuffer/pb_buffer.h"
#include "pipebuffer/pb_bufmgr.h"
+/*
+ * TODO: Have the query pool always ask the fence manager for
+ * SVGA_FENCE_FLAG_QUERY signaled. Unfortunately, pb_fenced doesn't
+ * support that currently, so we'd have to create a separate
+ * pb_fence_ops wrapper that does this implicitly.
+ */
+
+/**
+ * vmw_pools_cleanup - Destroy the buffer pools.
+ *
+ * @vws: pointer to a struct vmw_winsys_screen.
+ */
void
vmw_pools_cleanup(struct vmw_winsys_screen *vws)
{
if(vws->pools.gmr_fenced)
vws->pools.gmr_fenced->destroy(vws->pools.gmr_fenced);
+ if (vws->pools.query_fenced)
+ vws->pools.query_fenced->destroy(vws->pools.query_fenced);
/* gmr_mm pool is already destroyed above */
if(vws->pools.gmr)
vws->pools.gmr->destroy(vws->pools.gmr);
+ if(vws->pools.query)
+ vws->pools.query->destroy(vws->pools.query);
}
+/**
+ * vmw_query_pools_init - Create a pool of query buffers.
+ *
+ * @vws: Pointer to a struct vmw_winsys_screen.
+ *
+ * Typically this pool should be created on demand when we
+ * detect that the app will be using queries. There's nothing
+ * special with this pool other than the backing kernel buffer size,
+ * which is limited to 8192.
+ */
+boolean
+vmw_query_pools_init(struct vmw_winsys_screen *vws)
+{
+ vws->pools.query = vmw_gmr_bufmgr_create(vws);
+ if(!vws->pools.query)
+ return FALSE;
+
+ vws->pools.query_mm = mm_bufmgr_create(vws->pools.query,
+ VMW_QUERY_POOL_SIZE,
+ 3 /* 8 alignment */);
+ if(!vws->pools.query_mm)
+ goto out_no_query_mm;
+
+ vws->pools.query_fenced = fenced_bufmgr_create(
+ vws->pools.query_mm,
+ vmw_fence_ops_create(vws),
+ VMW_QUERY_POOL_SIZE,
+ ~0);
+
+ if(!vws->pools.query_fenced)
+ goto out_no_query_fenced;
+
+ return TRUE;
+
+ out_no_query_fenced:
+ vws->pools.query_mm->destroy(vws->pools.query_mm);
+ out_no_query_mm:
+ vws->pools.query->destroy(vws->pools.query);
+ return FALSE;
+}
+
+/**
+ * vmw_pools_init - Create a pool of GMR buffers.
+ *
+ * @vws: Pointer to a struct vmw_winsys_screen.
+ */
boolean
vmw_pools_init(struct vmw_winsys_screen *vws)
{
@@ -88,6 +150,10 @@ vmw_pools_init(struct vmw_winsys_screen *vws)
if(!vws->pools.gmr_fenced)
goto error;
+ vws->pools.query_fenced = NULL;
+ vws->pools.query_mm = NULL;
+ vws->pools.query = NULL;
+
return TRUE;
error:
diff --git a/src/gallium/winsys/svga/drm/vmw_screen_svga.c b/src/gallium/winsys/svga/drm/vmw_screen_svga.c
index c362aa39938..df4a384d3ee 100644
--- a/src/gallium/winsys/svga/drm/vmw_screen_svga.c
+++ b/src/gallium/winsys/svga/drm/vmw_screen_svga.c
@@ -64,7 +64,12 @@ vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
desc.alignment = alignment;
desc.usage = usage;
- provider = vws->pools.gmr_fenced;
+ if (usage == SVGA_BUFFER_USAGE_PINNED) {
+ if (vws->pools.query_fenced == NULL && !vmw_query_pools_init(vws))
+ return NULL;
+ provider = vws->pools.query_fenced;
+ } else
+ provider = vws->pools.gmr_fenced;
assert(provider);
buffer = provider->create_buffer(provider, size, &desc);
@@ -109,8 +114,9 @@ vmw_svga_winsys_fence_reference(struct svga_winsys_screen *sws,
struct pipe_fence_handle **pdst,
struct pipe_fence_handle *src)
{
- (void)sws;
- *pdst = src;
+ struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
+
+ vmw_fence_reference(vws, pdst, src);
}
@@ -120,8 +126,8 @@ vmw_svga_winsys_fence_signalled(struct svga_winsys_screen *sws,
unsigned flag)
{
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
- (void)flag;
- return vmw_ioctl_fence_signalled(vws, vmw_fence(fence));
+
+ return vmw_fence_signalled(vws, fence, flag);
}
@@ -131,8 +137,8 @@ vmw_svga_winsys_fence_finish(struct svga_winsys_screen *sws,
unsigned flag)
{
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
- (void)flag;
- return vmw_ioctl_fence_finish(vws, vmw_fence(fence));
+
+ return vmw_fence_finish(vws, fence, flag);
}
@@ -206,11 +212,7 @@ vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
{
struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
- if (!vws->ioctl.fifo_map) {
- return 0;
- }
-
- return vws->ioctl.fifo_map[SVGA_FIFO_3D_HWVERSION];
+ return (SVGA3dHardwareVersion) vws->ioctl.hwversion;
}
@@ -226,16 +228,13 @@ vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
const SVGA3dCapPair *capArray;
int numCaps, first, last;
- if(!vws->ioctl.fifo_map)
- return FALSE;
-
- if(vws->ioctl.fifo_map[SVGA_FIFO_3D_HWVERSION] < SVGA3D_HWVERSION_WS6_B1)
+ if(vws->ioctl.hwversion < SVGA3D_HWVERSION_WS6_B1)
return FALSE;
/*
* Search linearly through the caps block records for the specified type.
*/
- capsBlock = (const uint32 *)&vws->ioctl.fifo_map[SVGA_FIFO_3D_CAPS];
+ capsBlock = (const uint32 *)vws->ioctl.buffer;
for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {
const SVGA3dCapsRecord *record;
assert(offset < SVGA_FIFO_3D_CAPS_SIZE);
diff --git a/src/gallium/winsys/svga/drm/vmwgfx_drm.h b/src/gallium/winsys/svga/drm/vmwgfx_drm.h
index 2f2807df0b2..bad47a702f2 100644
--- a/src/gallium/winsys/svga/drm/vmwgfx_drm.h
+++ b/src/gallium/winsys/svga/drm/vmwgfx_drm.h
@@ -31,7 +31,6 @@
#define DRM_VMW_MAX_SURFACE_FACES 6
#define DRM_VMW_MAX_MIP_LEVELS 24
-#define DRM_VMW_EXT_NAME_LEN 128
#define DRM_VMW_GET_PARAM 0
#define DRM_VMW_ALLOC_DMABUF 1
@@ -48,10 +47,13 @@
#define DRM_VMW_UNREF_SURFACE 10
#define DRM_VMW_REF_SURFACE 11
#define DRM_VMW_EXECBUF 12
-#define DRM_VMW_FIFO_DEBUG 13
+#define DRM_VMW_GET_3D_CAP 13
#define DRM_VMW_FENCE_WAIT 14
-/* guarded by minor version >= 2 */
-#define DRM_VMW_UPDATE_LAYOUT 15
+#define DRM_VMW_FENCE_SIGNALED 15
+#define DRM_VMW_FENCE_UNREF 16
+#define DRM_VMW_FENCE_EVENT 17
+#define DRM_VMW_PRESENT 18
+#define DRM_VMW_PRESENT_READBACK 19
/*************************************************************************/
@@ -69,10 +71,10 @@
#define DRM_VMW_PARAM_NUM_STREAMS 0
#define DRM_VMW_PARAM_NUM_FREE_STREAMS 1
#define DRM_VMW_PARAM_3D 2
-#define DRM_VMW_PARAM_FIFO_OFFSET 3
-#define DRM_VMW_PARAM_HW_CAPS 4
-#define DRM_VMW_PARAM_FIFO_CAPS 5
-#define DRM_VMW_PARAM_MAX_FB_SIZE 6
+#define DRM_VMW_PARAM_HW_CAPS 3
+#define DRM_VMW_PARAM_FIFO_CAPS 4
+#define DRM_VMW_PARAM_MAX_FB_SIZE 5
+#define DRM_VMW_PARAM_FIFO_HW_VERSION 6
/**
* struct drm_vmw_getparam_arg
@@ -249,7 +251,7 @@ union drm_vmw_surface_reference_arg {
* DRM_VMW_EXECBUF
*
* Submit a command buffer for execution on the host, and return a
- * fence sequence that when signaled, indicates that the command buffer has
+ * fence seqno that when signaled, indicates that the command buffer has
* executed.
*/
@@ -271,21 +273,30 @@ union drm_vmw_surface_reference_arg {
* Argument to the DRM_VMW_EXECBUF Ioctl.
*/
-#define DRM_VMW_EXECBUF_VERSION 0
+#define DRM_VMW_EXECBUF_VERSION 1
struct drm_vmw_execbuf_arg {
uint64_t commands;
uint32_t command_size;
uint32_t throttle_us;
uint64_t fence_rep;
- uint32_t version;
- uint32_t flags;
+ uint32_t version;
+ uint32_t flags;
};
/**
* struct drm_vmw_fence_rep
*
- * @fence_seq: Fence sequence associated with a command submission.
+ * @handle: Fence object handle for fence associated with a command submission.
+ * @mask: Fence flags relevant for this fence object.
+ * @seqno: Fence sequence number in fifo. A fence object with a lower
+ * seqno will signal the EXEC flag before a fence object with a higher
+ * seqno. This can be used by user-space to avoid kernel calls to determine
+ * whether a fence has signaled the EXEC flag. Note that @seqno will
+ * wrap at 32-bit.
+ * @passed_seqno: The highest seqno number processed by the hardware
+ * so far. This can be used to mark user-space fence objects as signaled, and
+ * to determine whether a fence seqno might be stale.
* @error: This member should've been set to -EFAULT on submission.
* The following actions should be take on completion:
* error == -EFAULT: Fence communication failed. The host is synchronized.
@@ -299,9 +310,12 @@ struct drm_vmw_execbuf_arg {
*/
struct drm_vmw_fence_rep {
- uint64_t fence_seq;
- int32_t error;
+ uint32_t handle;
+ uint32_t mask;
+ uint32_t seqno;
+ uint32_t passed_seqno;
uint32_t pad64;
+ int32_t error;
};
/*************************************************************************/
@@ -392,39 +406,6 @@ struct drm_vmw_unref_dmabuf_arg {
/*************************************************************************/
/**
- * DRM_VMW_FIFO_DEBUG - Get last FIFO submission.
- *
- * This IOCTL copies the last FIFO submission directly out of the FIFO buffer.
- */
-
-/**
- * struct drm_vmw_fifo_debug_arg
- *
- * @debug_buffer: User space address of a debug_buffer cast to an uint64_t //In
- * @debug_buffer_size: Size in bytes of debug buffer //In
- * @used_size: Number of bytes copied to the buffer // Out
- * @did_not_fit: Boolean indicating that the fifo contents did not fit. //Out
- *
- * Argument to the DRM_VMW_FIFO_DEBUG Ioctl.
- */
-
-struct drm_vmw_fifo_debug_arg {
- uint64_t debug_buffer;
- uint32_t debug_buffer_size;
- uint32_t used_size;
- int32_t did_not_fit;
- uint32_t pad64;
-};
-
-struct drm_vmw_fence_wait_arg {
- uint64_t sequence;
- uint64_t kernel_cookie;
- int32_t cookie_valid;
- int32_t pad64;
-};
-
-/*************************************************************************/
-/**
* DRM_VMW_CONTROL_STREAM - Control overlays, aka streams.
*
* This IOCTL controls the overlay units of the svga device.
@@ -547,26 +528,197 @@ struct drm_vmw_stream_arg {
/*************************************************************************/
/**
- * DRM_VMW_UPDATE_LAYOUT - Update layout
+ * DRM_VMW_GET_3D_CAP
+ *
+ * Read 3D capabilities from the FIFO
+ *
+ */
+
+/**
+ * struct drm_vmw_get_3d_cap_arg
+ *
+ * @buffer: Pointer to a buffer for capability data, cast to an uint64_t
+ * @size: Max size to copy
+ *
+ * Input argument to the DRM_VMW_GET_3D_CAP_IOCTL
+ * ioctls.
+ */
+
+struct drm_vmw_get_3d_cap_arg {
+ uint64_t buffer;
+ uint32_t max_size;
+ uint32_t pad64;
+};
+
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_WAIT
+ *
+ * Waits for a fence object to signal. The wait is interruptible, so that
+ * signals may be delivered during the interrupt. The wait may timeout,
+ * in which case the calls returns -EBUSY. If the wait is restarted,
+ * that is restarting without resetting @cookie_valid to zero,
+ * the timeout is computed from the first call.
+ *
+ * The flags argument to the DRM_VMW_FENCE_WAIT ioctl indicates what to wait
+ * on:
+ * DRM_VMW_FENCE_FLAG_EXEC: All commands ahead of the fence in the command
+ * stream
+ * have executed.
+ * DRM_VMW_FENCE_FLAG_QUERY: All query results resulting from query finish
+ * commands
+ * in the buffer given to the EXECBUF ioctl returning the fence object handle
+ * are available to user-space.
+ *
+ * DRM_VMW_WAIT_OPTION_UNREF: If this wait option is given, and the
+ * fenc wait ioctl returns 0, the fence object has been unreferenced after
+ * the wait.
+ */
+
+#define DRM_VMW_FENCE_FLAG_EXEC (1 << 0)
+#define DRM_VMW_FENCE_FLAG_QUERY (1 << 1)
+
+#define DRM_VMW_WAIT_OPTION_UNREF (1 << 0)
+
+/**
+ * struct drm_vmw_fence_wait_arg
+ *
+ * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl.
+ * @cookie_valid: Must be reset to 0 on first call. Left alone on restart.
+ * @kernel_cookie: Set to 0 on first call. Left alone on restart.
+ * @timeout_us: Wait timeout in microseconds. 0 for indefinite timeout.
+ * @lazy: Set to 1 if timing is not critical. Allow more than a kernel tick
+ * before returning.
+ * @flags: Fence flags to wait on.
+ * @wait_options: Options that control the behaviour of the wait ioctl.
+ *
+ * Input argument to the DRM_VMW_FENCE_WAIT ioctl.
+ */
+
+struct drm_vmw_fence_wait_arg {
+ uint32_t handle;
+ int32_t cookie_valid;
+ uint64_t kernel_cookie;
+ uint64_t timeout_us;
+ int32_t lazy;
+ int32_t flags;
+ int32_t wait_options;
+ int32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_SIGNALED
*
- * Updates the prefered modes and connection status for connectors. The
- * command conisits of one drm_vmw_update_layout_arg pointing out a array
- * of num_outputs drm_vmw_rect's.
+ * Checks if a fence object is signaled..
*/
/**
- * struct drm_vmw_update_layout_arg
+ * struct drm_vmw_fence_signaled_arg
*
- * @num_outputs: number of active
- * @rects: pointer to array of drm_vmw_rect
+ * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl.
+ * @flags: Fence object flags input to DRM_VMW_FENCE_SIGNALED ioctl
+ * @signaled: Out: Flags signaled.
+ * @sequence: Out: Highest sequence passed so far. Can be used to signal the
+ * EXEC flag of user-space fence objects.
*
- * Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl.
+ * Input/Output argument to the DRM_VMW_FENCE_SIGNALED and DRM_VMW_FENCE_UNREF
+ * ioctls.
*/
-struct drm_vmw_update_layout_arg {
- uint32_t num_outputs;
+struct drm_vmw_fence_signaled_arg {
+ uint32_t handle;
+ uint32_t flags;
+ int32_t signaled;
+ uint32_t passed_seqno;
+ uint32_t signaled_flags;
+ uint32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_UNREF
+ *
+ * Unreferences a fence object, and causes it to be destroyed if there are no
+ * other references to it.
+ *
+ */
+
+/**
+ * struct drm_vmw_fence_arg
+ *
+ * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl.
+ *
+ * Input/Output argument to the DRM_VMW_FENCE_UNREF ioctl..
+ */
+
+struct drm_vmw_fence_arg {
+ uint32_t handle;
+ uint32_t pad64;
+};
+
+
+/*************************************************************************/
+/**
+ * DRM_VMW_PRESENT
+ *
+ * Executes an SVGA present on a given fb for a given surface. The surface
+ * is placed on the framebuffer. Cliprects are given relative to the given
+ * point (the point disignated by dest_{x|y}).
+ *
+ */
+
+/**
+ * struct drm_vmw_present_arg
+ * @fb_id: framebuffer id to present / read back from.
+ * @sid: Surface id to present from.
+ * @dest_x: X placement coordinate for surface.
+ * @dest_y: Y placement coordinate for surface.
+ * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t.
+ * @num_clips: Number of cliprects given relative to the framebuffer origin,
+ * in the same coordinate space as the frame buffer.
+ * @pad64: Unused 64-bit padding.
+ *
+ * Input argument to the DRM_VMW_PRESENT ioctl.
+ */
+
+struct drm_vmw_present_arg {
+ uint32_t fb_id;
+ uint32_t sid;
+ int32_t dest_x;
+ int32_t dest_y;
+ uint64_t clips_ptr;
+ uint32_t num_clips;
uint32_t pad64;
- uint64_t rects;
};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_PRESENT_READBACK
+ *
+ * Executes an SVGA present readback from a given fb to the dma buffer
+ * currently bound as the fb. If there is no dma buffer bound to the fb,
+ * an error will be returned.
+ *
+ */
+
+/**
+ * struct drm_vmw_present_arg
+ * @fb_id: fb_id to present / read back from.
+ * @num_clips: Number of cliprects.
+ * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t.
+ * @fence_rep: Pointer to a struct drm_vmw_fence_rep, cast to an uint64_t.
+ * If this member is NULL, then the ioctl should not return a fence.
+ */
+
+struct drm_vmw_present_readback_arg {
+ uint32_t fb_id;
+ uint32_t num_clips;
+ uint64_t clips_ptr;
+ uint64_t fence_rep;
+};
+
+
#endif