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/u_hash.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 */ 43 static unsigned 44 surface_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 */ 79 static INLINE unsigned 80 svga_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 */ 91 static INLINE struct svga_winsys_surface * 92 svga_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 (memcmp(&entry->key, key, sizeof *key) == 0 && 119 sws->fence_signalled(sws, entry->fence, 0) == 0) { 120 unsigned surf_size; 121 122 assert(sws->surface_is_flushed(sws, entry->handle)); 123 124 handle = entry->handle; /* Reference is transfered here. */ 125 entry->handle = NULL; 126 127 LIST_DEL(&entry->bucket_head); 128 129 LIST_DEL(&entry->head); 130 131 LIST_ADD(&entry->head, &cache->empty); 132 133 /* update the cache size */ 134 surf_size = surface_size(&entry->key); 135 assert(surf_size <= cache->total_size); 136 if (surf_size > cache->total_size) 137 cache->total_size = 0; /* should never happen, but be safe */ 138 else 139 cache->total_size -= surf_size; 140 141 break; 142 } 143 144 curr = next; 145 next = curr->next; 146 } 147 148 pipe_mutex_unlock(cache->mutex); 149 150 if (SVGA_DEBUG & DEBUG_DMA) 151 debug_printf("%s: cache %s after %u tries (bucket %d)\n", __FUNCTION__, 152 handle ? "hit" : "miss", tries, bucket); 153 154 return handle; 155 } 156 157 158 /** 159 * Free the least recently used entries in the surface cache until the 160 * cache size is <= the target size OR there are no unused entries left 161 * to discard. We don't do any flushing to try to free up additional 162 * surfaces. 163 */ 164 static void 165 svga_screen_cache_shrink(struct svga_screen *svgascreen, 166 unsigned target_size) 167 { 168 struct svga_host_surface_cache *cache = &svgascreen->cache; 169 struct svga_winsys_screen *sws = svgascreen->sws; 170 struct svga_host_surface_cache_entry *entry = NULL, *next_entry; 171 172 /* Walk over the list of unused buffers in reverse order: from oldest 173 * to newest. 174 */ 175 LIST_FOR_EACH_ENTRY_SAFE_REV(entry, next_entry, &cache->unused, head) { 176 if (entry->key.format != SVGA3D_BUFFER) { 177 /* we don't want to discard vertex/index buffers */ 178 179 cache->total_size -= surface_size(&entry->key); 180 181 assert(entry->handle); 182 sws->surface_reference(sws, &entry->handle, NULL); 183 184 LIST_DEL(&entry->bucket_head); 185 LIST_DEL(&entry->head); 186 LIST_ADD(&entry->head, &cache->empty); 187 188 if (cache->total_size <= target_size) { 189 /* all done */ 190 break; 191 } 192 } 193 } 194 } 195 196 197 /** 198 * Transfers a handle reference. 199 */ 200 static INLINE void 201 svga_screen_cache_add(struct svga_screen *svgascreen, 202 const struct svga_host_surface_cache_key *key, 203 struct svga_winsys_surface **p_handle) 204 { 205 struct svga_host_surface_cache *cache = &svgascreen->cache; 206 struct svga_winsys_screen *sws = svgascreen->sws; 207 struct svga_host_surface_cache_entry *entry = NULL; 208 struct svga_winsys_surface *handle = *p_handle; 209 unsigned surf_size; 210 211 assert(key->cachable); 212 213 assert(handle); 214 if (!handle) 215 return; 216 217 surf_size = surface_size(key); 218 219 *p_handle = NULL; 220 pipe_mutex_lock(cache->mutex); 221 222 if (surf_size >= SVGA_HOST_SURFACE_CACHE_BYTES) { 223 /* this surface is too large to cache, just free it */ 224 sws->surface_reference(sws, &handle, NULL); 225 pipe_mutex_unlock(cache->mutex); 226 return; 227 } 228 229 if (cache->total_size + surf_size > SVGA_HOST_SURFACE_CACHE_BYTES) { 230 /* Adding this surface would exceed the cache size. 231 * Try to discard least recently used entries until we hit the 232 * new target cache size. 233 */ 234 unsigned target_size = SVGA_HOST_SURFACE_CACHE_BYTES - surf_size; 235 236 svga_screen_cache_shrink(svgascreen, target_size); 237 238 if (cache->total_size > target_size) { 239 /* we weren't able to shrink the cache as much as we wanted so 240 * just discard this surface. 241 */ 242 sws->surface_reference(sws, &handle, NULL); 243 pipe_mutex_unlock(cache->mutex); 244 return; 245 } 246 } 247 248 if (!LIST_IS_EMPTY(&cache->empty)) { 249 /* use the first empty entry */ 250 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, 251 cache->empty.next, head); 252 253 LIST_DEL(&entry->head); 254 } 255 else if (!LIST_IS_EMPTY(&cache->unused)) { 256 /* free the last used buffer and reuse its entry */ 257 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, 258 cache->unused.prev, head); 259 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 260 "unref sid %p (make space)\n", entry->handle); 261 262 cache->total_size -= surface_size(&entry->key); 263 264 sws->surface_reference(sws, &entry->handle, NULL); 265 266 LIST_DEL(&entry->bucket_head); 267 268 LIST_DEL(&entry->head); 269 } 270 271 if (entry) { 272 entry->handle = handle; 273 memcpy(&entry->key, key, sizeof entry->key); 274 275 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 276 "cache sid %p\n", entry->handle); 277 LIST_ADD(&entry->head, &cache->validated); 278 279 cache->total_size += surf_size; 280 } 281 else { 282 /* Couldn't cache the buffer -- this really shouldn't happen */ 283 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 284 "unref sid %p (couldn't find space)\n", handle); 285 sws->surface_reference(sws, &handle, NULL); 286 } 287 288 pipe_mutex_unlock(cache->mutex); 289 } 290 291 292 /** 293 * Called during the screen flush to move all buffers not in a validate list 294 * into the unused list. 295 */ 296 void 297 svga_screen_cache_flush(struct svga_screen *svgascreen, 298 struct pipe_fence_handle *fence) 299 { 300 struct svga_host_surface_cache *cache = &svgascreen->cache; 301 struct svga_winsys_screen *sws = svgascreen->sws; 302 struct svga_host_surface_cache_entry *entry; 303 struct list_head *curr, *next; 304 unsigned bucket; 305 306 pipe_mutex_lock(cache->mutex); 307 308 curr = cache->validated.next; 309 next = curr->next; 310 while (curr != &cache->validated) { 311 entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, head); 312 313 assert(entry->handle); 314 315 if (sws->surface_is_flushed(sws, entry->handle)) { 316 LIST_DEL(&entry->head); 317 318 svgascreen->sws->fence_reference(svgascreen->sws, &entry->fence, fence); 319 320 LIST_ADD(&entry->head, &cache->unused); 321 322 bucket = svga_screen_cache_bucket(&entry->key); 323 LIST_ADD(&entry->bucket_head, &cache->bucket[bucket]); 324 } 325 326 curr = next; 327 next = curr->next; 328 } 329 330 pipe_mutex_unlock(cache->mutex); 331 } 332 333 334 /** 335 * Free all the surfaces in the cache. 336 * Called when destroying the svga screen object. 337 */ 338 void 339 svga_screen_cache_cleanup(struct svga_screen *svgascreen) 340 { 341 struct svga_host_surface_cache *cache = &svgascreen->cache; 342 struct svga_winsys_screen *sws = svgascreen->sws; 343 unsigned i; 344 345 for (i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i) { 346 if (cache->entries[i].handle) { 347 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 348 "unref sid %p (shutdown)\n", cache->entries[i].handle); 349 sws->surface_reference(sws, &cache->entries[i].handle, NULL); 350 351 cache->total_size -= surface_size(&cache->entries[i].key); 352 } 353 354 if (cache->entries[i].fence) 355 svgascreen->sws->fence_reference(svgascreen->sws, 356 &cache->entries[i].fence, NULL); 357 } 358 359 pipe_mutex_destroy(cache->mutex); 360 } 361 362 363 enum pipe_error 364 svga_screen_cache_init(struct svga_screen *svgascreen) 365 { 366 struct svga_host_surface_cache *cache = &svgascreen->cache; 367 unsigned i; 368 369 assert(cache->total_size == 0); 370 371 pipe_mutex_init(cache->mutex); 372 373 for (i = 0; i < SVGA_HOST_SURFACE_CACHE_BUCKETS; ++i) 374 LIST_INITHEAD(&cache->bucket[i]); 375 376 LIST_INITHEAD(&cache->unused); 377 378 LIST_INITHEAD(&cache->validated); 379 380 LIST_INITHEAD(&cache->empty); 381 for (i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i) 382 LIST_ADDTAIL(&cache->entries[i].head, &cache->empty); 383 384 return PIPE_OK; 385 } 386 387 388 /** 389 * Allocate a new host-side surface. If the surface is marked as cachable, 390 * first try re-using a surface in the cache of freed surfaces. Otherwise, 391 * allocate a new surface. 392 */ 393 struct svga_winsys_surface * 394 svga_screen_surface_create(struct svga_screen *svgascreen, 395 struct svga_host_surface_cache_key *key) 396 { 397 struct svga_winsys_screen *sws = svgascreen->sws; 398 struct svga_winsys_surface *handle = NULL; 399 boolean cachable = SVGA_SURFACE_CACHE_ENABLED && key->cachable; 400 401 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 402 "%s sz %dx%dx%d mips %d faces %d cachable %d\n", 403 __FUNCTION__, 404 key->size.width, 405 key->size.height, 406 key->size.depth, 407 key->numMipLevels, 408 key->numFaces, 409 key->cachable); 410 411 if (cachable) { 412 if (key->format == SVGA3D_BUFFER) { 413 /* For buffers, round the buffer size up to the nearest power 414 * of two to increase the probability of cache hits. Keep 415 * texture surface dimensions unchanged. 416 */ 417 uint32_t size = 1; 418 while (size < key->size.width) 419 size <<= 1; 420 key->size.width = size; 421 /* Since we're reusing buffers we're effectively transforming all 422 * of them into dynamic buffers. 423 * 424 * It would be nice to not cache long lived static buffers. But there 425 * is no way to detect the long lived from short lived ones yet. A 426 * good heuristic would be buffer size. 427 */ 428 key->flags &= ~SVGA3D_SURFACE_HINT_STATIC; 429 key->flags |= SVGA3D_SURFACE_HINT_DYNAMIC; 430 } 431 432 handle = svga_screen_cache_lookup(svgascreen, key); 433 if (handle) { 434 if (key->format == SVGA3D_BUFFER) 435 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 436 "reuse sid %p sz %d (buffer)\n", handle, 437 key->size.width); 438 else 439 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 440 "reuse sid %p sz %dx%dx%d mips %d faces %d\n", handle, 441 key->size.width, 442 key->size.height, 443 key->size.depth, 444 key->numMipLevels, 445 key->numFaces); 446 } 447 } 448 449 if (!handle) { 450 handle = sws->surface_create(sws, 451 key->flags, 452 key->format, 453 key->size, 454 key->numFaces, 455 key->numMipLevels); 456 if (handle) 457 SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, 458 " CREATE sid %p sz %dx%dx%d\n", 459 handle, 460 key->size.width, 461 key->size.height, 462 key->size.depth); 463 } 464 465 return handle; 466 } 467 468 469 /** 470 * Release a surface. We don't actually free the surface- we put 471 * it into the cache of freed surfaces (if it's cachable). 472 */ 473 void 474 svga_screen_surface_destroy(struct svga_screen *svgascreen, 475 const struct svga_host_surface_cache_key *key, 476 struct svga_winsys_surface **p_handle) 477 { 478 struct svga_winsys_screen *sws = svgascreen->sws; 479 480 /* We only set the cachable flag for surfaces of which we are the 481 * exclusive owner. So just hold onto our existing reference in 482 * that case. 483 */ 484 if (SVGA_SURFACE_CACHE_ENABLED && key->cachable) { 485 svga_screen_cache_add(svgascreen, key, p_handle); 486 } 487 else { 488 SVGA_DBG(DEBUG_DMA, 489 "unref sid %p (uncachable)\n", *p_handle); 490 sws->surface_reference(sws, p_handle, NULL); 491 } 492 } 493