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