Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /**********************************************************
  2.  * Copyright 2009-2011 VMware, Inc.  All rights reserved.
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person
  5.  * obtaining a copy of this software and associated documentation
  6.  * files (the "Software"), to deal in the Software without
  7.  * restriction, including without limitation the rights to use, copy,
  8.  * modify, merge, publish, distribute, sublicense, and/or sell copies
  9.  * of the Software, and to permit persons to whom the Software is
  10.  * furnished to do so, subject to the following conditions:
  11.  *
  12.  * The above copyright notice and this permission notice shall be
  13.  * included in all copies or substantial portions of the Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16.  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18.  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  19.  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  20.  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22.  * SOFTWARE.
  23.  *
  24.  **********************************************************/
  25. /*
  26.  * TODO:
  27.  *
  28.  * Fencing is currently a bit inefficient, since we need to call the
  29.  * kernel do determine a fence object signaled status if the fence is not
  30.  * signaled. This can be greatly improved upon by using the fact that the
  31.  * execbuf ioctl returns the last signaled fence seqno, as does the
  32.  * fence signaled ioctl. We should set up a ring of fence objects and
  33.  * walk through them checking for signaled status each time we receive a
  34.  * new passed fence seqno.
  35.  */
  36.  
  37. #include "util/u_memory.h"
  38. #include "util/u_atomic.h"
  39.  
  40. #include "pipebuffer/pb_buffer_fenced.h"
  41.  
  42. #include "vmw_screen.h"
  43. #include "vmw_fence.h"
  44.  
  45. struct vmw_fence_ops
  46. {
  47.    struct pb_fence_ops base;
  48.  
  49.    struct vmw_winsys_screen *vws;
  50. };
  51.  
  52. struct vmw_fence
  53. {
  54.    int32_t refcount;
  55.    uint32_t handle;
  56.    uint32_t mask;
  57.    int32_t signalled;
  58. };
  59.  
  60. /**
  61.  * vmw_fence - return the vmw_fence object identified by a
  62.  * struct pipe_fence_handle *
  63.  *
  64.  * @fence: The opaque pipe fence handle.
  65.  */
  66. static INLINE struct vmw_fence *
  67. vmw_fence(struct pipe_fence_handle *fence)
  68. {
  69.    return (struct vmw_fence *) fence;
  70. }
  71.  
  72. /**
  73.  * vmw_fence_create - Create a user-space fence object.
  74.  *
  75.  * @handle: Handle identifying the kernel fence object.
  76.  * @mask: Mask of flags that this fence object may signal.
  77.  *
  78.  * Returns NULL on failure.
  79.  */
  80. struct pipe_fence_handle *
  81. vmw_fence_create(uint32_t handle, uint32_t mask)
  82. {
  83.    struct vmw_fence *fence = CALLOC_STRUCT(vmw_fence);
  84.  
  85.    if (!fence)
  86.       return NULL;
  87.  
  88.    p_atomic_set(&fence->refcount, 1);
  89.    fence->handle = handle;
  90.    fence->mask = mask;
  91.    p_atomic_set(&fence->signalled, 0);
  92.  
  93.    return (struct pipe_fence_handle *) fence;
  94. }
  95.  
  96. /**
  97.  * vmw_fence_ops - Return the vmw_fence_ops structure backing a
  98.  * struct pb_fence_ops pointer.
  99.  *
  100.  * @ops: Pointer to a struct pb_fence_ops.
  101.  *
  102.  */
  103. static INLINE struct vmw_fence_ops *
  104. vmw_fence_ops(struct pb_fence_ops *ops)
  105. {
  106.    assert(ops);
  107.    return (struct vmw_fence_ops *)ops;
  108. }
  109.  
  110.  
  111.  
  112. /**
  113.  * vmw_fence_reference - Reference / unreference a vmw fence object.
  114.  *
  115.  * @vws: Pointer to the winsys screen.
  116.  * @ptr: Pointer to reference transfer destination.
  117.  * @fence: Pointer to object to reference. May be NULL.
  118.  */
  119. void
  120. vmw_fence_reference(struct vmw_winsys_screen *vws,
  121.                     struct pipe_fence_handle **ptr,
  122.                     struct pipe_fence_handle *fence)
  123. {
  124.    if (*ptr) {
  125.       struct vmw_fence *vfence = vmw_fence(*ptr);
  126.  
  127.       if (p_atomic_dec_zero(&vfence->refcount)) {
  128.          vmw_ioctl_fence_unref(vws, vfence->handle);
  129.          FREE(vfence);
  130.       }
  131.    }
  132.  
  133.    if (fence) {
  134.       struct vmw_fence *vfence = vmw_fence(fence);
  135.  
  136.       p_atomic_inc(&vfence->refcount);
  137.    }
  138.  
  139.    *ptr = fence;
  140. }
  141.  
  142.  
  143. /**
  144.  * vmw_fence_signalled - Check whether a fence object is signalled.
  145.  *
  146.  * @vws: Pointer to the winsys screen.
  147.  * @fence: Handle to the fence object.
  148.  * @flag: Fence flags to check. If the fence object can't signal
  149.  * a flag, it is assumed to be already signaled.
  150.  *
  151.  * Returns 0 if the fence object was signaled, nonzero otherwise.
  152.  */
  153. int
  154. vmw_fence_signalled(struct vmw_winsys_screen *vws,
  155.                    struct pipe_fence_handle *fence,
  156.                    unsigned flag)
  157. {
  158.    struct vmw_fence *vfence;
  159.    int32_t vflags = SVGA_FENCE_FLAG_EXEC;
  160.    int ret;
  161.    uint32_t old;
  162.  
  163.    if (!fence)
  164.       return 0;
  165.  
  166.    vfence = vmw_fence(fence);
  167.    old = p_atomic_read(&vfence->signalled);
  168.  
  169.    vflags &= ~vfence->mask;
  170.  
  171.    if ((old & vflags) == vflags)
  172.       return 0;
  173.  
  174.    ret = vmw_ioctl_fence_signalled(vws, vfence->handle, vflags);
  175.  
  176.    if (ret == 0) {
  177.       int32_t prev = old;
  178.  
  179.       do {
  180.          old = prev;
  181.          prev = p_atomic_cmpxchg(&vfence->signalled, old, old | vflags);
  182.       } while (prev != old);
  183.    }
  184.  
  185.    return ret;
  186. }
  187.  
  188. /**
  189.  * vmw_fence_finish - Wait for a fence object to signal.
  190.  *
  191.  * @vws: Pointer to the winsys screen.
  192.  * @fence: Handle to the fence object.
  193.  * @flag: Fence flags to wait for. If the fence object can't signal
  194.  * a flag, it is assumed to be already signaled.
  195.  *
  196.  * Returns 0 if the wait succeeded. Nonzero otherwise.
  197.  */
  198. int
  199. vmw_fence_finish(struct vmw_winsys_screen *vws,
  200.                  struct pipe_fence_handle *fence,
  201.                  unsigned flag)
  202. {
  203.    struct vmw_fence *vfence;
  204.    int32_t vflags = SVGA_FENCE_FLAG_EXEC;
  205.    int ret;
  206.    uint32_t old;
  207.  
  208.    if (!fence)
  209.       return 0;
  210.  
  211.    vfence = vmw_fence(fence);
  212.    old = p_atomic_read(&vfence->signalled);
  213.    vflags &= ~vfence->mask;
  214.  
  215.    if ((old & vflags) == vflags)
  216.       return 0;
  217.  
  218.    ret = vmw_ioctl_fence_finish(vws, vfence->handle, vflags);
  219.  
  220.    if (ret == 0) {
  221.       int32_t prev = old;
  222.  
  223.       do {
  224.          old = prev;
  225.          prev = p_atomic_cmpxchg(&vfence->signalled, old, old | vflags);
  226.       } while (prev != old);
  227.    }
  228.  
  229.    return ret;
  230. }
  231.  
  232.  
  233. /**
  234.  * vmw_fence_ops_fence_reference - wrapper for the pb_fence_ops api.
  235.  *
  236.  * wrapper around vmw_fence_reference.
  237.  */
  238. static void
  239. vmw_fence_ops_fence_reference(struct pb_fence_ops *ops,
  240.                               struct pipe_fence_handle **ptr,
  241.                               struct pipe_fence_handle *fence)
  242. {
  243.    struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws;
  244.  
  245.    vmw_fence_reference(vws, ptr, fence);
  246. }
  247.  
  248. /**
  249.  * vmw_fence_ops_fence_signalled - wrapper for the pb_fence_ops api.
  250.  *
  251.  * wrapper around vmw_fence_signalled.
  252.  */
  253. static int
  254. vmw_fence_ops_fence_signalled(struct pb_fence_ops *ops,
  255.                               struct pipe_fence_handle *fence,
  256.                               unsigned flag)
  257. {
  258.    struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws;
  259.  
  260.    return vmw_fence_signalled(vws, fence, flag);
  261. }
  262.  
  263.  
  264. /**
  265.  * vmw_fence_ops_fence_finish - wrapper for the pb_fence_ops api.
  266.  *
  267.  * wrapper around vmw_fence_finish.
  268.  */
  269. static int
  270. vmw_fence_ops_fence_finish(struct pb_fence_ops *ops,
  271.                            struct pipe_fence_handle *fence,
  272.                            unsigned flag)
  273. {
  274.    struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws;
  275.  
  276.    return vmw_fence_finish(vws, fence, flag);
  277. }
  278.  
  279.  
  280. /**
  281.  * vmw_fence_ops_destroy - Destroy a pb_fence_ops function table.
  282.  *
  283.  * @ops: The function table to destroy.
  284.  *
  285.  * Part of the pb_fence_ops api.
  286.  */
  287. static void
  288. vmw_fence_ops_destroy(struct pb_fence_ops *ops)
  289. {
  290.    FREE(ops);
  291. }
  292.  
  293.  
  294. /**
  295.  * vmw_fence_ops_create - Create a pb_fence_ops function table.
  296.  *
  297.  * @vws: Pointer to a struct vmw_winsys_screen.
  298.  *
  299.  * Returns a pointer to a pb_fence_ops function table to interface
  300.  * with pipe_buffer. This function is typically called on driver setup.
  301.  *
  302.  * Returns NULL on failure.
  303.  */
  304. struct pb_fence_ops *
  305. vmw_fence_ops_create(struct vmw_winsys_screen *vws)
  306. {
  307.    struct vmw_fence_ops *ops;
  308.  
  309.    ops = CALLOC_STRUCT(vmw_fence_ops);
  310.    if(!ops)
  311.       return NULL;
  312.  
  313.    ops->base.destroy = &vmw_fence_ops_destroy;
  314.    ops->base.fence_reference = &vmw_fence_ops_fence_reference;
  315.    ops->base.fence_signalled = &vmw_fence_ops_fence_signalled;
  316.    ops->base.fence_finish = &vmw_fence_ops_fence_finish;
  317.  
  318.    ops->vws = vws;
  319.  
  320.    return &ops->base;
  321. }
  322.  
  323.  
  324.