1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 29#include "pipe/p_screen.h" 30#include "util/u_memory.h" 31#include "lp_debug.h" 32#include "lp_fence.h" 33 34 35#include "util/timespec.h" 36 37/** 38 * Create a new fence object. 39 * 40 * The rank will be the number of bins in the scene. Whenever a rendering 41 * thread hits a fence command, it'll increment the fence counter. When 42 * the counter == the rank, the fence is finished. 43 * 44 * \param rank the expected finished value of the fence counter. 45 */ 46struct lp_fence * 47lp_fence_create(unsigned rank) 48{ 49 static unsigned fence_id = 0; 50 struct lp_fence *fence = CALLOC_STRUCT(lp_fence); 51 52 if (!fence) 53 return NULL; 54 55 pipe_reference_init(&fence->reference, 1); 56 57 (void) mtx_init(&fence->mutex, mtx_plain); 58 cnd_init(&fence->signalled); 59 60 fence->id = p_atomic_inc_return(&fence_id) - 1; 61 fence->rank = rank; 62 63 if (LP_DEBUG & DEBUG_FENCE) 64 debug_printf("%s %d\n", __FUNCTION__, fence->id); 65 66 return fence; 67} 68 69 70/** Destroy a fence. Called when refcount hits zero. */ 71void 72lp_fence_destroy(struct lp_fence *fence) 73{ 74 if (LP_DEBUG & DEBUG_FENCE) 75 debug_printf("%s %d\n", __FUNCTION__, fence->id); 76 77 mtx_destroy(&fence->mutex); 78 cnd_destroy(&fence->signalled); 79 FREE(fence); 80} 81 82 83/** 84 * Called by the rendering threads to increment the fence counter. 85 * When the counter == the rank, the fence is finished. 86 */ 87void 88lp_fence_signal(struct lp_fence *fence) 89{ 90 if (LP_DEBUG & DEBUG_FENCE) 91 debug_printf("%s %d\n", __FUNCTION__, fence->id); 92 93 mtx_lock(&fence->mutex); 94 95 fence->count++; 96 assert(fence->count <= fence->rank); 97 98 if (LP_DEBUG & DEBUG_FENCE) 99 debug_printf("%s count=%u rank=%u\n", __FUNCTION__, 100 fence->count, fence->rank); 101 102 /* Wakeup all threads waiting on the mutex: 103 */ 104 cnd_broadcast(&fence->signalled); 105 106 mtx_unlock(&fence->mutex); 107} 108 109boolean 110lp_fence_signalled(struct lp_fence *f) 111{ 112 return f->count == f->rank; 113} 114 115void 116lp_fence_wait(struct lp_fence *f) 117{ 118 if (LP_DEBUG & DEBUG_FENCE) 119 debug_printf("%s %d\n", __FUNCTION__, f->id); 120 121 mtx_lock(&f->mutex); 122 assert(f->issued); 123 while (f->count < f->rank) { 124 cnd_wait(&f->signalled, &f->mutex); 125 } 126 mtx_unlock(&f->mutex); 127} 128 129 130boolean 131lp_fence_timedwait(struct lp_fence *f, uint64_t timeout) 132{ 133 struct timespec ts, abs_ts; 134 int ret; 135 136 timespec_get(&ts, TIME_UTC); 137 138 bool ts_overflow = timespec_add_nsec(&abs_ts, &ts, timeout); 139 140 if (LP_DEBUG & DEBUG_FENCE) 141 debug_printf("%s %d\n", __FUNCTION__, f->id); 142 143 mtx_lock(&f->mutex); 144 assert(f->issued); 145 while (f->count < f->rank) { 146 if (ts_overflow) 147 ret = cnd_wait(&f->signalled, &f->mutex); 148 else 149 ret = cnd_timedwait(&f->signalled, &f->mutex, &abs_ts); 150 if (ret != thrd_success) 151 break; 152 } 153 const boolean result = (f->count >= f->rank); 154 mtx_unlock(&f->mutex); 155 return result; 156} 157