ws_dri_fencemgr.c

Go to the documentation of this file.
00001 #include "ws_dri_fencemgr.h"
00002 #include "pipe/p_thread.h"
00003 #include <xf86mm.h>
00004 #include <string.h>
00005 #include <unistd.h>
00006 
00007 /*
00008  * Note: Locking order is
00009  * _DriFenceObject::mutex
00010  * _DriFenceMgr::mutex
00011  */
00012 
00013 struct _DriFenceMgr {
00014     /*
00015      * Constant members. Need no mutex protection.
00016      */
00017     struct _DriFenceMgrCreateInfo info;
00018     void *private;
00019 
00020     /*
00021      * These members are protected by this->mutex
00022      */
00023     pipe_mutex mutex;
00024     int refCount;
00025     drmMMListHead *heads;
00026     int num_fences;
00027 };
00028 
00029 struct _DriFenceObject {
00030 
00031     /*
00032      * These members are constant and need no mutex protection.
00033      */
00034     struct _DriFenceMgr *mgr;
00035     uint32_t fence_class;
00036     uint32_t fence_type;
00037 
00038     /*
00039      * These members are protected by mgr->mutex.
00040      */
00041     drmMMListHead head;
00042     int refCount;
00043 
00044     /*
00045      * These members are protected by this->mutex.
00046      */
00047     pipe_mutex mutex;
00048     uint32_t signaled_type;
00049     void *private;
00050 };
00051 
00052 uint32_t
00053 driFenceType(struct _DriFenceObject *fence)
00054 {
00055   return fence->fence_type;
00056 }
00057 
00058 struct _DriFenceMgr *
00059 driFenceMgrCreate(const struct _DriFenceMgrCreateInfo *info)
00060 {
00061   struct _DriFenceMgr *tmp;
00062   uint32_t i;
00063 
00064   tmp = calloc(1, sizeof(*tmp));
00065   if (!tmp)
00066       return NULL;
00067 
00068   pipe_mutex_init(tmp->mutex);
00069   pipe_mutex_lock(tmp->mutex);
00070   tmp->refCount = 1;
00071   tmp->info = *info;
00072   tmp->num_fences = 0;
00073   tmp->heads = calloc(tmp->info.num_classes, sizeof(*tmp->heads));
00074   if (!tmp->heads)
00075       goto out_err;
00076 
00077   for (i=0; i<tmp->info.num_classes; ++i) {
00078       DRMINITLISTHEAD(&tmp->heads[i]);
00079   }
00080   pipe_mutex_unlock(tmp->mutex);
00081   return tmp;
00082 
00083   out_err:
00084   if (tmp)
00085       free(tmp);
00086   return NULL;
00087 }
00088 
00089 static void
00090 driFenceMgrUnrefUnlock(struct _DriFenceMgr **pMgr)
00091 {
00092     struct _DriFenceMgr *mgr = *pMgr;
00093 
00094     *pMgr = NULL;
00095     if (--mgr->refCount == 0)
00096         free(mgr);
00097     else
00098         pipe_mutex_unlock(mgr->mutex);
00099 }
00100 
00101 void
00102 driFenceMgrUnReference(struct _DriFenceMgr **pMgr)
00103 {
00104     pipe_mutex_lock((*pMgr)->mutex);
00105     driFenceMgrUnrefUnlock(pMgr);
00106 }
00107 
00108 static void
00109 driFenceUnReferenceLocked(struct _DriFenceObject **pFence)
00110 {
00111     struct _DriFenceObject *fence = *pFence;
00112     struct _DriFenceMgr *mgr = fence->mgr;
00113 
00114     *pFence = NULL;
00115     if (--fence->refCount == 0) {
00116         DRMLISTDELINIT(&fence->head);
00117         if (fence->private)
00118             mgr->info.unreference(mgr, &fence->private);
00119     --mgr->num_fences;
00120         fence->mgr = NULL;
00121         --mgr->refCount;
00122         free(fence);
00123 
00124     }
00125 }
00126 
00127 
00128 static void
00129 driSignalPreviousFencesLocked(struct _DriFenceMgr *mgr,
00130                               drmMMListHead *list,
00131                               uint32_t fence_class,
00132                               uint32_t fence_type)
00133 {
00134     struct _DriFenceObject *entry;
00135     drmMMListHead *prev;
00136 
00137     while(list != &mgr->heads[fence_class]) {
00138         entry = DRMLISTENTRY(struct _DriFenceObject, list, head);
00139 
00140         /*
00141          * Up refcount so that entry doesn't disappear from under us
00142          * when we unlock-relock mgr to get the correct locking order.
00143          */
00144 
00145         ++entry->refCount;
00146         pipe_mutex_unlock(mgr->mutex);
00147         pipe_mutex_lock(entry->mutex);
00148         pipe_mutex_lock(mgr->mutex);
00149 
00150         prev = list->prev;
00151 
00152 
00153 
00154         if (list->prev == list) {
00155 
00156                 /*
00157                  * Somebody else removed the entry from the list.
00158                  */
00159 
00160                 pipe_mutex_unlock(entry->mutex);
00161                 driFenceUnReferenceLocked(&entry);
00162                 return;
00163         }
00164 
00165         entry->signaled_type |= (fence_type & entry->fence_type);
00166         if (entry->signaled_type == entry->fence_type) {
00167             DRMLISTDELINIT(list);
00168             mgr->info.unreference(mgr, &entry->private);
00169         }
00170         pipe_mutex_unlock(entry->mutex);
00171         driFenceUnReferenceLocked(&entry);
00172         list = prev;
00173     }
00174 }
00175 
00176 
00177 int
00178 driFenceFinish(struct _DriFenceObject *fence, uint32_t fence_type,
00179                int lazy_hint)
00180 {
00181     struct _DriFenceMgr *mgr = fence->mgr;
00182     int ret = 0;
00183 
00184     pipe_mutex_lock(fence->mutex);
00185 
00186     if ((fence->signaled_type & fence_type) == fence_type)
00187         goto out0;
00188 
00189     ret = mgr->info.finish(mgr, fence->private, fence_type, lazy_hint);
00190     if (ret)
00191         goto out0;
00192 
00193     pipe_mutex_lock(mgr->mutex);
00194     pipe_mutex_unlock(fence->mutex);
00195 
00196     driSignalPreviousFencesLocked(mgr, &fence->head, fence->fence_class,
00197                                   fence_type);
00198     pipe_mutex_unlock(mgr->mutex);
00199     return 0;
00200 
00201   out0:
00202     pipe_mutex_unlock(fence->mutex);
00203     return ret;
00204 }
00205 
00206 uint32_t driFenceSignaledTypeCached(struct _DriFenceObject *fence)
00207 {
00208     uint32_t ret;
00209 
00210     pipe_mutex_lock(fence->mutex);
00211     ret = fence->signaled_type;
00212     pipe_mutex_unlock(fence->mutex);
00213 
00214     return ret;
00215 }
00216 
00217 int
00218 driFenceSignaledType(struct _DriFenceObject *fence, uint32_t flush_type,
00219                  uint32_t *signaled)
00220 {
00221     int ret = 0;
00222     struct _DriFenceMgr *mgr;
00223 
00224     pipe_mutex_lock(fence->mutex);
00225     mgr = fence->mgr;
00226     *signaled = fence->signaled_type;
00227     if ((fence->signaled_type & flush_type) == flush_type)
00228         goto out0;
00229 
00230     ret = mgr->info.signaled(mgr, fence->private, flush_type, signaled);
00231     if (ret) {
00232         *signaled = fence->signaled_type;
00233         goto out0;
00234     }
00235 
00236     if ((fence->signaled_type | *signaled) == fence->signaled_type)
00237         goto out0;
00238 
00239     pipe_mutex_lock(mgr->mutex);
00240     pipe_mutex_unlock(fence->mutex);
00241 
00242     driSignalPreviousFencesLocked(mgr, &fence->head, fence->fence_class,
00243                                   *signaled);
00244 
00245     pipe_mutex_unlock(mgr->mutex);
00246     return 0;
00247   out0:
00248     pipe_mutex_unlock(fence->mutex);
00249     return ret;
00250 }
00251 
00252 struct _DriFenceObject *
00253 driFenceReference(struct _DriFenceObject *fence)
00254 {
00255     pipe_mutex_lock(fence->mgr->mutex);
00256     ++fence->refCount;
00257     pipe_mutex_unlock(fence->mgr->mutex);
00258     return fence;
00259 }
00260 
00261 void
00262 driFenceUnReference(struct _DriFenceObject **pFence)
00263 {
00264     struct _DriFenceMgr *mgr;
00265 
00266     if (*pFence == NULL)
00267         return;
00268 
00269     mgr = (*pFence)->mgr;
00270     pipe_mutex_lock(mgr->mutex);
00271     ++mgr->refCount;
00272     driFenceUnReferenceLocked(pFence);
00273     driFenceMgrUnrefUnlock(&mgr);
00274 }
00275 
00276 struct _DriFenceObject
00277 *driFenceCreate(struct _DriFenceMgr *mgr, uint32_t fence_class,
00278                 uint32_t fence_type, void *private, size_t private_size)
00279 {
00280     struct _DriFenceObject *fence;
00281     size_t fence_size = sizeof(*fence);
00282 
00283     if (private_size)
00284         fence_size = ((fence_size + 15) & ~15);
00285 
00286     fence = calloc(1, fence_size + private_size);
00287 
00288     if (!fence) {
00289         int ret = mgr->info.finish(mgr, private, fence_type, 0);
00290 
00291         if (ret)
00292             usleep(10000000);
00293 
00294         return NULL;
00295     }
00296 
00297     pipe_mutex_init(fence->mutex);
00298     pipe_mutex_lock(fence->mutex);
00299     pipe_mutex_lock(mgr->mutex);
00300     fence->refCount = 1;
00301     DRMLISTADDTAIL(&fence->head, &mgr->heads[fence_class]);
00302     fence->mgr = mgr;
00303     ++mgr->refCount;
00304     ++mgr->num_fences;
00305     pipe_mutex_unlock(mgr->mutex);
00306     fence->fence_class = fence_class;
00307     fence->fence_type = fence_type;
00308     fence->signaled_type = 0;
00309     fence->private = private;
00310     if (private_size) {
00311         fence->private = (void *)(((uint8_t *) fence) + fence_size);
00312         memcpy(fence->private, private, private_size);
00313     }
00314 
00315     pipe_mutex_unlock(fence->mutex);
00316     return fence;
00317 }
00318 
00319 
00320 static int
00321 tSignaled(struct _DriFenceMgr *mgr, void *private, uint32_t flush_type,
00322           uint32_t *signaled_type)
00323 {
00324   long fd = (long) mgr->private;
00325   int dummy;
00326   drmFence *fence = (drmFence *) private;
00327   int ret;
00328 
00329   *signaled_type = 0;
00330   ret = drmFenceSignaled((int) fd, fence, flush_type, &dummy);
00331   if (ret)
00332     return ret;
00333 
00334   *signaled_type = fence->signaled;
00335 
00336   return 0;
00337 }
00338 
00339 static int
00340 tFinish(struct _DriFenceMgr *mgr, void *private, uint32_t fence_type,
00341         int lazy_hint)
00342 {
00343   long fd = (long) mgr->private;
00344   unsigned flags = lazy_hint ? DRM_FENCE_FLAG_WAIT_LAZY : 0;
00345 
00346   return drmFenceWait((int)fd, flags, (drmFence *) private, fence_type);
00347 }
00348 
00349 static int
00350 tUnref(struct _DriFenceMgr *mgr, void **private)
00351 {
00352   long fd = (long) mgr->private;
00353   drmFence *fence = (drmFence *) *private;
00354   *private = NULL;
00355 
00356   return drmFenceUnreference(fd, fence);
00357 }
00358 
00359 struct _DriFenceMgr *driFenceMgrTTMInit(int fd)
00360 {
00361   struct _DriFenceMgrCreateInfo info;
00362   struct _DriFenceMgr *mgr;
00363 
00364   info.flags = DRI_FENCE_CLASS_ORDERED;
00365   info.num_classes = 4;
00366   info.signaled = tSignaled;
00367   info.finish = tFinish;
00368   info.unreference = tUnref;
00369 
00370   mgr = driFenceMgrCreate(&info);
00371   if (mgr == NULL)
00372     return NULL;
00373 
00374   mgr->private = (void *) (long) fd;
00375   return mgr;
00376 }
00377 

Generated on Tue Sep 29 06:25:17 2009 for Gallium3D by  doxygen 1.5.4