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
00009
00010
00011
00012
00013 struct _DriFenceMgr {
00014
00015
00016
00017 struct _DriFenceMgrCreateInfo info;
00018 void *private;
00019
00020
00021
00022
00023 pipe_mutex mutex;
00024 int refCount;
00025 drmMMListHead *heads;
00026 int num_fences;
00027 };
00028
00029 struct _DriFenceObject {
00030
00031
00032
00033
00034 struct _DriFenceMgr *mgr;
00035 uint32_t fence_class;
00036 uint32_t fence_type;
00037
00038
00039
00040
00041 drmMMListHead head;
00042 int refCount;
00043
00044
00045
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
00142
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
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