winsys/svga: Update to vmwgfx kernel module 2.1

Introduces fence objecs and a size limit on query buffers.
The possibility to map the fifo from user-space is gone, and
replaced by an ioctl that reads the 3D capabilities.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Jakob Bornecranz <jakob@vmware.com>
This commit is contained in:
Thomas Hellstrom 2011-09-28 09:13:50 +02:00
parent e63f2787b6
commit e7843273fa
11 changed files with 669 additions and 264 deletions

View File

@ -241,7 +241,7 @@ static boolean svga_get_query_result(struct pipe_context *pipe,
if(!wait)
return FALSE;
sws->fence_finish(sws, sq->fence, 0);
sws->fence_finish(sws, sq->fence, SVGA_FENCE_FLAG_QUERY);
state = sq->queryResult->state;
}

View File

@ -61,7 +61,8 @@ struct winsys_handle;
#define SVGA_RELOC_WRITE 0x1
#define SVGA_RELOC_READ 0x2
#define SVGA_FENCE_FLAG_EXEC (1 << 0)
#define SVGA_FENCE_FLAG_QUERY (1 << 1)
/** Opaque surface handle */
struct svga_winsys_surface;

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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_ */

View File

@ -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);

View File

@ -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;

View File

@ -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 (pfence)
*pfence = NULL;
} else {
if (pfence) {
*pfence = vmw_fence_create(rep.handle, rep.mask);
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 == 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;
}
void
vmw_ioctl_fence_unref(struct vmw_winsys_screen *vws,
uint32_t handle)
{
struct drm_vmw_fence_arg arg;
int ret;
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 INLINE uint32_t
vmw_drm_fence_flags(uint32_t flags)
{
uint32_t dflags = 0;
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;
}
int
vmw_ioctl_fence_signalled(struct vmw_winsys_screen *vws,
uint32_t fence)
uint32_t handle,
uint32_t flags)
{
uint32_t expected;
uint32_t current;
assert(fence);
if(!fence)
return 0;
expected = fence;
current = vws->ioctl.fifo_map[SVGA_FIFO_FENCE];
if ((int32)(current - expected) >= 0)
return 0; /* fence passed */
else
return -1;
}
static void
vmw_ioctl_sync(struct vmw_winsys_screen *vws,
uint32_t fence)
{
uint32_t cur_fence;
struct drm_vmw_fence_wait_arg arg;
struct drm_vmw_fence_signaled_arg arg;
uint32_t vflags = vmw_drm_fence_flags(flags);
int ret;
vmw_printf("%s: fence = %lu\n", __FUNCTION__,
(unsigned long)fence);
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;
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);
}

View File

@ -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:

View File

@ -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);

View File

@ -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;
};
/*************************************************************************/
@ -390,39 +404,6 @@ struct drm_vmw_unref_dmabuf_arg {
uint32_t pad64;
};
/*************************************************************************/
/**
* 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.
@ -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
*
* 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.
*/
/**
* struct drm_vmw_update_layout_arg
* struct drm_vmw_get_3d_cap_arg
*
* @num_outputs: number of active
* @rects: pointer to array of drm_vmw_rect
* @buffer: Pointer to a buffer for capability data, cast to an uint64_t
* @size: Max size to copy
*
* Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl.
* Input argument to the DRM_VMW_GET_3D_CAP_IOCTL
* ioctls.
*/
struct drm_vmw_update_layout_arg {
uint32_t num_outputs;
struct drm_vmw_get_3d_cap_arg {
uint64_t buffer;
uint32_t max_size;
uint32_t pad64;
uint64_t rects;
};
/*************************************************************************/
/**
* 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
*
* Checks if a fence object is signaled..
*/
/**
* struct drm_vmw_fence_signaled_arg
*
* @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/Output argument to the DRM_VMW_FENCE_SIGNALED and DRM_VMW_FENCE_UNREF
* ioctls.
*/
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;
};
/*************************************************************************/
/**
* 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