Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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.  
  494.  
  495. /**
  496.  * Print/dump the contents of the screen cache.  For debugging.
  497.  */
  498. void
  499. svga_screen_cache_dump(const struct svga_screen *svgascreen)
  500. {
  501.    const struct svga_host_surface_cache *cache = &svgascreen->cache;
  502.    unsigned bucket;
  503.    unsigned count = 0;
  504.  
  505.    debug_printf("svga3d surface cache:\n");
  506.    for (bucket = 0; bucket < SVGA_HOST_SURFACE_CACHE_BUCKETS; bucket++) {
  507.       struct list_head *curr;
  508.       curr = cache->bucket[bucket].next;
  509.       while (curr && curr != &cache->bucket[bucket]) {
  510.          struct svga_host_surface_cache_entry *entry =
  511.             LIST_ENTRY(struct svga_host_surface_cache_entry,
  512.                        curr, bucket_head);
  513.          if (entry->key.format != 37) {
  514.             debug_printf("  %u x %u x %u format %u\n",
  515.                          entry->key.size.width,
  516.                          entry->key.size.height,
  517.                          entry->key.size.depth,
  518.                          entry->key.format);
  519.          }
  520.          curr = curr->next;
  521.          count++;
  522.       }
  523.    }
  524.  
  525.    debug_printf("%u surfaces, %u bytes\n", count, cache->total_size);
  526. }
  527.