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 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_picture_pool.h>
34 #include <vlc_atomic.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
*);
48 unsigned long long available
;
50 unsigned short picture_count
;
54 static void picture_pool_Destroy(picture_pool_t
*pool
)
56 if (atomic_fetch_sub(&pool
->refs
, 1) != 1)
59 vlc_cond_destroy(&pool
->wait
);
60 vlc_mutex_destroy(&pool
->lock
);
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
];
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
,
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
);
118 picture_pool_t
*picture_pool_NewExtended(const picture_pool_configuration_t
*cfg
)
120 if (unlikely(cfg
->picture_count
> POOL_MAX
))
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
))
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;
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;
147 picture_pool_t
*picture_pool_New(unsigned count
, picture_t
*const *tab
)
149 picture_pool_configuration_t cfg
= {
150 .picture_count
= count
,
154 return picture_pool_NewExtended(&cfg
);
157 picture_pool_t
*picture_pool_NewFromFormat(const video_format_t
*fmt
,
160 picture_t
*picture
[count
? count
: 1];
163 for (i
= 0; i
< count
; i
++) {
164 picture
[i
] = picture_NewFromFormat(fmt
);
165 if (picture
[i
] == NULL
)
169 picture_pool_t
*pool
= picture_pool_New(count
, picture
);
177 picture_Release(picture
[--i
]);
181 picture_pool_t
*picture_pool_Reserve(picture_pool_t
*master
, unsigned count
)
183 picture_t
*picture
[count
? count
: 1];
186 for (i
= 0; i
< count
; i
++) {
187 picture
[i
] = picture_pool_Get(master
);
188 if (picture
[i
] == NULL
)
192 picture_pool_t
*pool
= picture_pool_New(count
, picture
);
200 picture_Release(picture
[--i
]);
204 /** Find next (bit) set */
205 static int fnsll(unsigned long long x
, unsigned i
)
207 if (i
>= CHAR_BIT
* sizeof (x
))
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);
219 vlc_mutex_unlock(&pool
->lock
);
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);
236 picture_t
*clone
= picture_pool_ClonePicture(pool
, i
- 1);
238 assert(clone
->p_next
== NULL
);
239 atomic_fetch_add(&pool
->refs
, 1);
244 vlc_mutex_unlock(&pool
->lock
);
248 picture_t
*picture_pool_Wait(picture_pool_t
*pool
)
252 vlc_mutex_lock(&pool
->lock
);
253 assert(pool
->refs
> 0);
255 while (pool
->available
== 0)
259 vlc_mutex_unlock(&pool
->lock
);
262 vlc_cond_wait(&pool
->wait
, &pool
->lock
);
265 i
= ffsll(pool
->available
);
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
);
280 picture_t
*clone
= picture_pool_ClonePicture(pool
, i
- 1);
282 assert(clone
->p_next
== NULL
);
283 atomic_fetch_add(&pool
->refs
, 1);
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
;
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
*),
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
]);