ebd06b0e030048bc4b8bb67fb2510fa0eb6af829
[mesa.git] / src / gallium / auxiliary / pipebuffer / pb_cache.c
1 /**************************************************************************
2 *
3 * Copyright 2007-2008 VMware, Inc.
4 * Copyright 2015 Advanced Micro Devices, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 #include "pb_cache.h"
30 #include "util/u_memory.h"
31 #include "util/u_time.h"
32
33
34 /**
35 * Actually destroy the buffer.
36 */
37 static void
38 destroy_buffer_locked(struct pb_cache_entry *entry)
39 {
40 struct pb_cache *mgr = entry->mgr;
41
42 assert(!pipe_is_referenced(&entry->buffer->reference));
43 if (entry->head.next) {
44 LIST_DEL(&entry->head);
45 assert(mgr->num_buffers);
46 --mgr->num_buffers;
47 mgr->cache_size -= entry->buffer->size;
48 }
49 entry->mgr->destroy_buffer(entry->buffer);
50 }
51
52 /**
53 * Free as many cache buffers from the list head as possible.
54 */
55 static void
56 release_expired_buffers_locked(struct pb_cache *mgr)
57 {
58 struct list_head *curr, *next;
59 struct pb_cache_entry *entry;
60 int64_t now;
61
62 now = os_time_get();
63
64 curr = mgr->cache.next;
65 next = curr->next;
66 while (curr != &mgr->cache) {
67 entry = LIST_ENTRY(struct pb_cache_entry, curr, head);
68
69 if (!os_time_timeout(entry->start, entry->end, now))
70 break;
71
72 destroy_buffer_locked(entry);
73
74 curr = next;
75 next = curr->next;
76 }
77 }
78
79 /**
80 * Add a buffer to the cache. This is typically done when the buffer is
81 * being released.
82 */
83 void
84 pb_cache_add_buffer(struct pb_cache_entry *entry)
85 {
86 struct pb_cache *mgr = entry->mgr;
87
88 pipe_mutex_lock(mgr->mutex);
89 assert(!pipe_is_referenced(&entry->buffer->reference));
90
91 release_expired_buffers_locked(mgr);
92
93 /* Directly release any buffer that exceeds the limit. */
94 if (mgr->cache_size + entry->buffer->size > mgr->max_cache_size) {
95 entry->mgr->destroy_buffer(entry->buffer);
96 pipe_mutex_unlock(mgr->mutex);
97 return;
98 }
99
100 entry->start = os_time_get();
101 entry->end = entry->start + mgr->usecs;
102 LIST_ADDTAIL(&entry->head, &mgr->cache);
103 ++mgr->num_buffers;
104 mgr->cache_size += entry->buffer->size;
105 pipe_mutex_unlock(mgr->mutex);
106 }
107
108 /**
109 * \return 1 if compatible and can be reclaimed
110 * 0 if incompatible
111 * -1 if compatible and can't be reclaimed
112 */
113 static int
114 pb_cache_is_buffer_compat(struct pb_cache_entry *entry,
115 pb_size size, unsigned alignment, unsigned usage)
116 {
117 struct pb_buffer *buf = entry->buffer;
118
119 if (usage & entry->mgr->bypass_usage)
120 return 0;
121
122 if (buf->size < size)
123 return 0;
124
125 /* be lenient with size */
126 if (buf->size > (unsigned) (entry->mgr->size_factor * size))
127 return 0;
128
129 if (!pb_check_alignment(alignment, buf->alignment))
130 return 0;
131
132 if (!pb_check_usage(usage, buf->usage))
133 return 0;
134
135 return entry->mgr->can_reclaim(buf) ? 1 : -1;
136 }
137
138 /**
139 * Find a compatible buffer in the cache, return it, and remove it
140 * from the cache.
141 */
142 struct pb_buffer *
143 pb_cache_reclaim_buffer(struct pb_cache *mgr, pb_size size,
144 unsigned alignment, unsigned usage)
145 {
146 struct pb_cache_entry *entry;
147 struct pb_cache_entry *cur_entry;
148 struct list_head *cur, *next;
149 int64_t now;
150 int ret = 0;
151
152 pipe_mutex_lock(mgr->mutex);
153
154 entry = NULL;
155 cur = mgr->cache.next;
156 next = cur->next;
157
158 /* search in the expired buffers, freeing them in the process */
159 now = os_time_get();
160 while (cur != &mgr->cache) {
161 cur_entry = LIST_ENTRY(struct pb_cache_entry, cur, head);
162
163 if (!entry && (ret = pb_cache_is_buffer_compat(cur_entry, size,
164 alignment, usage) > 0))
165 entry = cur_entry;
166 else if (os_time_timeout(cur_entry->start, cur_entry->end, now))
167 destroy_buffer_locked(cur_entry);
168 else
169 /* This buffer (and all hereafter) are still hot in cache */
170 break;
171
172 /* the buffer is busy (and probably all remaining ones too) */
173 if (ret == -1)
174 break;
175
176 cur = next;
177 next = cur->next;
178 }
179
180 /* keep searching in the hot buffers */
181 if (!entry && ret != -1) {
182 while (cur != &mgr->cache) {
183 cur_entry = LIST_ENTRY(struct pb_cache_entry, cur, head);
184 ret = pb_cache_is_buffer_compat(cur_entry, size, alignment, usage);
185
186 if (ret > 0) {
187 entry = cur_entry;
188 break;
189 }
190 if (ret == -1)
191 break;
192 /* no need to check the timeout here */
193 cur = next;
194 next = cur->next;
195 }
196 }
197
198 /* found a compatible buffer, return it */
199 if (entry) {
200 struct pb_buffer *buf = entry->buffer;
201
202 mgr->cache_size -= buf->size;
203 LIST_DEL(&entry->head);
204 --mgr->num_buffers;
205 pipe_mutex_unlock(mgr->mutex);
206 /* Increase refcount */
207 pipe_reference_init(&buf->reference, 1);
208 return buf;
209 }
210
211 pipe_mutex_unlock(mgr->mutex);
212 return NULL;
213 }
214
215 /**
216 * Empty the cache. Useful when there is not enough memory.
217 */
218 void
219 pb_cache_release_all_buffers(struct pb_cache *mgr)
220 {
221 struct list_head *curr, *next;
222 struct pb_cache_entry *buf;
223
224 pipe_mutex_lock(mgr->mutex);
225 curr = mgr->cache.next;
226 next = curr->next;
227 while (curr != &mgr->cache) {
228 buf = LIST_ENTRY(struct pb_cache_entry, curr, head);
229 destroy_buffer_locked(buf);
230 curr = next;
231 next = curr->next;
232 }
233 pipe_mutex_unlock(mgr->mutex);
234 }
235
236 void
237 pb_cache_init_entry(struct pb_cache *mgr, struct pb_cache_entry *entry,
238 struct pb_buffer *buf)
239 {
240 memset(entry, 0, sizeof(*entry));
241 entry->buffer = buf;
242 entry->mgr = mgr;
243 }
244
245 /**
246 * Initialize a caching buffer manager.
247 *
248 * @param mgr The cache buffer manager
249 * @param usecs Unused buffers may be released from the cache after this
250 * time
251 * @param size_factor Declare buffers that are size_factor times bigger than
252 * the requested size as cache hits.
253 * @param bypass_usage Bitmask. If (requested usage & bypass_usage) != 0,
254 * buffer allocation requests are rejected.
255 * @param maximum_cache_size Maximum size of all unused buffers the cache can
256 * hold.
257 * @param destroy_buffer Function that destroys a buffer for good.
258 * @param can_reclaim Whether a buffer can be reclaimed (e.g. is not busy)
259 */
260 void
261 pb_cache_init(struct pb_cache *mgr, uint usecs, float size_factor,
262 unsigned bypass_usage, uint64_t maximum_cache_size,
263 void (*destroy_buffer)(struct pb_buffer *buf),
264 bool (*can_reclaim)(struct pb_buffer *buf))
265 {
266 LIST_INITHEAD(&mgr->cache);
267 pipe_mutex_init(mgr->mutex);
268 mgr->cache_size = 0;
269 mgr->max_cache_size = maximum_cache_size;
270 mgr->usecs = usecs;
271 mgr->num_buffers = 0;
272 mgr->bypass_usage = bypass_usage;
273 mgr->size_factor = size_factor;
274 mgr->destroy_buffer = destroy_buffer;
275 mgr->can_reclaim = can_reclaim;
276 }
277
278 /**
279 * Deinitialize the manager completely.
280 */
281 void
282 pb_cache_deinit(struct pb_cache *mgr)
283 {
284 pb_cache_release_all_buffers(mgr);
285 pipe_mutex_destroy(mgr->mutex);
286 }