pb_bufmgr_cache.c revision e06474dbae6979177629fb6187331291ff230c65
1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch/************************************************************************** 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * All Rights Reserved. 5c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Permission is hereby granted, free of charge, to any person obtaining a 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * copy of this software and associated documentation files (the 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * "Software"), to deal in the Software without restriction, including 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * without limitation the rights to use, copy, modify, merge, publish, 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * distribute, sub license, and/or sell copies of the Software, and to 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * permit persons to whom the Software is furnished to do so, subject to 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * the following conditions: 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * The above copyright notice and this permission notice (including the 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * next paragraph) shall be included in all copies or substantial portions 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * of the Software. 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) **************************************************************************/ 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * \file 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Buffer cache. 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * \author Jose Fonseca <jrfonseca-at-tungstengraphics-dot-com> 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * \author Thomas Hellström <thomas-at-tungstengraphics-dot-com> 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "pipe/p_compiler.h" 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "pipe/p_debug.h" 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "pipe/p_winsys.h" 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "pipe/p_thread.h" 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "util/u_memory.h" 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "util/u_double_list.h" 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "util/u_time.h" 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "pb_buffer.h" 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "pb_bufmgr.h" 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Convenience macro (type safe). 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#define SUPER(__derived) (&(__derived)->base) 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistruct pb_cache_manager; 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Wrapper around a pipe buffer which adds delayed destruction. 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistruct pb_cache_buffer 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct pb_buffer base; 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct pb_buffer *buffer; 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct pb_cache_manager *mgr; 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** Caching time interval */ 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct util_time start, end; 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct list_head head; 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistruct pb_cache_manager 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct pb_manager base; 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) struct pb_manager *provider; 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci unsigned usecs; 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pipe_mutex mutex; 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct list_head delayed; 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t numDelayed; 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}; 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic INLINE struct pb_cache_buffer * 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipb_cache_buffer(struct pb_buffer *buf) 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){ 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci assert(buf); 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return (struct pb_cache_buffer *)buf; 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic INLINE struct pb_cache_manager * 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipb_cache_manager(struct pb_manager *mgr) 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci assert(mgr); 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return (struct pb_cache_manager *)mgr; 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Actually destroy the buffer. 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic INLINE void 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci_pb_cache_buffer_destroy(struct pb_cache_buffer *buf) 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct pb_cache_manager *mgr = buf->mgr; 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LIST_DEL(&buf->head); 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci assert(mgr->numDelayed); 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci --mgr->numDelayed; 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci assert(!buf->base.base.refcount); 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci pb_reference(&buf->buffer, NULL); 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FREE(buf); 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Free as many cache buffers from the list head as possible. 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci_pb_cache_buffer_list_check_free(struct pb_cache_manager *mgr) 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{ 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct list_head *curr, *next; 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct pb_cache_buffer *buf; 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci struct util_time now; 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci util_time_get(&now); 1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci curr = mgr->delayed.next; 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci next = curr->next; 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while(curr != &mgr->delayed) { 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) buf = LIST_ENTRY(struct pb_cache_buffer, curr, head); 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 139 if(!util_time_timeout(&buf->start, &buf->end, &now)) 140 break; 141 142 _pb_cache_buffer_destroy(buf); 143 144 curr = next; 145 next = curr->next; 146 } 147} 148 149 150static void 151pb_cache_buffer_destroy(struct pb_buffer *_buf) 152{ 153 struct pb_cache_buffer *buf = pb_cache_buffer(_buf); 154 struct pb_cache_manager *mgr = buf->mgr; 155 156 pipe_mutex_lock(mgr->mutex); 157 assert(buf->base.base.refcount == 0); 158 159 _pb_cache_buffer_list_check_free(mgr); 160 161 util_time_get(&buf->start); 162 util_time_add(&buf->start, mgr->usecs, &buf->end); 163 LIST_ADDTAIL(&buf->head, &mgr->delayed); 164 ++mgr->numDelayed; 165 pipe_mutex_unlock(mgr->mutex); 166} 167 168 169static void * 170pb_cache_buffer_map(struct pb_buffer *_buf, 171 unsigned flags) 172{ 173 struct pb_cache_buffer *buf = pb_cache_buffer(_buf); 174 return pb_map(buf->buffer, flags); 175} 176 177 178static void 179pb_cache_buffer_unmap(struct pb_buffer *_buf) 180{ 181 struct pb_cache_buffer *buf = pb_cache_buffer(_buf); 182 pb_unmap(buf->buffer); 183} 184 185 186static enum pipe_error 187pb_cache_buffer_validate(struct pb_buffer *_buf, 188 struct pb_validate *vl, 189 unsigned flags) 190{ 191 struct pb_cache_buffer *buf = pb_cache_buffer(_buf); 192 return pb_validate(buf->buffer, vl, flags); 193} 194 195 196static void 197pb_cache_buffer_fence(struct pb_buffer *_buf, 198 struct pipe_fence_handle *fence) 199{ 200 struct pb_cache_buffer *buf = pb_cache_buffer(_buf); 201 pb_fence(buf->buffer, fence); 202} 203 204 205static void 206pb_cache_buffer_get_base_buffer(struct pb_buffer *_buf, 207 struct pb_buffer **base_buf, 208 unsigned *offset) 209{ 210 struct pb_cache_buffer *buf = pb_cache_buffer(_buf); 211 pb_get_base_buffer(buf->buffer, base_buf, offset); 212} 213 214 215const struct pb_vtbl 216pb_cache_buffer_vtbl = { 217 pb_cache_buffer_destroy, 218 pb_cache_buffer_map, 219 pb_cache_buffer_unmap, 220 pb_cache_buffer_validate, 221 pb_cache_buffer_fence, 222 pb_cache_buffer_get_base_buffer 223}; 224 225 226static INLINE boolean 227pb_cache_is_buffer_compat(struct pb_cache_buffer *buf, 228 size_t size, 229 const struct pb_desc *desc) 230{ 231 if(buf->base.base.size < size) 232 return FALSE; 233 234 /* be lenient with size */ 235 if(buf->base.base.size >= 2*size) 236 return FALSE; 237 238 if(!pb_check_alignment(desc->alignment, buf->base.base.alignment)) 239 return FALSE; 240 241 if(!pb_check_usage(desc->usage, buf->base.base.usage)) 242 return FALSE; 243 244 return TRUE; 245} 246 247 248static struct pb_buffer * 249pb_cache_manager_create_buffer(struct pb_manager *_mgr, 250 size_t size, 251 const struct pb_desc *desc) 252{ 253 struct pb_cache_manager *mgr = pb_cache_manager(_mgr); 254 struct pb_cache_buffer *buf; 255 struct pb_cache_buffer *curr_buf; 256 struct list_head *curr, *next; 257 struct util_time now; 258 259 pipe_mutex_lock(mgr->mutex); 260 261 buf = NULL; 262 curr = mgr->delayed.next; 263 next = curr->next; 264 265 /* search in the expired buffers, freeing them in the process */ 266 util_time_get(&now); 267 while(curr != &mgr->delayed) { 268 curr_buf = LIST_ENTRY(struct pb_cache_buffer, curr, head); 269 if(!buf && pb_cache_is_buffer_compat(curr_buf, size, desc)) 270 buf = curr_buf; 271 else if(util_time_timeout(&curr_buf->start, &curr_buf->end, &now)) 272 _pb_cache_buffer_destroy(curr_buf); 273 else 274 /* This buffer (and all hereafter) are still hot in cache */ 275 break; 276 curr = next; 277 next = curr->next; 278 } 279 280 /* keep searching in the hot buffers */ 281 if(!buf) { 282 while(curr != &mgr->delayed) { 283 curr_buf = LIST_ENTRY(struct pb_cache_buffer, curr, head); 284 if(pb_cache_is_buffer_compat(curr_buf, size, desc)) { 285 buf = curr_buf; 286 break; 287 } 288 /* no need to check the timeout here */ 289 curr = next; 290 next = curr->next; 291 } 292 } 293 294 if(buf) { 295 LIST_DEL(&buf->head); 296 pipe_mutex_unlock(mgr->mutex); 297 ++buf->base.base.refcount; 298 return &buf->base; 299 } 300 301 pipe_mutex_unlock(mgr->mutex); 302 303 buf = CALLOC_STRUCT(pb_cache_buffer); 304 if(!buf) 305 return NULL; 306 307 buf->buffer = mgr->provider->create_buffer(mgr->provider, size, desc); 308 if(!buf->buffer) { 309 FREE(buf); 310 return NULL; 311 } 312 313 assert(buf->buffer->base.refcount >= 1); 314 assert(pb_check_alignment(desc->alignment, buf->buffer->base.alignment)); 315 assert(pb_check_usage(desc->usage, buf->buffer->base.usage)); 316 assert(buf->buffer->base.size >= size); 317 318 buf->base.base.refcount = 1; 319 buf->base.base.alignment = buf->buffer->base.alignment; 320 buf->base.base.usage = buf->buffer->base.usage; 321 buf->base.base.size = buf->buffer->base.size; 322 323 buf->base.vtbl = &pb_cache_buffer_vtbl; 324 buf->mgr = mgr; 325 326 return &buf->base; 327} 328 329 330static void 331pb_cache_manager_flush(struct pb_manager *_mgr) 332{ 333 struct pb_cache_manager *mgr = pb_cache_manager(_mgr); 334 struct list_head *curr, *next; 335 struct pb_cache_buffer *buf; 336 337 pipe_mutex_lock(mgr->mutex); 338 curr = mgr->delayed.next; 339 next = curr->next; 340 while(curr != &mgr->delayed) { 341 buf = LIST_ENTRY(struct pb_cache_buffer, curr, head); 342 _pb_cache_buffer_destroy(buf); 343 curr = next; 344 next = curr->next; 345 } 346 pipe_mutex_unlock(mgr->mutex); 347 348 assert(mgr->provider->flush); 349 if(mgr->provider->flush) 350 mgr->provider->flush(mgr->provider); 351} 352 353 354static void 355pb_cache_manager_destroy(struct pb_manager *mgr) 356{ 357 pb_cache_manager_flush(mgr); 358 FREE(mgr); 359} 360 361 362struct pb_manager * 363pb_cache_manager_create(struct pb_manager *provider, 364 unsigned usecs) 365{ 366 struct pb_cache_manager *mgr; 367 368 if(!provider) 369 return NULL; 370 371 mgr = CALLOC_STRUCT(pb_cache_manager); 372 if (!mgr) 373 return NULL; 374 375 mgr->base.destroy = pb_cache_manager_destroy; 376 mgr->base.create_buffer = pb_cache_manager_create_buffer; 377 mgr->base.flush = pb_cache_manager_flush; 378 mgr->provider = provider; 379 mgr->usecs = usecs; 380 LIST_INITHEAD(&mgr->delayed); 381 mgr->numDelayed = 0; 382 pipe_mutex_init(mgr->mutex); 383 384 return &mgr->base; 385} 386