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 */
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 INLINE 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 (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 */
164static void
165svga_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 */
200static INLINE void
201svga_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 */
296void
297svga_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 */
338void
339svga_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
363enum pipe_error
364svga_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 */
393struct svga_winsys_surface *
394svga_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 */
473void
474svga_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