From: Thomas Hellstrom Date: Wed, 28 Sep 2011 07:13:50 +0000 (+0200) Subject: winsys/svga: Update to vmwgfx kernel module 2.1 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e7843273fae516fa9922f12053bb6c063b39921c;p=mesa.git 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 Reviewed-by: Jakob Bornecranz --- diff --git a/src/gallium/drivers/svga/svga_pipe_query.c b/src/gallium/drivers/svga/svga_pipe_query.c index 579f8034c7c..c44e0b8ec49 100644 --- a/src/gallium/drivers/svga/svga_pipe_query.c +++ b/src/gallium/drivers/svga/svga_pipe_query.c @@ -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; } diff --git a/src/gallium/drivers/svga/svga_winsys.h b/src/gallium/drivers/svga/svga_winsys.h index ae61cea083f..d9560efea33 100644 --- a/src/gallium/drivers/svga/svga_winsys.h +++ b/src/gallium/drivers/svga/svga_winsys.h @@ -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; 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; }; /*************************************************************************/ @@ -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 + * + */ + +/** + * 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