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