pb_buffer_fenced.c revision b9da3791c934e05b82063a8c79c423a0a8e29a94
1/************************************************************************** 2 * 3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. 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 TUNGSTEN GRAPHICS 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 * \file 30 * Implementation of fenced buffers. 31 * 32 * \author Jos� Fonseca <jrfonseca-at-tungstengraphics-dot-com> 33 * \author Thomas Hellstr�m <thomas-at-tungstengraphics-dot-com> 34 */ 35 36 37#include "pipe/p_compiler.h" 38#include "pipe/p_debug.h" 39#include "pipe/p_winsys.h" 40#include "pipe/p_thread.h" 41#include "pipe/p_util.h" 42#include "util/u_double_list.h" 43 44#include "pb_buffer.h" 45#include "pb_buffer_fenced.h" 46 47#ifndef __MSC__ 48#include <unistd.h> 49#endif 50 51 52/** 53 * Convenience macro (type safe). 54 */ 55#define SUPER(__derived) (&(__derived)->base) 56 57 58struct fenced_buffer_list 59{ 60 _glthread_Mutex mutex; 61 62 struct pipe_winsys *winsys; 63 64 size_t numDelayed; 65 size_t checkDelayed; 66 67 struct list_head delayed; 68}; 69 70 71/** 72 * Wrapper around a pipe buffer which adds fencing and reference counting. 73 */ 74struct fenced_buffer 75{ 76 struct pb_buffer base; 77 78 struct pb_buffer *buffer; 79 80 struct pipe_fence_handle *fence; 81 82 struct list_head head; 83 struct fenced_buffer_list *list; 84}; 85 86 87static INLINE struct fenced_buffer * 88fenced_buffer(struct pb_buffer *buf) 89{ 90 assert(buf); 91 assert(buf->vtbl == &fenced_buffer_vtbl); 92 return (struct fenced_buffer *)buf; 93} 94 95 96 97 98static void 99_fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, 100 int wait) 101{ 102 struct pipe_winsys *winsys = fenced_list->winsys; 103 struct fenced_buffer *fenced_buf; 104 struct list_head *list, *prev; 105 int signaled = -1; 106 107 list = fenced_list->delayed.next; 108 109 if (fenced_list->numDelayed > 3) { 110 unsigned i; 111 112 for (i = 0; i < fenced_list->numDelayed; i += 3) { 113 list = list->next; 114 } 115 } 116 117 prev = list->prev; 118 for (; list != &fenced_list->delayed; list = prev, prev = list->prev) { 119 120 fenced_buf = LIST_ENTRY(struct fenced_buffer, list, head); 121 122 if (signaled != 0) { 123 if (wait) { 124 signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0); 125 } 126 else { 127 signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0); 128 } 129 } 130 131 if (signaled != 0) 132 /* XXX: we are assuming that buffers are freed in the same order they 133 * are fenced which may not always be true... 134 */ 135 break; 136 137 winsys->fence_reference(winsys, &fenced_buf->fence, NULL); 138 139 LIST_DEL(list); 140 fenced_list->numDelayed--; 141 142 /* Do the delayed destroy: 143 */ 144 pb_reference(&fenced_buf->buffer, NULL); 145 FREE(fenced_buf); 146 } 147} 148 149 150static void 151fenced_buffer_destroy(struct pb_buffer *buf) 152{ 153 struct fenced_buffer *fenced_buf = fenced_buffer(buf); 154 struct fenced_buffer_list *fenced_list = fenced_buf->list; 155 156 if (fenced_buf->fence) { 157 LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed); 158 fenced_list->numDelayed++; 159 } 160 else { 161 pb_reference(&fenced_buf->buffer, NULL); 162 FREE(fenced_buf); 163 } 164 165 if ((fenced_list->numDelayed % fenced_list->checkDelayed) == 0) 166 _fenced_buffer_list_check_free(fenced_list, 0); 167} 168 169 170static void * 171fenced_buffer_map(struct pb_buffer *buf, 172 unsigned flags) 173{ 174 struct fenced_buffer *fenced_buf = fenced_buffer(buf); 175 return pb_map(fenced_buf->buffer, flags); 176} 177 178 179static void 180fenced_buffer_unmap(struct pb_buffer *buf) 181{ 182 struct fenced_buffer *fenced_buf = fenced_buffer(buf); 183 pb_unmap(fenced_buf->buffer); 184} 185 186 187static void 188fenced_buffer_get_base_buffer(struct pb_buffer *buf, 189 struct pb_buffer **base_buf, 190 unsigned *offset) 191{ 192 struct fenced_buffer *fenced_buf = fenced_buffer(buf); 193 pb_get_base_buffer(fenced_buf->buffer, base_buf, offset); 194} 195 196 197const struct pb_vtbl 198fenced_buffer_vtbl = { 199 fenced_buffer_destroy, 200 fenced_buffer_map, 201 fenced_buffer_unmap, 202 fenced_buffer_get_base_buffer 203}; 204 205 206struct pb_buffer * 207fenced_buffer_create(struct fenced_buffer_list *fenced_list, 208 struct pb_buffer *buffer) 209{ 210 struct fenced_buffer *buf; 211 212 if(!buffer) 213 return NULL; 214 215 buf = CALLOC_STRUCT(fenced_buffer); 216 if(!buf) 217 return NULL; 218 219 buf->base.base.refcount = 1; 220 buf->base.base.alignment = buffer->base.alignment; 221 buf->base.base.usage = buffer->base.usage; 222 buf->base.base.size = buffer->base.size; 223 224 buf->base.vtbl = &fenced_buffer_vtbl; 225 buf->buffer = buffer; 226 buf->list = fenced_list; 227 228 return &buf->base; 229} 230 231 232void 233buffer_fence(struct pb_buffer *buf, 234 struct pipe_fence_handle *fence) 235{ 236 struct fenced_buffer *fenced_buf = fenced_buffer(buf); 237 struct fenced_buffer_list *fenced_list = fenced_buf->list; 238 struct pipe_winsys *winsys = fenced_list->winsys; 239 240 _glthread_LOCK_MUTEX(fenced_list->mutex); 241 winsys->fence_reference(winsys, &fenced_buf->fence, fence); 242 _glthread_UNLOCK_MUTEX(fenced_list->mutex); 243} 244 245 246struct fenced_buffer_list * 247fenced_buffer_list_create(struct pipe_winsys *winsys) 248{ 249 struct fenced_buffer_list *fenced_list; 250 251 fenced_list = (struct fenced_buffer_list *)CALLOC(1, sizeof(*fenced_list)); 252 if (!fenced_list) 253 return NULL; 254 255 fenced_list->winsys = winsys; 256 257 LIST_INITHEAD(&fenced_list->delayed); 258 259 fenced_list->numDelayed = 0; 260 261 /* TODO: don't hard code this */ 262 fenced_list->checkDelayed = 5; 263 264 _glthread_INIT_MUTEX(fenced_list->mutex); 265 266 return fenced_list; 267} 268 269 270void 271fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, 272 int wait) 273{ 274 _glthread_LOCK_MUTEX(fenced_list->mutex); 275 _fenced_buffer_list_check_free(fenced_list, wait); 276 _glthread_UNLOCK_MUTEX(fenced_list->mutex); 277} 278 279 280void 281fenced_buffer_list_destroy(struct fenced_buffer_list *fenced_list) 282{ 283 _glthread_LOCK_MUTEX(fenced_list->mutex); 284 285 /* Wait on outstanding fences */ 286 while (fenced_list->numDelayed) { 287 _glthread_UNLOCK_MUTEX(fenced_list->mutex); 288 sched_yield(); 289 _fenced_buffer_list_check_free(fenced_list, 1); 290 _glthread_LOCK_MUTEX(fenced_list->mutex); 291 } 292 293 _glthread_UNLOCK_MUTEX(fenced_list->mutex); 294 295 FREE(fenced_list); 296} 297 298 299