Subversion Repositories Kolibri OS

Rev

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

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21.  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
  22.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27.  
  28. /**
  29.  * \file
  30.  * Buffer cache.
  31.  *
  32.  * \author Jose Fonseca <jrfonseca-at-tungstengraphics-dot-com>
  33.  * \author Thomas Hellström <thomas-at-tungstengraphics-dot-com>
  34.  */
  35.  
  36.  
  37. #include "pipe/p_compiler.h"
  38. #include "util/u_debug.h"
  39. #include "os/os_thread.h"
  40. #include "util/u_memory.h"
  41. #include "util/u_double_list.h"
  42. #include "util/u_time.h"
  43.  
  44. #include "pb_buffer.h"
  45. #include "pb_bufmgr.h"
  46.  
  47.  
  48. /**
  49.  * Convenience macro (type safe).
  50.  */
  51. #define SUPER(__derived) (&(__derived)->base)
  52.  
  53.  
  54. struct pb_cache_manager;
  55.  
  56.  
  57. /**
  58.  * Wrapper around a pipe buffer which adds delayed destruction.
  59.  */
  60. struct pb_cache_buffer
  61. {
  62.    struct pb_buffer base;
  63.    
  64.    struct pb_buffer *buffer;
  65.    struct pb_cache_manager *mgr;
  66.  
  67.    /** Caching time interval */
  68.    int64_t start, end;
  69.  
  70.    struct list_head head;
  71. };
  72.  
  73.  
  74. struct pb_cache_manager
  75. {
  76.    struct pb_manager base;
  77.  
  78.    struct pb_manager *provider;
  79.    unsigned usecs;
  80.    
  81.    pipe_mutex mutex;
  82.    
  83.    struct list_head delayed;
  84.    pb_size numDelayed;
  85. };
  86.  
  87.  
  88. static INLINE struct pb_cache_buffer *
  89. pb_cache_buffer(struct pb_buffer *buf)
  90. {
  91.    assert(buf);
  92.    return (struct pb_cache_buffer *)buf;
  93. }
  94.  
  95.  
  96. static INLINE struct pb_cache_manager *
  97. pb_cache_manager(struct pb_manager *mgr)
  98. {
  99.    assert(mgr);
  100.    return (struct pb_cache_manager *)mgr;
  101. }
  102.  
  103.  
  104. /**
  105.  * Actually destroy the buffer.
  106.  */
  107. static INLINE void
  108. _pb_cache_buffer_destroy(struct pb_cache_buffer *buf)
  109. {
  110.    struct pb_cache_manager *mgr = buf->mgr;
  111.  
  112.    LIST_DEL(&buf->head);
  113.    assert(mgr->numDelayed);
  114.    --mgr->numDelayed;
  115.    assert(!pipe_is_referenced(&buf->base.reference));
  116.    pb_reference(&buf->buffer, NULL);
  117.    FREE(buf);
  118. }
  119.  
  120.  
  121. /**
  122.  * Free as many cache buffers from the list head as possible.
  123.  */
  124. static void
  125. _pb_cache_buffer_list_check_free(struct pb_cache_manager *mgr)
  126. {
  127.    struct list_head *curr, *next;
  128.    struct pb_cache_buffer *buf;
  129.    int64_t now;
  130.    
  131.    now = os_time_get();
  132.    
  133.    curr = mgr->delayed.next;
  134.    next = curr->next;
  135.    while(curr != &mgr->delayed) {
  136.       buf = LIST_ENTRY(struct pb_cache_buffer, curr, head);
  137.  
  138.       if(!os_time_timeout(buf->start, buf->end, now))
  139.          break;
  140.          
  141.       _pb_cache_buffer_destroy(buf);
  142.  
  143.       curr = next;
  144.       next = curr->next;
  145.    }
  146. }
  147.  
  148.  
  149. static void
  150. pb_cache_buffer_destroy(struct pb_buffer *_buf)
  151. {
  152.    struct pb_cache_buffer *buf = pb_cache_buffer(_buf);  
  153.    struct pb_cache_manager *mgr = buf->mgr;
  154.  
  155.    pipe_mutex_lock(mgr->mutex);
  156.    assert(!pipe_is_referenced(&buf->base.reference));
  157.    
  158.    _pb_cache_buffer_list_check_free(mgr);
  159.    
  160.    buf->start = os_time_get();
  161.    buf->end = buf->start + mgr->usecs;
  162.    LIST_ADDTAIL(&buf->head, &mgr->delayed);
  163.    ++mgr->numDelayed;
  164.    pipe_mutex_unlock(mgr->mutex);
  165. }
  166.  
  167.  
  168. static void *
  169. pb_cache_buffer_map(struct pb_buffer *_buf,
  170.                     unsigned flags, void *flush_ctx)
  171. {
  172.    struct pb_cache_buffer *buf = pb_cache_buffer(_buf);  
  173.    return pb_map(buf->buffer, flags, flush_ctx);
  174. }
  175.  
  176.  
  177. static void
  178. pb_cache_buffer_unmap(struct pb_buffer *_buf)
  179. {
  180.    struct pb_cache_buffer *buf = pb_cache_buffer(_buf);  
  181.    pb_unmap(buf->buffer);
  182. }
  183.  
  184.  
  185. static enum pipe_error
  186. pb_cache_buffer_validate(struct pb_buffer *_buf,
  187.                          struct pb_validate *vl,
  188.                          unsigned flags)
  189. {
  190.    struct pb_cache_buffer *buf = pb_cache_buffer(_buf);
  191.    return pb_validate(buf->buffer, vl, flags);
  192. }
  193.  
  194.  
  195. static void
  196. pb_cache_buffer_fence(struct pb_buffer *_buf,
  197.                       struct pipe_fence_handle *fence)
  198. {
  199.    struct pb_cache_buffer *buf = pb_cache_buffer(_buf);
  200.    pb_fence(buf->buffer, fence);
  201. }
  202.  
  203.  
  204. static void
  205. pb_cache_buffer_get_base_buffer(struct pb_buffer *_buf,
  206.                               struct pb_buffer **base_buf,
  207.                               pb_size *offset)
  208. {
  209.    struct pb_cache_buffer *buf = pb_cache_buffer(_buf);
  210.    pb_get_base_buffer(buf->buffer, base_buf, offset);
  211. }
  212.  
  213.  
  214. const struct pb_vtbl
  215. pb_cache_buffer_vtbl = {
  216.       pb_cache_buffer_destroy,
  217.       pb_cache_buffer_map,
  218.       pb_cache_buffer_unmap,
  219.       pb_cache_buffer_validate,
  220.       pb_cache_buffer_fence,
  221.       pb_cache_buffer_get_base_buffer
  222. };
  223.  
  224.  
  225. static INLINE int
  226. pb_cache_is_buffer_compat(struct pb_cache_buffer *buf,  
  227.                           pb_size size,
  228.                           const struct pb_desc *desc)
  229. {
  230.    if(buf->base.size < size)
  231.       return 0;
  232.  
  233.    /* be lenient with size */
  234.    if(buf->base.size >= 2*size)
  235.       return 0;
  236.    
  237.    if(!pb_check_alignment(desc->alignment, buf->base.alignment))
  238.       return 0;
  239.    
  240.    if(!pb_check_usage(desc->usage, buf->base.usage))
  241.       return 0;
  242.  
  243.    if (buf->mgr->provider->is_buffer_busy) {
  244.       if (buf->mgr->provider->is_buffer_busy(buf->mgr->provider, buf->buffer))
  245.          return -1;
  246.    } else {
  247.       void *ptr = pb_map(buf->buffer, PB_USAGE_DONTBLOCK, NULL);
  248.  
  249.       if (!ptr)
  250.          return -1;
  251.  
  252.       pb_unmap(buf->buffer);
  253.    }
  254.  
  255.    return 1;
  256. }
  257.  
  258.  
  259. static struct pb_buffer *
  260. pb_cache_manager_create_buffer(struct pb_manager *_mgr,
  261.                                pb_size size,
  262.                                const struct pb_desc *desc)
  263. {
  264.    struct pb_cache_manager *mgr = pb_cache_manager(_mgr);
  265.    struct pb_cache_buffer *buf;
  266.    struct pb_cache_buffer *curr_buf;
  267.    struct list_head *curr, *next;
  268.    int64_t now;
  269.    int ret = 0;
  270.  
  271.    pipe_mutex_lock(mgr->mutex);
  272.  
  273.    buf = NULL;
  274.    curr = mgr->delayed.next;
  275.    next = curr->next;
  276.    
  277.    /* search in the expired buffers, freeing them in the process */
  278.    now = os_time_get();
  279.    while(curr != &mgr->delayed) {
  280.       curr_buf = LIST_ENTRY(struct pb_cache_buffer, curr, head);
  281.       if(!buf && (ret = pb_cache_is_buffer_compat(curr_buf, size, desc) > 0))
  282.          buf = curr_buf;
  283.       else if(os_time_timeout(curr_buf->start, curr_buf->end, now))
  284.          _pb_cache_buffer_destroy(curr_buf);
  285.       else
  286.          /* This buffer (and all hereafter) are still hot in cache */
  287.          break;
  288.       if (ret == -1)
  289.          break;
  290.       curr = next;
  291.       next = curr->next;
  292.    }
  293.  
  294.    /* keep searching in the hot buffers */
  295.    if(!buf && ret != -1) {
  296.       while(curr != &mgr->delayed) {
  297.          curr_buf = LIST_ENTRY(struct pb_cache_buffer, curr, head);
  298.          ret = pb_cache_is_buffer_compat(curr_buf, size, desc);
  299.          if (ret > 0) {
  300.             buf = curr_buf;
  301.             break;
  302.          }
  303.          if (ret == -1)
  304.             break;
  305.          /* no need to check the timeout here */
  306.          curr = next;
  307.          next = curr->next;
  308.       }
  309.    }
  310.    
  311.    if(buf) {
  312.       LIST_DEL(&buf->head);
  313.       --mgr->numDelayed;
  314.       pipe_mutex_unlock(mgr->mutex);
  315.       /* Increase refcount */
  316.       pipe_reference_init(&buf->base.reference, 1);
  317.       return &buf->base;
  318.    }
  319.    
  320.    pipe_mutex_unlock(mgr->mutex);
  321.  
  322.    buf = CALLOC_STRUCT(pb_cache_buffer);
  323.    if(!buf)
  324.       return NULL;
  325.    
  326.    buf->buffer = mgr->provider->create_buffer(mgr->provider, size, desc);
  327.  
  328.    /* Empty the cache and try again. */
  329.    if (!buf->buffer) {
  330.       mgr->base.flush(&mgr->base);
  331.       buf->buffer = mgr->provider->create_buffer(mgr->provider, size, desc);
  332.    }
  333.  
  334.    if(!buf->buffer) {
  335.       FREE(buf);
  336.       return NULL;
  337.    }
  338.    
  339.    assert(pipe_is_referenced(&buf->buffer->reference));
  340.    assert(pb_check_alignment(desc->alignment, buf->buffer->alignment));
  341.    assert(pb_check_usage(desc->usage, buf->buffer->usage));
  342.    assert(buf->buffer->size >= size);
  343.    
  344.    pipe_reference_init(&buf->base.reference, 1);
  345.    buf->base.alignment = buf->buffer->alignment;
  346.    buf->base.usage = buf->buffer->usage;
  347.    buf->base.size = buf->buffer->size;
  348.    
  349.    buf->base.vtbl = &pb_cache_buffer_vtbl;
  350.    buf->mgr = mgr;
  351.    
  352.    return &buf->base;
  353. }
  354.  
  355.  
  356. static void
  357. pb_cache_manager_flush(struct pb_manager *_mgr)
  358. {
  359.    struct pb_cache_manager *mgr = pb_cache_manager(_mgr);
  360.    struct list_head *curr, *next;
  361.    struct pb_cache_buffer *buf;
  362.  
  363.    pipe_mutex_lock(mgr->mutex);
  364.    curr = mgr->delayed.next;
  365.    next = curr->next;
  366.    while(curr != &mgr->delayed) {
  367.       buf = LIST_ENTRY(struct pb_cache_buffer, curr, head);
  368.       _pb_cache_buffer_destroy(buf);
  369.       curr = next;
  370.       next = curr->next;
  371.    }
  372.    pipe_mutex_unlock(mgr->mutex);
  373.    
  374.    assert(mgr->provider->flush);
  375.    if(mgr->provider->flush)
  376.       mgr->provider->flush(mgr->provider);
  377. }
  378.  
  379.  
  380. static void
  381. pb_cache_manager_destroy(struct pb_manager *mgr)
  382. {
  383.    pb_cache_manager_flush(mgr);
  384.    FREE(mgr);
  385. }
  386.  
  387.  
  388. struct pb_manager *
  389. pb_cache_manager_create(struct pb_manager *provider,
  390.                         unsigned usecs)
  391. {
  392.    struct pb_cache_manager *mgr;
  393.  
  394.    if(!provider)
  395.       return NULL;
  396.    
  397.    mgr = CALLOC_STRUCT(pb_cache_manager);
  398.    if (!mgr)
  399.       return NULL;
  400.  
  401.    mgr->base.destroy = pb_cache_manager_destroy;
  402.    mgr->base.create_buffer = pb_cache_manager_create_buffer;
  403.    mgr->base.flush = pb_cache_manager_flush;
  404.    mgr->provider = provider;
  405.    mgr->usecs = usecs;
  406.    LIST_INITHEAD(&mgr->delayed);
  407.    mgr->numDelayed = 0;
  408.    pipe_mutex_init(mgr->mutex);
  409.      
  410.    return &mgr->base;
  411. }
  412.