asx: remove useless test
[vlc.git] / src / misc / picture_pool.c
blob7b5a82bfbaaa3ce7e6cd24a5cd0ab8b350b9b940
1 /*****************************************************************************
2 * picture_pool.c : picture pool functions
3 *****************************************************************************
4 * Copyright (C) 2009 VLC authors and VideoLAN
5 * Copyright (C) 2009 Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
6 * Copyright (C) 2013-2015 RĂ©mi Denis-Courmont
8 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 #include <assert.h>
29 #include <limits.h>
30 #include <stdlib.h>
32 #include <vlc_common.h>
33 #include <vlc_picture_pool.h>
34 #include <vlc_atomic.h>
35 #include "picture.h"
37 #define POOL_MAX (CHAR_BIT * sizeof (unsigned long long))
39 static_assert ((POOL_MAX & (POOL_MAX - 1)) == 0, "Not a power of two");
41 struct picture_pool_t {
42 int (*pic_lock)(picture_t *);
43 void (*pic_unlock)(picture_t *);
44 vlc_mutex_t lock;
45 vlc_cond_t wait;
47 bool canceled;
48 unsigned long long available;
49 atomic_ushort refs;
50 unsigned short picture_count;
51 picture_t *picture[];
54 static void picture_pool_Destroy(picture_pool_t *pool)
56 if (atomic_fetch_sub(&pool->refs, 1) != 1)
57 return;
59 vlc_cond_destroy(&pool->wait);
60 vlc_mutex_destroy(&pool->lock);
61 aligned_free(pool);
64 void picture_pool_Release(picture_pool_t *pool)
66 for (unsigned i = 0; i < pool->picture_count; i++)
67 picture_Release(pool->picture[i]);
68 picture_pool_Destroy(pool);
71 static void picture_pool_ReleasePicture(picture_t *clone)
73 picture_priv_t *priv = (picture_priv_t *)clone;
74 uintptr_t sys = (uintptr_t)priv->gc.opaque;
75 picture_pool_t *pool = (void *)(sys & ~(POOL_MAX - 1));
76 unsigned offset = sys & (POOL_MAX - 1);
77 picture_t *picture = pool->picture[offset];
79 free(clone);
81 if (pool->pic_unlock != NULL)
82 pool->pic_unlock(picture);
83 picture_Release(picture);
85 vlc_mutex_lock(&pool->lock);
86 assert(!(pool->available & (1ULL << offset)));
87 pool->available |= 1ULL << offset;
88 vlc_cond_signal(&pool->wait);
89 vlc_mutex_unlock(&pool->lock);
91 picture_pool_Destroy(pool);
94 static picture_t *picture_pool_ClonePicture(picture_pool_t *pool,
95 unsigned offset)
97 picture_t *picture = pool->picture[offset];
98 uintptr_t sys = ((uintptr_t)pool) + offset;
99 picture_resource_t res = {
100 .p_sys = picture->p_sys,
101 .pf_destroy = picture_pool_ReleasePicture,
104 for (int i = 0; i < picture->i_planes; i++) {
105 res.p[i].p_pixels = picture->p[i].p_pixels;
106 res.p[i].i_lines = picture->p[i].i_lines;
107 res.p[i].i_pitch = picture->p[i].i_pitch;
110 picture_t *clone = picture_NewFromResource(&picture->format, &res);
111 if (likely(clone != NULL)) {
112 ((picture_priv_t *)clone)->gc.opaque = (void *)sys;
113 picture_Hold(picture);
115 return clone;
118 picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg)
120 if (unlikely(cfg->picture_count > POOL_MAX))
121 return NULL;
123 picture_pool_t *pool;
124 size_t size = sizeof (*pool) + cfg->picture_count * sizeof (picture_t *);
126 size += (-size) & (POOL_MAX - 1);
127 pool = aligned_alloc(POOL_MAX, size);
128 if (unlikely(pool == NULL))
129 return NULL;
131 pool->pic_lock = cfg->lock;
132 pool->pic_unlock = cfg->unlock;
133 vlc_mutex_init(&pool->lock);
134 vlc_cond_init(&pool->wait);
135 if (cfg->picture_count == POOL_MAX)
136 pool->available = ~0ULL;
137 else
138 pool->available = (1ULL << cfg->picture_count) - 1;
139 atomic_init(&pool->refs, 1);
140 pool->picture_count = cfg->picture_count;
141 memcpy(pool->picture, cfg->picture,
142 cfg->picture_count * sizeof (picture_t *));
143 pool->canceled = false;
144 return pool;
147 picture_pool_t *picture_pool_New(unsigned count, picture_t *const *tab)
149 picture_pool_configuration_t cfg = {
150 .picture_count = count,
151 .picture = tab,
154 return picture_pool_NewExtended(&cfg);
157 picture_pool_t *picture_pool_NewFromFormat(const video_format_t *fmt,
158 unsigned count)
160 picture_t *picture[count ? count : 1];
161 unsigned i;
163 for (i = 0; i < count; i++) {
164 picture[i] = picture_NewFromFormat(fmt);
165 if (picture[i] == NULL)
166 goto error;
169 picture_pool_t *pool = picture_pool_New(count, picture);
170 if (!pool)
171 goto error;
173 return pool;
175 error:
176 while (i > 0)
177 picture_Release(picture[--i]);
178 return NULL;
181 picture_pool_t *picture_pool_Reserve(picture_pool_t *master, unsigned count)
183 picture_t *picture[count ? count : 1];
184 unsigned i;
186 for (i = 0; i < count; i++) {
187 picture[i] = picture_pool_Get(master);
188 if (picture[i] == NULL)
189 goto error;
192 picture_pool_t *pool = picture_pool_New(count, picture);
193 if (!pool)
194 goto error;
196 return pool;
198 error:
199 while (i > 0)
200 picture_Release(picture[--i]);
201 return NULL;
204 /** Find next (bit) set */
205 static int fnsll(unsigned long long x, unsigned i)
207 if (i >= CHAR_BIT * sizeof (x))
208 return 0;
209 return ffsll(x & ~((1ULL << i) - 1));
212 picture_t *picture_pool_Get(picture_pool_t *pool)
214 vlc_mutex_lock(&pool->lock);
215 assert(pool->refs > 0);
217 if (pool->canceled)
219 vlc_mutex_unlock(&pool->lock);
220 return NULL;
223 for (unsigned i = ffsll(pool->available); i; i = fnsll(pool->available, i))
225 pool->available &= ~(1ULL << (i - 1));
226 vlc_mutex_unlock(&pool->lock);
228 picture_t *picture = pool->picture[i - 1];
230 if (pool->pic_lock != NULL && pool->pic_lock(picture) != VLC_SUCCESS) {
231 vlc_mutex_lock(&pool->lock);
232 pool->available |= 1ULL << (i - 1);
233 continue;
236 picture_t *clone = picture_pool_ClonePicture(pool, i - 1);
237 if (clone != NULL) {
238 assert(clone->p_next == NULL);
239 atomic_fetch_add(&pool->refs, 1);
241 return clone;
244 vlc_mutex_unlock(&pool->lock);
245 return NULL;
248 picture_t *picture_pool_Wait(picture_pool_t *pool)
250 unsigned i;
252 vlc_mutex_lock(&pool->lock);
253 assert(pool->refs > 0);
255 while (pool->available == 0)
257 if (pool->canceled)
259 vlc_mutex_unlock(&pool->lock);
260 return NULL;
262 vlc_cond_wait(&pool->wait, &pool->lock);
265 i = ffsll(pool->available);
266 assert(i > 0);
267 pool->available &= ~(1ULL << (i - 1));
268 vlc_mutex_unlock(&pool->lock);
270 picture_t *picture = pool->picture[i - 1];
272 if (pool->pic_lock != NULL && pool->pic_lock(picture) != VLC_SUCCESS) {
273 vlc_mutex_lock(&pool->lock);
274 pool->available |= 1ULL << (i - 1);
275 vlc_cond_signal(&pool->wait);
276 vlc_mutex_unlock(&pool->lock);
277 return NULL;
280 picture_t *clone = picture_pool_ClonePicture(pool, i - 1);
281 if (clone != NULL) {
282 assert(clone->p_next == NULL);
283 atomic_fetch_add(&pool->refs, 1);
285 return clone;
288 void picture_pool_Cancel(picture_pool_t *pool, bool canceled)
290 vlc_mutex_lock(&pool->lock);
291 assert(pool->refs > 0);
293 pool->canceled = canceled;
294 if (canceled)
295 vlc_cond_broadcast(&pool->wait);
296 vlc_mutex_unlock(&pool->lock);
299 bool picture_pool_OwnsPic(picture_pool_t *pool, picture_t *pic)
301 picture_priv_t *priv = (picture_priv_t *)pic;
303 while (priv->gc.destroy != picture_pool_ReleasePicture) {
304 pic = priv->gc.opaque;
305 priv = (picture_priv_t *)pic;
308 uintptr_t sys = (uintptr_t)priv->gc.opaque;
309 picture_pool_t *picpool = (void *)(sys & ~(POOL_MAX - 1));
310 return pool == picpool;
313 unsigned picture_pool_GetSize(const picture_pool_t *pool)
315 return pool->picture_count;
318 void picture_pool_Enum(picture_pool_t *pool, void (*cb)(void *, picture_t *),
319 void *opaque)
321 /* NOTE: So far, the pictures table cannot change after the pool is created
322 * so there is no need to lock the pool mutex here. */
323 for (unsigned i = 0; i < pool->picture_count; i++)
324 cb(opaque, pool->picture[i]);