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