1/********************************************************** 2 * Copyright 2008-2009 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 **********************************************************/ 25 26#include "util/u_math.h" 27#include "util/u_memory.h" 28#include "util/crc32.h" 29 30#include "svga_debug.h" 31#include "svga_format.h" 32#include "svga_winsys.h" 33#include "svga_screen.h" 34#include "svga_screen_cache.h" 35 36 37#define SVGA_SURFACE_CACHE_ENABLED 1 38 39 40/** 41 * Return the size of the surface described by the key (in bytes). 42 */ 43static unsigned 44surface_size(const struct svga_host_surface_cache_key *key) 45{ 46 unsigned bw, bh, bpb, total_size, i; 47 48 assert(key->numMipLevels > 0); 49 assert(key->numFaces > 0); 50 51 if (key->format == SVGA3D_BUFFER) { 52 /* Special case: we don't want to count vertex/index buffers 53 * against the cache size limit, so view them as zero-sized. 54 */ 55 return 0; 56 } 57 58 svga_format_size(key->format, &bw, &bh, &bpb); 59 60 total_size = 0; 61 62 for (i = 0; i < key->numMipLevels; i++) { 63 unsigned w = u_minify(key->size.width, i); 64 unsigned h = u_minify(key->size.height, i); 65 unsigned d = u_minify(key->size.depth, i); 66 unsigned img_size = ((w + bw - 1) / bw) * ((h + bh - 1) / bh) * d * bpb; 67 total_size += img_size; 68 } 69 70 total_size *= key->numFaces; 71 72 return total_size; 73} 74 75 76/** 77 * Compute the bucket for this key. 78 */ 79static inline unsigned 80svga_screen_cache_bucket(const struct svga_host_surface_cache_key *key) 81{ 82 return util_hash_crc32(key, sizeof *key) % SVGA_HOST_SURFACE_CACHE_BUCKETS; 83} 84 85 86/** 87 * Search the cache for a surface that matches the key. If a match is 88 * found, remove it from the cache and return the surface pointer. 89 * Return NULL otherwise. 90 */ 91static struct svga_winsys_surface * 92svga_screen_cache_lookup(struct svga_screen *svgascreen, 93 const struct svga_host_surface_cache_key *key) 94{ 95 struct svga_host_surface_cache *cache = &svgascreen->cache; 96 struct svga_winsys_screen *sws = svgascreen->sws; 97 struct svga_host_surface_cache_entry *entry; 98 struct svga_winsys_surface *handle = NULL; 99 struct list_head *curr, *next; 100 unsigned bucket; 101 unsigned tries = 0; 102 103 assert(key->cachable); 104 105 bucket = svga_screen_cache_bucket(key); 106 107 pipe_mutex_lock(cache->mutex); 108 109 curr = cache->bucket[bucket].next; 110 next = curr->next; 111 while (curr != &cache->bucket[bucket]) { 112 ++tries; 113 114 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, bucket_head); 115 116 assert(entry->handle); 117 118 /* If the key matches and the fence is signalled (the surface is no 119 * longer needed) the lookup was successful. We found a surface that 120 * can be reused. 121 * We unlink the surface from the cache entry and we add the entry to 122 * the 'empty' list. 123 */ 124 if (memcmp(&entry->key, key, sizeof *key) == 0 && 125 sws->fence_signalled(sws, entry->fence, 0) == 0) { 126 unsigned surf_size; 127 128 assert(sws->surface_is_flushed(sws, entry->handle)); 129 130 handle = entry->handle; /* Reference is transfered here. */ 131 entry->handle = NULL; 132 133 /* Remove from hash table */ 134 LIST_DEL(&entry->bucket_head); 135 136 /* remove from LRU list */ 137 LIST_DEL(&entry->head); 138 139 /* Add the cache entry (but not the surface!) to the empty list */ 140 LIST_ADD(&entry->head, &cache->empty); 141 142 /* update the cache size */ 143 surf_size = surface_size(&entry->key); 144 assert(surf_size <= cache->total_size); 145 if (surf_size > cache->total_size) 146 cache->total_size = 0; /* should never happen, but be safe */ 147 else 148 cache->total_size -= surf_size; 149 150 break; 151 } 152 153 curr = next; 154 next = curr->next; 155 } 156 157 pipe_mutex_unlock(cache->mutex); 158 159 if (SVGA_DEBUG & DEBUG_DMA) 160 debug_printf("%s: cache %s after %u tries (bucket %d)\n", __FUNCTION__, 161 handle ? "hit" : "miss", tries, bucket); 162 163 return handle; 164} 165 166 167/** 168 * Free the least recently used entries in the surface cache until the 169 * cache size is <= the target size OR there are no unused entries left 170 * to discard. We don't do any flushing to try to free up additional 171 * surfaces. 172 */ 173static void 174svga_screen_cache_shrink(struct svga_screen *svgascreen, 175 unsigned target_size) 176{ 177 struct svga_host_surface_cache *cache = &svgascreen->cache; 178 struct svga_winsys_screen *sws = svgascreen->sws; 179 struct svga_host_surface_cache_entry *entry = NULL, *next_entry; 180 181 /* Walk over the list of unused buffers in reverse order: from oldest 182 * to newest. 183 */ 184 LIST_FOR_EACH_ENTRY_SAFE_REV(entry, next_entry, &cache->unused, head) { 185 if (entry->key.format != SVGA3D_BUFFER) { 186 /* we don't want to discard vertex/index buffers */ 187 188 cache->total_size -= surface_size(&entry->key); 189 190 assert(entry->handle); 191 sws->surface_reference(sws, &entry->handle, NULL); 192 193 LIST_DEL(&entry->bucket_head); 194 LIST_DEL(&entry->head); 195 LIST_ADD(&entry->head, &cache->empty); 196 197 if (cache->total_size <= target_size) { 198 /* all done */ 199 break; 200 } 201 } 202 } 203} 204 205 206/** 207 * Add a surface to the cache. This is done when the driver deletes 208 * the surface. Note: transfers a handle reference. 209 */ 210static void 211svga_screen_cache_add(struct svga_screen *svgascreen, 212 const struct svga_host_surface_cache_key *key, 213 struct svga_winsys_surface **p_handle) 214{ 215 struct svga_host_surface_cache *cache = &svgascreen->cache; 216 struct svga_winsys_screen *sws = svgascreen->sws; 217 struct svga_host_surface_cache_entry *entry = NULL; 218 struct svga_winsys_surface *handle = *p_handle; 219 unsigned surf_size; 220 221 assert(key->cachable); 222 223 if (!handle) 224 return; 225 226 surf_size = surface_size(key); 227 228 *p_handle = NULL; 229 pipe_mutex_lock(cache->mutex); 230 231 if (surf_size >= SVGA_HOST_SURFACE_CACHE_BYTES) { 232 /* this surface is too large to cache, just free it */ 233 sws->surface_reference(sws, &handle, NULL); 234 pipe_mutex_unlock(cache->mutex); 235 return; 236 } 237 238 if (cache->total_size + surf_size > SVGA_HOST_SURFACE_CACHE_BYTES) { 239 /* Adding this surface would exceed the cache size. 240 * Try to discard least recently used entries until we hit the 241 * new target cache size. 242 */ 243 unsigned target_size = SVGA_HOST_SURFACE_CACHE_BYTES - surf_size; 244 245 svga_screen_cache_shrink(svgascreen, target_size); 246 247 if (cache->total_size > target_size) { 248 /* we weren't able to shrink the cache as much as we wanted so 249 * just discard this surface. 250 */ 251 sws->surface_reference(sws, &handle, NULL); 252 pipe_mutex_unlock(cache->mutex); 253 return; 254 } 255 } 256 257 if (!LIST_IS_EMPTY(&cache->empty)) { 258 /* An empty entry has no surface associated with it. 259 * Use the first empty entry. 260 */ 261 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, 262 cache->empty.next, head); 263 264 /* Remove from LRU list */ 265 LIST_DEL(&entry->head); 266 } 267 else if (!LIST_IS_EMPTY(&cache->unused)) { 268 /* free the last used buffer and reuse its entry */ 269 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, 270 cache->unused.prev, head); 271 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 272 "unref sid %p (make space)\n", entry->handle); 273 274 cache->total_size -= surface_size(&entry->key); 275 276 sws->surface_reference(sws, &entry->handle, NULL); 277 278 /* Remove from hash table */ 279 LIST_DEL(&entry->bucket_head); 280 281 /* Remove from LRU list */ 282 LIST_DEL(&entry->head); 283 } 284 285 if (entry) { 286 assert(entry->handle == NULL); 287 entry->handle = handle; 288 memcpy(&entry->key, key, sizeof entry->key); 289 290 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 291 "cache sid %p\n", entry->handle); 292 LIST_ADD(&entry->head, &cache->validated); 293 294 cache->total_size += surf_size; 295 } 296 else { 297 /* Couldn't cache the buffer -- this really shouldn't happen */ 298 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 299 "unref sid %p (couldn't find space)\n", handle); 300 sws->surface_reference(sws, &handle, NULL); 301 } 302 303 pipe_mutex_unlock(cache->mutex); 304} 305 306 307/** 308 * Called during the screen flush to move all buffers not in a validate list 309 * into the unused list. 310 */ 311void 312svga_screen_cache_flush(struct svga_screen *svgascreen, 313 struct pipe_fence_handle *fence) 314{ 315 struct svga_host_surface_cache *cache = &svgascreen->cache; 316 struct svga_winsys_screen *sws = svgascreen->sws; 317 struct svga_host_surface_cache_entry *entry; 318 struct list_head *curr, *next; 319 unsigned bucket; 320 321 pipe_mutex_lock(cache->mutex); 322 323 /* Loop over entries in the invalidated list */ 324 curr = cache->invalidated.next; 325 next = curr->next; 326 while (curr != &cache->invalidated) { 327 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, head); 328 329 assert(entry->handle); 330 331 if (sws->surface_is_flushed(sws, entry->handle)) { 332 /* remove entry from the invalidated list */ 333 LIST_DEL(&entry->head); 334 335 sws->fence_reference(sws, &entry->fence, fence); 336 337 /* Add entry to the unused list */ 338 LIST_ADD(&entry->head, &cache->unused); 339 340 /* Add entry to the hash table bucket */ 341 bucket = svga_screen_cache_bucket(&entry->key); 342 LIST_ADD(&entry->bucket_head, &cache->bucket[bucket]); 343 } 344 345 curr = next; 346 next = curr->next; 347 } 348 349 curr = cache->validated.next; 350 next = curr->next; 351 while (curr != &cache->validated) { 352 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, head); 353 354 assert(entry->handle); 355 356 if (sws->surface_is_flushed(sws, entry->handle)) { 357 /* remove entry from the validated list */ 358 LIST_DEL(&entry->head); 359 360 /* it is now safe to invalidate the surface content. */ 361 sws->surface_invalidate(sws, entry->handle); 362 363 /* add the entry to the invalidated list */ 364 LIST_ADD(&entry->head, &cache->invalidated); 365 } 366 367 curr = next; 368 next = curr->next; 369 } 370 371 pipe_mutex_unlock(cache->mutex); 372} 373 374 375/** 376 * Free all the surfaces in the cache. 377 * Called when destroying the svga screen object. 378 */ 379void 380svga_screen_cache_cleanup(struct svga_screen *svgascreen) 381{ 382 struct svga_host_surface_cache *cache = &svgascreen->cache; 383 struct svga_winsys_screen *sws = svgascreen->sws; 384 unsigned i; 385 386 for (i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i) { 387 if (cache->entries[i].handle) { 388 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 389 "unref sid %p (shutdown)\n", cache->entries[i].handle); 390 sws->surface_reference(sws, &cache->entries[i].handle, NULL); 391 392 cache->total_size -= surface_size(&cache->entries[i].key); 393 } 394 395 if (cache->entries[i].fence) 396 sws->fence_reference(sws, &cache->entries[i].fence, NULL); 397 } 398 399 pipe_mutex_destroy(cache->mutex); 400} 401 402 403enum pipe_error 404svga_screen_cache_init(struct svga_screen *svgascreen) 405{ 406 struct svga_host_surface_cache *cache = &svgascreen->cache; 407 unsigned i; 408 409 assert(cache->total_size == 0); 410 411 pipe_mutex_init(cache->mutex); 412 413 for (i = 0; i < SVGA_HOST_SURFACE_CACHE_BUCKETS; ++i) 414 LIST_INITHEAD(&cache->bucket[i]); 415 416 LIST_INITHEAD(&cache->unused); 417 418 LIST_INITHEAD(&cache->validated); 419 420 LIST_INITHEAD(&cache->invalidated); 421 422 LIST_INITHEAD(&cache->empty); 423 for (i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i) 424 LIST_ADDTAIL(&cache->entries[i].head, &cache->empty); 425 426 return PIPE_OK; 427} 428 429 430/** 431 * Allocate a new host-side surface. If the surface is marked as cachable, 432 * first try re-using a surface in the cache of freed surfaces. Otherwise, 433 * allocate a new surface. 434 * \param bind_flags bitmask of PIPE_BIND_x flags 435 * \param usage one of PIPE_USAGE_x values 436 * \param validated return True if the surface is a reused surface 437 */ 438struct svga_winsys_surface * 439svga_screen_surface_create(struct svga_screen *svgascreen, 440 unsigned bind_flags, enum pipe_resource_usage usage, 441 boolean *validated, 442 struct svga_host_surface_cache_key *key) 443{ 444 struct svga_winsys_screen *sws = svgascreen->sws; 445 struct svga_winsys_surface *handle = NULL; 446 boolean cachable = SVGA_SURFACE_CACHE_ENABLED && key->cachable; 447 448 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 449 "%s sz %dx%dx%d mips %d faces %d arraySize %d cachable %d\n", 450 __FUNCTION__, 451 key->size.width, 452 key->size.height, 453 key->size.depth, 454 key->numMipLevels, 455 key->numFaces, 456 key->arraySize, 457 key->cachable); 458 459 if (cachable) { 460 if (key->format == SVGA3D_BUFFER) { 461 SVGA3dSurfaceFlags hint_flag; 462 463 /* For buffers, round the buffer size up to the nearest power 464 * of two to increase the probability of cache hits. Keep 465 * texture surface dimensions unchanged. 466 */ 467 uint32_t size = 1; 468 while (size < key->size.width) 469 size <<= 1; 470 key->size.width = size; 471 472 /* Determine whether the buffer is static or dynamic. 473 * This is a bit of a heuristic which can be tuned as needed. 474 */ 475 if (usage == PIPE_USAGE_DEFAULT || 476 usage == PIPE_USAGE_IMMUTABLE) { 477 hint_flag = SVGA3D_SURFACE_HINT_STATIC; 478 } 479 else if (bind_flags & PIPE_BIND_INDEX_BUFFER) { 480 /* Index buffers don't change too often. Mark them as static. 481 */ 482 hint_flag = SVGA3D_SURFACE_HINT_STATIC; 483 } 484 else { 485 /* Since we're reusing buffers we're effectively transforming all 486 * of them into dynamic buffers. 487 * 488 * It would be nice to not cache long lived static buffers. But there 489 * is no way to detect the long lived from short lived ones yet. A 490 * good heuristic would be buffer size. 491 */ 492 hint_flag = SVGA3D_SURFACE_HINT_DYNAMIC; 493 } 494 495 key->flags &= ~(SVGA3D_SURFACE_HINT_STATIC | 496 SVGA3D_SURFACE_HINT_DYNAMIC); 497 key->flags |= hint_flag; 498 } 499 500 handle = svga_screen_cache_lookup(svgascreen, key); 501 if (handle) { 502 if (key->format == SVGA3D_BUFFER) 503 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 504 "reuse sid %p sz %d (buffer)\n", handle, 505 key->size.width); 506 else 507 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 508 "reuse sid %p sz %dx%dx%d mips %d faces %d arraySize %d\n", handle, 509 key->size.width, 510 key->size.height, 511 key->size.depth, 512 key->numMipLevels, 513 key->numFaces, 514 key->arraySize); 515 *validated = TRUE; 516 } 517 } 518 519 if (!handle) { 520 unsigned usage = 0; 521 522 if (!key->cachable) 523 usage |= SVGA_SURFACE_USAGE_SHARED; 524 if (key->scanout) 525 usage |= SVGA_SURFACE_USAGE_SCANOUT; 526 527 handle = sws->surface_create(sws, 528 key->flags, 529 key->format, 530 usage, 531 key->size, 532 key->numFaces * key->arraySize, 533 key->numMipLevels, 534 key->sampleCount); 535 if (handle) 536 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 537 " CREATE sid %p sz %dx%dx%d\n", 538 handle, 539 key->size.width, 540 key->size.height, 541 key->size.depth); 542 543 *validated = FALSE; 544 } 545 546 return handle; 547} 548 549 550/** 551 * Release a surface. We don't actually free the surface- we put 552 * it into the cache of freed surfaces (if it's cachable). 553 */ 554void 555svga_screen_surface_destroy(struct svga_screen *svgascreen, 556 const struct svga_host_surface_cache_key *key, 557 struct svga_winsys_surface **p_handle) 558{ 559 struct svga_winsys_screen *sws = svgascreen->sws; 560 561 /* We only set the cachable flag for surfaces of which we are the 562 * exclusive owner. So just hold onto our existing reference in 563 * that case. 564 */ 565 if (SVGA_SURFACE_CACHE_ENABLED && key->cachable) { 566 svga_screen_cache_add(svgascreen, key, p_handle); 567 } 568 else { 569 SVGA_DBG(DEBUG_DMA, 570 "unref sid %p (uncachable)\n", *p_handle); 571 sws->surface_reference(sws, p_handle, NULL); 572 } 573} 574 575 576/** 577 * Print/dump the contents of the screen cache. For debugging. 578 */ 579void 580svga_screen_cache_dump(const struct svga_screen *svgascreen) 581{ 582 const struct svga_host_surface_cache *cache = &svgascreen->cache; 583 unsigned bucket; 584 unsigned count = 0; 585 586 debug_printf("svga3d surface cache:\n"); 587 for (bucket = 0; bucket < SVGA_HOST_SURFACE_CACHE_BUCKETS; bucket++) { 588 struct list_head *curr; 589 curr = cache->bucket[bucket].next; 590 while (curr && curr != &cache->bucket[bucket]) { 591 struct svga_host_surface_cache_entry *entry = 592 LIST_ENTRY(struct svga_host_surface_cache_entry, 593 curr, bucket_head); 594 if (entry->key.format == SVGA3D_BUFFER) { 595 debug_printf(" %p: buffer %u bytes\n", 596 entry->handle, 597 entry->key.size.width); 598 } 599 else { 600 debug_printf(" %p: %u x %u x %u format %u\n", 601 entry->handle, 602 entry->key.size.width, 603 entry->key.size.height, 604 entry->key.size.depth, 605 entry->key.format); 606 } 607 curr = curr->next; 608 count++; 609 } 610 } 611 612 debug_printf("%u surfaces, %u bytes\n", count, cache->total_size); 613} 614